From 16c2f12a54f8bf84d1b7dcf2dfda786376c9c77c Mon Sep 17 00:00:00 2001 From: Alex Jenkins Date: Sat, 11 Apr 2026 01:08:44 +0000 Subject: [PATCH] update more languages Signed-off-by: Alex Jenkins --- docs/python-api.ar.md | 4071 +++++++++++++++++ docs/python-api.ru.md | 4071 +++++++++++++++++ docs/python-api.zh-cn.md | 4071 +++++++++++++++++ .../architecture-principles.zh-cn.md | 24 +- .../extraction-provenance-subgraph.ar.md | 52 + .../extraction-provenance-subgraph.he.md | 30 + .../extraction-provenance-subgraph.hi.md | 47 + .../extraction-provenance-subgraph.pt.md | 34 + .../extraction-provenance-subgraph.ru.md | 55 + .../extraction-provenance-subgraph.sw.md | 45 + .../extraction-provenance-subgraph.tr.md | 62 + .../extraction-provenance-subgraph.zh-cn.md | 54 + .../extraction-time-provenance.ar.md | 259 ++ .../extraction-time-provenance.es.md | 176 + .../extraction-time-provenance.he.md | 203 + .../extraction-time-provenance.hi.md | 140 + .../extraction-time-provenance.pt.md | 131 + .../extraction-time-provenance.ru.md | 143 + .../extraction-time-provenance.sw.md | 308 ++ .../extraction-time-provenance.tr.md | 170 + .../extraction-time-provenance.zh-cn.md | 210 + docs/tech-specs/flow-class-definition.ar.md | 26 + docs/tech-specs/flow-class-definition.es.md | 19 + docs/tech-specs/flow-class-definition.he.md | 43 + docs/tech-specs/flow-class-definition.hi.md | 43 + docs/tech-specs/flow-class-definition.pt.md | 32 + docs/tech-specs/flow-class-definition.ru.md | 28 + docs/tech-specs/flow-class-definition.sw.md | 114 + docs/tech-specs/flow-class-definition.tr.md | 43 +- .../tech-specs/flow-class-definition.zh-cn.md | 32 + .../flow-configurable-parameters.ar.md | 126 + .../flow-configurable-parameters.es.md | 151 + .../flow-configurable-parameters.he.md | 97 + .../flow-configurable-parameters.hi.md | 105 + .../flow-configurable-parameters.pt.md | 103 + .../flow-configurable-parameters.ru.md | 120 + .../flow-configurable-parameters.sw.md | 219 + .../flow-configurable-parameters.tr.md | 140 + .../flow-configurable-parameters.zh-cn.md | 93 + docs/tech-specs/graph-contexts.pt.md | 97 + docs/tech-specs/graph-contexts.tr.md | 194 + docs/tech-specs/graphql-query.ar.md | 140 + docs/tech-specs/graphql-query.es.md | 76 + docs/tech-specs/graphql-query.he.md | 76 +- docs/tech-specs/graphql-query.hi.md | 144 +- docs/tech-specs/graphql-query.pt.md | 110 + docs/tech-specs/graphql-query.ru.md | 141 +- docs/tech-specs/graphql-query.sw.md | 196 +- docs/tech-specs/graphql-query.tr.md | 91 + docs/tech-specs/graphql-query.zh-cn.md | 47 + .../graphrag-performance-optimization.ar.md | 133 + .../graphrag-performance-optimization.he.md | 170 + .../graphrag-performance-optimization.hi.md | 122 + .../graphrag-performance-optimization.pt.md | 121 + .../graphrag-performance-optimization.ru.md | 108 + .../graphrag-performance-optimization.sw.md | 262 ++ .../graphrag-performance-optimization.tr.md | 89 + ...graphrag-performance-optimization.zh-cn.md | 137 + .../import-export-graceful-shutdown.ar.md | 27 + .../import-export-graceful-shutdown.es.md | 35 + .../import-export-graceful-shutdown.he.md | 25 +- .../import-export-graceful-shutdown.hi.md | 28 + .../import-export-graceful-shutdown.pt.md | 20 + .../import-export-graceful-shutdown.ru.md | 27 + .../import-export-graceful-shutdown.sw.md | 48 + .../import-export-graceful-shutdown.tr.md | 39 + .../import-export-graceful-shutdown.zh-cn.md | 37 +- docs/tech-specs/jsonl-prompt-output.ar.md | 77 + docs/tech-specs/jsonl-prompt-output.es.md | 61 + docs/tech-specs/jsonl-prompt-output.he.md | 85 + docs/tech-specs/jsonl-prompt-output.hi.md | 100 +- docs/tech-specs/jsonl-prompt-output.pt.md | 41 + docs/tech-specs/jsonl-prompt-output.ru.md | 28 + docs/tech-specs/jsonl-prompt-output.tr.md | 93 + docs/tech-specs/jsonl-prompt-output.zh-cn.md | 69 + docs/tech-specs/large-document-loading.ar.md | 984 ++++ docs/tech-specs/large-document-loading.es.md | 105 + docs/tech-specs/large-document-loading.he.md | 984 ++++ docs/tech-specs/large-document-loading.hi.md | 984 ++++ docs/tech-specs/large-document-loading.pt.md | 113 + docs/tech-specs/large-document-loading.ru.md | 984 ++++ docs/tech-specs/large-document-loading.sw.md | 319 ++ docs/tech-specs/large-document-loading.tr.md | 984 ++++ .../large-document-loading.zh-cn.md | 984 ++++ docs/tech-specs/logging-strategy.ar.md | 350 ++ docs/tech-specs/logging-strategy.he.md | 350 ++ docs/tech-specs/logging-strategy.hi.md | 350 ++ docs/tech-specs/logging-strategy.pt.md | 350 ++ docs/tech-specs/logging-strategy.sw.md | 350 ++ docs/tech-specs/logging-strategy.tr.md | 350 ++ docs/tech-specs/mcp-tool-arguments.hi.md | 256 ++ docs/tech-specs/mcp-tool-arguments.pt.md | 256 ++ docs/tech-specs/mcp-tool-arguments.sw.md | 256 ++ docs/tech-specs/mcp-tool-arguments.tr.md | 256 ++ docs/tech-specs/mcp-tool-bearer-token.ar.md | 554 +++ docs/tech-specs/mcp-tool-bearer-token.es.md | 554 +++ docs/tech-specs/mcp-tool-bearer-token.he.md | 554 +++ docs/tech-specs/mcp-tool-bearer-token.hi.md | 554 +++ docs/tech-specs/mcp-tool-bearer-token.pt.md | 554 +++ docs/tech-specs/mcp-tool-bearer-token.ru.md | 554 +++ docs/tech-specs/mcp-tool-bearer-token.sw.md | 554 +++ docs/tech-specs/mcp-tool-bearer-token.tr.md | 554 +++ .../tech-specs/mcp-tool-bearer-token.zh-cn.md | 554 +++ docs/tech-specs/minio-to-s3-migration.ar.md | 258 ++ docs/tech-specs/minio-to-s3-migration.es.md | 258 ++ docs/tech-specs/minio-to-s3-migration.he.md | 258 ++ docs/tech-specs/minio-to-s3-migration.hi.md | 258 ++ docs/tech-specs/minio-to-s3-migration.pt.md | 258 ++ docs/tech-specs/minio-to-s3-migration.ru.md | 258 ++ docs/tech-specs/minio-to-s3-migration.sw.md | 258 ++ docs/tech-specs/minio-to-s3-migration.tr.md | 258 ++ .../tech-specs/minio-to-s3-migration.zh-cn.md | 258 ++ docs/tech-specs/more-config-cli.pt.md | 279 ++ docs/tech-specs/more-config-cli.tr.md | 279 ++ docs/tech-specs/multi-tenant-support.ar.md | 772 ++++ docs/tech-specs/multi-tenant-support.es.md | 772 ++++ docs/tech-specs/multi-tenant-support.he.md | 772 ++++ docs/tech-specs/multi-tenant-support.hi.md | 772 ++++ docs/tech-specs/multi-tenant-support.pt.md | 772 ++++ docs/tech-specs/multi-tenant-support.ru.md | 772 ++++ docs/tech-specs/multi-tenant-support.sw.md | 772 ++++ docs/tech-specs/multi-tenant-support.tr.md | 772 ++++ docs/tech-specs/multi-tenant-support.zh-cn.md | 772 ++++ .../neo4j-user-collection-isolation.hi.md | 331 +- .../neo4j-user-collection-isolation.pt.md | 359 ++ .../neo4j-user-collection-isolation.tr.md | 359 ++ .../tech-specs/ontology-extract-phase-2.ar.md | 761 +++ .../tech-specs/ontology-extract-phase-2.es.md | 761 +++ .../tech-specs/ontology-extract-phase-2.he.md | 761 +++ .../tech-specs/ontology-extract-phase-2.hi.md | 761 +++ .../tech-specs/ontology-extract-phase-2.pt.md | 761 +++ .../tech-specs/ontology-extract-phase-2.ru.md | 761 +++ .../tech-specs/ontology-extract-phase-2.sw.md | 761 +++ .../tech-specs/ontology-extract-phase-2.tr.md | 761 +++ .../ontology-extract-phase-2.zh-cn.md | 761 +++ docs/tech-specs/ontology.pt.md | 286 ++ docs/tech-specs/ontology.tr.md | 286 ++ docs/tech-specs/ontorag.ar.md | 1067 +++++ docs/tech-specs/ontorag.es.md | 1067 +++++ docs/tech-specs/ontorag.he.md | 1067 +++++ docs/tech-specs/ontorag.hi.md | 1067 +++++ docs/tech-specs/ontorag.pt.md | 1067 +++++ docs/tech-specs/ontorag.ru.md | 1067 +++++ docs/tech-specs/ontorag.sw.md | 1067 +++++ docs/tech-specs/ontorag.tr.md | 1067 +++++ docs/tech-specs/ontorag.zh-cn.md | 1067 +++++ docs/tech-specs/openapi-spec.ar.md | 231 + docs/tech-specs/openapi-spec.es.md | 231 + docs/tech-specs/openapi-spec.he.md | 231 + docs/tech-specs/openapi-spec.hi.md | 231 + docs/tech-specs/openapi-spec.pt.md | 231 + docs/tech-specs/openapi-spec.ru.md | 231 + docs/tech-specs/openapi-spec.sw.md | 231 + docs/tech-specs/openapi-spec.tr.md | 231 + docs/tech-specs/openapi-spec.zh-cn.md | 231 + docs/tech-specs/pubsub.ar.md | 958 ++++ docs/tech-specs/pubsub.es.md | 958 ++++ docs/tech-specs/pubsub.he.md | 958 ++++ docs/tech-specs/pubsub.hi.md | 958 ++++ docs/tech-specs/pubsub.pt.md | 958 ++++ docs/tech-specs/pubsub.ru.md | 958 ++++ docs/tech-specs/pubsub.sw.md | 958 ++++ docs/tech-specs/pubsub.tr.md | 958 ++++ docs/tech-specs/pubsub.zh-cn.md | 958 ++++ docs/tech-specs/python-api-refactor.ar.md | 1508 ++++++ docs/tech-specs/python-api-refactor.es.md | 1508 ++++++ docs/tech-specs/python-api-refactor.he.md | 1508 ++++++ docs/tech-specs/python-api-refactor.hi.md | 1508 ++++++ docs/tech-specs/python-api-refactor.pt.md | 1508 ++++++ docs/tech-specs/python-api-refactor.ru.md | 1508 ++++++ docs/tech-specs/python-api-refactor.sw.md | 1508 ++++++ docs/tech-specs/python-api-refactor.tr.md | 1508 ++++++ docs/tech-specs/python-api-refactor.zh-cn.md | 1508 ++++++ .../query-time-explainability.ar.md | 263 ++ .../query-time-explainability.hi.md | 263 ++ .../query-time-explainability.pt.md | 263 ++ .../query-time-explainability.ru.md | 263 ++ .../query-time-explainability.sw.md | 263 ++ .../query-time-explainability.tr.md | 263 ++ docs/tech-specs/rag-streaming-support.hi.md | 288 ++ docs/tech-specs/rag-streaming-support.pt.md | 288 ++ docs/tech-specs/rag-streaming-support.sw.md | 288 ++ docs/tech-specs/rag-streaming-support.tr.md | 288 ++ .../schema-refactoring-proposal.pt.md | 91 + .../schema-refactoring-proposal.sw.md | 91 + .../schema-refactoring-proposal.tr.md | 91 + docs/tech-specs/streaming-llm-responses.ar.md | 570 +++ docs/tech-specs/streaming-llm-responses.es.md | 570 +++ docs/tech-specs/streaming-llm-responses.he.md | 570 +++ docs/tech-specs/streaming-llm-responses.hi.md | 570 +++ docs/tech-specs/streaming-llm-responses.pt.md | 570 +++ docs/tech-specs/streaming-llm-responses.ru.md | 570 +++ docs/tech-specs/streaming-llm-responses.sw.md | 570 +++ docs/tech-specs/streaming-llm-responses.tr.md | 570 +++ .../streaming-llm-responses.zh-cn.md | 570 +++ docs/tech-specs/structured-data-2.ar.md | 613 +++ docs/tech-specs/structured-data-2.es.md | 613 +++ docs/tech-specs/structured-data-2.he.md | 613 +++ docs/tech-specs/structured-data-2.hi.md | 613 +++ docs/tech-specs/structured-data-2.pt.md | 613 +++ docs/tech-specs/structured-data-2.ru.md | 613 +++ docs/tech-specs/structured-data-2.sw.md | 613 +++ docs/tech-specs/structured-data-2.tr.md | 613 +++ docs/tech-specs/structured-data-2.zh-cn.md | 613 +++ .../structured-data-descriptor.ar.md | 559 +++ .../structured-data-descriptor.es.md | 559 +++ .../structured-data-descriptor.he.md | 559 +++ .../structured-data-descriptor.hi.md | 559 +++ .../structured-data-descriptor.pt.md | 559 +++ .../structured-data-descriptor.ru.md | 559 +++ .../structured-data-descriptor.sw.md | 559 +++ .../structured-data-descriptor.tr.md | 559 +++ .../structured-data-descriptor.zh-cn.md | 559 +++ docs/tech-specs/structured-data-schemas.pt.md | 139 + docs/tech-specs/structured-data-schemas.tr.md | 139 + docs/tech-specs/structured-data.ar.md | 253 + docs/tech-specs/structured-data.es.md | 253 + docs/tech-specs/structured-data.he.md | 253 + docs/tech-specs/structured-data.hi.md | 253 + docs/tech-specs/structured-data.pt.md | 253 + docs/tech-specs/structured-data.ru.md | 253 + docs/tech-specs/structured-data.sw.md | 253 + docs/tech-specs/structured-data.tr.md | 253 + docs/tech-specs/structured-data.zh-cn.md | 253 + docs/tech-specs/structured-diag-service.ar.md | 273 ++ docs/tech-specs/structured-diag-service.es.md | 273 ++ docs/tech-specs/structured-diag-service.he.md | 273 ++ docs/tech-specs/structured-diag-service.hi.md | 273 ++ docs/tech-specs/structured-diag-service.pt.md | 273 ++ docs/tech-specs/structured-diag-service.ru.md | 273 ++ docs/tech-specs/structured-diag-service.sw.md | 273 ++ docs/tech-specs/structured-diag-service.tr.md | 273 ++ .../structured-diag-service.zh-cn.md | 273 ++ docs/tech-specs/tool-group.ar.md | 491 ++ docs/tech-specs/tool-group.es.md | 491 ++ docs/tech-specs/tool-group.he.md | 491 ++ docs/tech-specs/tool-group.hi.md | 491 ++ docs/tech-specs/tool-group.pt.md | 491 ++ docs/tech-specs/tool-group.ru.md | 491 ++ docs/tech-specs/tool-group.sw.md | 491 ++ docs/tech-specs/tool-group.tr.md | 491 ++ docs/tech-specs/tool-group.zh-cn.md | 491 ++ docs/tech-specs/tool-services.ar.md | 491 +- docs/tech-specs/tool-services.es.md | 471 ++ docs/tech-specs/tool-services.he.md | 505 +- docs/tech-specs/tool-services.hi.md | 471 ++ docs/tech-specs/tool-services.pt.md | 471 ++ docs/tech-specs/tool-services.sw.md | 471 ++ docs/tech-specs/tool-services.tr.md | 471 ++ 249 files changed, 117186 insertions(+), 186 deletions(-) create mode 100644 docs/python-api.ar.md create mode 100644 docs/python-api.ru.md create mode 100644 docs/python-api.zh-cn.md create mode 100644 docs/tech-specs/large-document-loading.ar.md create mode 100644 docs/tech-specs/large-document-loading.he.md create mode 100644 docs/tech-specs/large-document-loading.hi.md create mode 100644 docs/tech-specs/large-document-loading.ru.md create mode 100644 docs/tech-specs/large-document-loading.tr.md create mode 100644 docs/tech-specs/large-document-loading.zh-cn.md create mode 100644 docs/tech-specs/logging-strategy.ar.md create mode 100644 docs/tech-specs/logging-strategy.he.md create mode 100644 docs/tech-specs/logging-strategy.hi.md create mode 100644 docs/tech-specs/logging-strategy.pt.md create mode 100644 docs/tech-specs/logging-strategy.sw.md create mode 100644 docs/tech-specs/logging-strategy.tr.md create mode 100644 docs/tech-specs/mcp-tool-arguments.hi.md create mode 100644 docs/tech-specs/mcp-tool-arguments.pt.md create mode 100644 docs/tech-specs/mcp-tool-arguments.sw.md create mode 100644 docs/tech-specs/mcp-tool-arguments.tr.md create mode 100644 docs/tech-specs/mcp-tool-bearer-token.ar.md create mode 100644 docs/tech-specs/mcp-tool-bearer-token.es.md create mode 100644 docs/tech-specs/mcp-tool-bearer-token.he.md create mode 100644 docs/tech-specs/mcp-tool-bearer-token.hi.md create mode 100644 docs/tech-specs/mcp-tool-bearer-token.pt.md create mode 100644 docs/tech-specs/mcp-tool-bearer-token.ru.md create mode 100644 docs/tech-specs/mcp-tool-bearer-token.sw.md create mode 100644 docs/tech-specs/mcp-tool-bearer-token.tr.md create mode 100644 docs/tech-specs/mcp-tool-bearer-token.zh-cn.md create mode 100644 docs/tech-specs/minio-to-s3-migration.ar.md create mode 100644 docs/tech-specs/minio-to-s3-migration.es.md create mode 100644 docs/tech-specs/minio-to-s3-migration.he.md create mode 100644 docs/tech-specs/minio-to-s3-migration.hi.md create mode 100644 docs/tech-specs/minio-to-s3-migration.pt.md create mode 100644 docs/tech-specs/minio-to-s3-migration.ru.md create mode 100644 docs/tech-specs/minio-to-s3-migration.sw.md create mode 100644 docs/tech-specs/minio-to-s3-migration.tr.md create mode 100644 docs/tech-specs/minio-to-s3-migration.zh-cn.md create mode 100644 docs/tech-specs/more-config-cli.pt.md create mode 100644 docs/tech-specs/more-config-cli.tr.md create mode 100644 docs/tech-specs/multi-tenant-support.ar.md create mode 100644 docs/tech-specs/multi-tenant-support.es.md create mode 100644 docs/tech-specs/multi-tenant-support.he.md create mode 100644 docs/tech-specs/multi-tenant-support.hi.md create mode 100644 docs/tech-specs/multi-tenant-support.pt.md create mode 100644 docs/tech-specs/multi-tenant-support.ru.md create mode 100644 docs/tech-specs/multi-tenant-support.sw.md create mode 100644 docs/tech-specs/multi-tenant-support.tr.md create mode 100644 docs/tech-specs/multi-tenant-support.zh-cn.md create mode 100644 docs/tech-specs/neo4j-user-collection-isolation.pt.md create mode 100644 docs/tech-specs/neo4j-user-collection-isolation.tr.md create mode 100644 docs/tech-specs/ontology-extract-phase-2.ar.md create mode 100644 docs/tech-specs/ontology-extract-phase-2.es.md create mode 100644 docs/tech-specs/ontology-extract-phase-2.he.md create mode 100644 docs/tech-specs/ontology-extract-phase-2.hi.md create mode 100644 docs/tech-specs/ontology-extract-phase-2.pt.md create mode 100644 docs/tech-specs/ontology-extract-phase-2.ru.md create mode 100644 docs/tech-specs/ontology-extract-phase-2.sw.md create mode 100644 docs/tech-specs/ontology-extract-phase-2.tr.md create mode 100644 docs/tech-specs/ontology-extract-phase-2.zh-cn.md create mode 100644 docs/tech-specs/ontology.pt.md create mode 100644 docs/tech-specs/ontology.tr.md create mode 100644 docs/tech-specs/ontorag.ar.md create mode 100644 docs/tech-specs/ontorag.es.md create mode 100644 docs/tech-specs/ontorag.he.md create mode 100644 docs/tech-specs/ontorag.hi.md create mode 100644 docs/tech-specs/ontorag.pt.md create mode 100644 docs/tech-specs/ontorag.ru.md create mode 100644 docs/tech-specs/ontorag.sw.md create mode 100644 docs/tech-specs/ontorag.tr.md create mode 100644 docs/tech-specs/ontorag.zh-cn.md create mode 100644 docs/tech-specs/openapi-spec.ar.md create mode 100644 docs/tech-specs/openapi-spec.es.md create mode 100644 docs/tech-specs/openapi-spec.he.md create mode 100644 docs/tech-specs/openapi-spec.hi.md create mode 100644 docs/tech-specs/openapi-spec.pt.md create mode 100644 docs/tech-specs/openapi-spec.ru.md create mode 100644 docs/tech-specs/openapi-spec.sw.md create mode 100644 docs/tech-specs/openapi-spec.tr.md create mode 100644 docs/tech-specs/openapi-spec.zh-cn.md create mode 100644 docs/tech-specs/pubsub.ar.md create mode 100644 docs/tech-specs/pubsub.es.md create mode 100644 docs/tech-specs/pubsub.he.md create mode 100644 docs/tech-specs/pubsub.hi.md create mode 100644 docs/tech-specs/pubsub.pt.md create mode 100644 docs/tech-specs/pubsub.ru.md create mode 100644 docs/tech-specs/pubsub.sw.md create mode 100644 docs/tech-specs/pubsub.tr.md create mode 100644 docs/tech-specs/pubsub.zh-cn.md create mode 100644 docs/tech-specs/python-api-refactor.ar.md create mode 100644 docs/tech-specs/python-api-refactor.es.md create mode 100644 docs/tech-specs/python-api-refactor.he.md create mode 100644 docs/tech-specs/python-api-refactor.hi.md create mode 100644 docs/tech-specs/python-api-refactor.pt.md create mode 100644 docs/tech-specs/python-api-refactor.ru.md create mode 100644 docs/tech-specs/python-api-refactor.sw.md create mode 100644 docs/tech-specs/python-api-refactor.tr.md create mode 100644 docs/tech-specs/python-api-refactor.zh-cn.md create mode 100644 docs/tech-specs/query-time-explainability.ar.md create mode 100644 docs/tech-specs/query-time-explainability.hi.md create mode 100644 docs/tech-specs/query-time-explainability.pt.md create mode 100644 docs/tech-specs/query-time-explainability.ru.md create mode 100644 docs/tech-specs/query-time-explainability.sw.md create mode 100644 docs/tech-specs/query-time-explainability.tr.md create mode 100644 docs/tech-specs/rag-streaming-support.hi.md create mode 100644 docs/tech-specs/rag-streaming-support.pt.md create mode 100644 docs/tech-specs/rag-streaming-support.sw.md create mode 100644 docs/tech-specs/rag-streaming-support.tr.md create mode 100644 docs/tech-specs/schema-refactoring-proposal.pt.md create mode 100644 docs/tech-specs/schema-refactoring-proposal.sw.md create mode 100644 docs/tech-specs/schema-refactoring-proposal.tr.md create mode 100644 docs/tech-specs/streaming-llm-responses.ar.md create mode 100644 docs/tech-specs/streaming-llm-responses.es.md create mode 100644 docs/tech-specs/streaming-llm-responses.he.md create mode 100644 docs/tech-specs/streaming-llm-responses.hi.md create mode 100644 docs/tech-specs/streaming-llm-responses.pt.md create mode 100644 docs/tech-specs/streaming-llm-responses.ru.md create mode 100644 docs/tech-specs/streaming-llm-responses.sw.md create mode 100644 docs/tech-specs/streaming-llm-responses.tr.md create mode 100644 docs/tech-specs/streaming-llm-responses.zh-cn.md create mode 100644 docs/tech-specs/structured-data-2.ar.md create mode 100644 docs/tech-specs/structured-data-2.es.md create mode 100644 docs/tech-specs/structured-data-2.he.md create mode 100644 docs/tech-specs/structured-data-2.hi.md create mode 100644 docs/tech-specs/structured-data-2.pt.md create mode 100644 docs/tech-specs/structured-data-2.ru.md create mode 100644 docs/tech-specs/structured-data-2.sw.md create mode 100644 docs/tech-specs/structured-data-2.tr.md create mode 100644 docs/tech-specs/structured-data-2.zh-cn.md create mode 100644 docs/tech-specs/structured-data-descriptor.ar.md create mode 100644 docs/tech-specs/structured-data-descriptor.es.md create mode 100644 docs/tech-specs/structured-data-descriptor.he.md create mode 100644 docs/tech-specs/structured-data-descriptor.hi.md create mode 100644 docs/tech-specs/structured-data-descriptor.pt.md create mode 100644 docs/tech-specs/structured-data-descriptor.ru.md create mode 100644 docs/tech-specs/structured-data-descriptor.sw.md create mode 100644 docs/tech-specs/structured-data-descriptor.tr.md create mode 100644 docs/tech-specs/structured-data-descriptor.zh-cn.md create mode 100644 docs/tech-specs/structured-data-schemas.pt.md create mode 100644 docs/tech-specs/structured-data-schemas.tr.md create mode 100644 docs/tech-specs/structured-data.ar.md create mode 100644 docs/tech-specs/structured-data.es.md create mode 100644 docs/tech-specs/structured-data.he.md create mode 100644 docs/tech-specs/structured-data.hi.md create mode 100644 docs/tech-specs/structured-data.pt.md create mode 100644 docs/tech-specs/structured-data.ru.md create mode 100644 docs/tech-specs/structured-data.sw.md create mode 100644 docs/tech-specs/structured-data.tr.md create mode 100644 docs/tech-specs/structured-data.zh-cn.md create mode 100644 docs/tech-specs/structured-diag-service.ar.md create mode 100644 docs/tech-specs/structured-diag-service.es.md create mode 100644 docs/tech-specs/structured-diag-service.he.md create mode 100644 docs/tech-specs/structured-diag-service.hi.md create mode 100644 docs/tech-specs/structured-diag-service.pt.md create mode 100644 docs/tech-specs/structured-diag-service.ru.md create mode 100644 docs/tech-specs/structured-diag-service.sw.md create mode 100644 docs/tech-specs/structured-diag-service.tr.md create mode 100644 docs/tech-specs/structured-diag-service.zh-cn.md create mode 100644 docs/tech-specs/tool-group.ar.md create mode 100644 docs/tech-specs/tool-group.es.md create mode 100644 docs/tech-specs/tool-group.he.md create mode 100644 docs/tech-specs/tool-group.hi.md create mode 100644 docs/tech-specs/tool-group.pt.md create mode 100644 docs/tech-specs/tool-group.ru.md create mode 100644 docs/tech-specs/tool-group.sw.md create mode 100644 docs/tech-specs/tool-group.tr.md create mode 100644 docs/tech-specs/tool-group.zh-cn.md create mode 100644 docs/tech-specs/tool-services.es.md create mode 100644 docs/tech-specs/tool-services.hi.md create mode 100644 docs/tech-specs/tool-services.pt.md create mode 100644 docs/tech-specs/tool-services.sw.md create mode 100644 docs/tech-specs/tool-services.tr.md diff --git a/docs/python-api.ar.md b/docs/python-api.ar.md new file mode 100644 index 00000000..12b3c477 --- /dev/null +++ b/docs/python-api.ar.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)` + +تهيئة عميل واجهة برمجة تطبيقات TrustGraph. + +**الوسائط:** + +`url`: عنوان URL الأساسي لواجهة برمجة تطبيقات TrustGraph (الافتراضي: "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)` + +إغلاق جميع اتصالات العميل غير المتزامنة. + +تقوم هذه الطريقة بإغلاق اتصالات 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 مع دعم البث. +هذه هي الطريقة المفضلة للبث غير المتزامن في Python. + +**المرتجعات:** 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: عميل إدارة المجموعة. + +**مثال:** + +```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: عميل إدارة التكوين. + +**مثال:** + +```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 منخفض المستوى. + +هذه الطريقة مخصصة بشكل أساسي للاستخدام الداخلي ولكن يمكن استخدامها للوصول المباشر إلى +واجهة برمجة التطبيقات عند الحاجة. + +**الوسائط:** + +`path`: مسار نقطة نهاية واجهة برمجة التطبيقات (بالنسبة لعنوان URL الأساسي) +`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`: معرف مثيل العملية + +**الإرجاع:** قاموس: تعريف مثيل العملية + +**مثال:** + +```python +flow_def = api.flow().get("default") +print(flow_def) +``` + +### `get_blueprint(self, blueprint_name)` + +الحصول على تعريف مخطط تدفق بالاسم. + +**الوسائط:** + +`blueprint_name`: اسم المخطط المراد استرجاعه. + +**الإرجاع:** قاموس: تعريف المخطط كقاموس. + +**مثال:** + +```python +blueprint = api.flow().get_blueprint("default") +print(blueprint) # Blueprint configuration +``` + +### `id(self, id='default')` + +الحصول على مثيل تدفق لتنفيذ العمليات على تدفق معين. + +**الوسائط:** + +`id`: مُعرّف التدفق (الافتراضي: "default") + +**الإرجاع:** FlowInstance: مثيل التدفق لعمليات الخدمة + +**مثال:** + +```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)` + +إرسال طلب واجهة برمجة تطبيقات (API) ضمن نطاق التدفق. + +**الوسائط:** + +`path`: لاحقة مسار اختيارية لنقاط نهاية التدفق. +`request`: قاموس حمولة الطلب. + +**الإرجاع:** dict: كائن الاستجابة. + +**الاستثناءات:** + +`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 +``` + +عميل مثيل التدفق لتنفيذ الخدمات في تدفق معين. + +توفر هذه الفئة الوصول إلى جميع خدمات TrustGraph بما في ذلك: +إكمال النص والتضمينات. +عمليات الوكيل مع إدارة الحالة. +استعلامات Graph و RAG للوثائق. +عمليات الرسم البياني المعرفي (ثلاثيات، كائنات). +تحميل الوثائق ومعالجتها. +تحويل اللغة الطبيعية إلى استعلام GraphQL. +تحليل البيانات المنظمة واكتشاف المخطط. +تنفيذ أداة MCP. +قالب المطالبات. + +يتم الوصول إلى الخدمات من خلال مثيل تدفق قيد التشغيل يتم تحديده بواسطة معرّف. + +### الطرق + +### `__init__(self, api, id)` + +تهيئة FlowInstance. + +**الوسائط:** + +`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 و بيانات وصفية. + +### `document_embeddings_query(self, text, user, collection, limit=10)` + +الاستعلام عن أجزاء المستندات باستخدام التشابه الدلالي. + +يجد أجزاء المستندات التي يكون محتوىها متشابهًا دلاليًا مع +النص المدخل، باستخدام تضمينات المتجهات. + +**الوسائط:** + +`text`: نص الاستعلام للبحث الدلالي. +`user`: معرف المستخدم/المساحة. +`collection`: معرف المجموعة. +`limit`: الحد الأقصى لعدد النتائج (افتراضي: 10). + +**النتائج:** قاموس: نتائج الاستعلام مع الأجزاء التي تحتوي على 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`: مُعرّف المستخدم/مساحة المفاتيح (الافتراضي: "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). + +يستخدم الرسم البياني 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، صور، إلخ) لاستخراج ومعالجة +من خلال مسار المستند الخاص بالتدفق. + +**الوسائط:** + +`document`: محتوى المستند كبايت. +`id`: مُعرّف المستند الاختياري (يتم إنشاؤه تلقائيًا إذا كان فارغًا). +`metadata`: بيانات وصفية اختيارية (قائمة من الثلاثيات أو كائن مع طريقة الإرسال). +`user`: مُعرّف المستخدم/مساحة المفاتيح (اختياري). +`collection`: مُعرّف المجموعة (اختياري). + +**الإرجاع:** قاموس: استجابة المعالجة. + +**يُثير:** + +`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`: مُعرّف المستند الاختياري (يتم إنشاؤه تلقائيًا إذا كان فارغًا). +`metadata`: بيانات وصفية اختيارية (قائمة من الثلاثيات أو كائن مع طريقة الإرسال). +`charset`: ترميز الأحرف (افتراضي: "utf-8"). +`user`: مُعرّف المستخدم/مساحة المفاتيح (اختياري). +`collection`: مُعرّف المجموعة (اختياري). + +**الإرجاع:** قاموس: استجابة المعالجة. + +**الأخطاء:** + +`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`: قاموس معلمات الأداة (الافتراضي: {}). + +**الإرجاع:** 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')` + +تنفيذ سؤال بلغة طبيعية مقابل بيانات منظمة. +يجمع بين تحويل استعلام معالجة اللغة الطبيعية وتنفيذ GraphQL. + +**الوسائط:** + +`question`: سؤال بلغة طبيعية +`user`: معرف مساحة مفاتيح Cassandra (افتراضي: "trustgraph") +`collection`: معرف مجموعة البيانات (افتراضي: "default") + +**الإرجاع:** قاموس يحتوي على البيانات والأخطاء الاختيارية. + +### `text_completion(self, system, prompt)` + +تنفيذ إكمال نص باستخدام نموذج اللغة الكبير (LLM) الخاص بالتدفق. + +**الوسائط:** + +`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`: معرف الموضوع (اختياري، استخدم None للرمز بدل) +`p`: معرف الفاعل (اختياري، استخدم None للرمز بدل) +`o`: معرف المفعول به أو حرفي (اختياري، استخدم 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. + +يوفر عمليات إدارة التدفق المستندة إلى `async/await` بما في ذلك عمليات القائمة، +والبدء، والإيقاف، وإدارة تعريفات فئات التدفق. كما يوفر +الوصول إلى الخدمات الخاصة بنطاق التدفق مثل الوكلاء، وRAG، والاستعلامات عبر نقاط نهاية REST غير متدفقة. + + +ملاحظة: للحصول على دعم التدفق، استخدم `AsyncSocketClient` بدلاً من ذلك. + +### الطرق + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +تهيئة عميل التدفق غير المتزامن. + +**الوسائط:** + +`url`: عنوان URL الأساسي لواجهة برمجة تطبيقات TrustGraph. +`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]` + +إرسال طلب HTTP POST غير متزامن إلى واجهة برمجة التطبيقات (API) الخاصة بالبوابة. + +طريقة داخلية لإجراء طلبات مصادقة إلى واجهة برمجة التطبيقات (API) الخاصة بـ TrustGraph. + +**الوسائط:** + +`path`: مسار نقطة نهاية واجهة برمجة التطبيقات (API) (بالنسبة إلى عنوان URL الأساسي). +`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`: عميل التدفق غير المتزامن الرئيسي. +`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)` + +توليد تضمينات للنصوص المدخلة. + +تحويل النصوص إلى تمثيلات متجهة رقمية باستخدام نموذج التضمين المُكوّن في التدفق. +مفيد للبحث الدلالي ومقارنات التشابه. + + +**الوسائط:** + +`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]` + +إرسال طلب إلى خدمة ذات نطاق محدد. + +طريقة داخلية لاستدعاء الخدمات داخل مثيل التدفق هذا. + +**الوسائط:** + +`service`: اسم الخدمة (مثل، "agent"، "graph-rag"، "triples") +`request_data`: حمولة طلب الخدمة + +**الإرجاع:** dict: كائن استجابة الخدمة + +**يُصدر:** + +`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`: موجه النظام الذي يحدد سلوك نموذج اللغة الكبير. +`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، +مع تغليف مكتبة WebSocket غير المتزامنة باستخدام مولدات متزامنة لسهولة الاستخدام. +يدعم عمليات البث من الوكلاء، واستعلامات RAG، وإكمال النصوص. + +ملاحظة: هذا هو غلاف متزامن لعمليات WebSocket غير المتزامنة. للحصول على دعم غير متزامن حقيقي، استخدم AsyncSocketClient بدلاً من ذلك. + +### الطرق + + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +تهيئة عميل WebSocket متزامن. + +**الوسائط:** + +`url`: عنوان URL الأساسي لواجهة برمجة تطبيقات TrustGraph (سيتم تحويل HTTP/HTTPS إلى WS/WSS). +`timeout`: مهلة WebSocket بالثواني. +`token`: رمز مميز اختياري للمصادقة. + +### `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`: عميل المقبس الأبوي. +`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]` + +تنفيذ عملية وكيل مع دعم الشفافية. + +يقوم بإرسال كل من أجزاء المحتوى (أفكار الوكيل، ملاحظات الوكيل، إجابات الوكيل) +وأحداث المصدر (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`: معلمات إضافية يتم تمريرها إلى الخدمة + +**الإرجاع:** قاموس: نتائج الاستعلام مع معرفات الأجزاء لأجزاء المستندات المطابقة + +**مثال:** + +```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 يعتمد على المستندات مع خيار التدفق. + +يستخدم تضمينات المتجهات للعثور على أجزاء المستندات ذات الصلة، ثم يقوم بإنشاء +استجابة باستخدام نموذج لغوي كبير. يوفر وضع التدفق النتائج بشكل تدريجي. + +**الوسائط:** + +`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 للمستند من: +السؤال: استعلام المستخدم. +الاستكشاف: الأجزاء المستردة من مستودع المستندات (عدد الأجزاء). +التوليف: الإجابة التي تم إنشاؤها. + +**الوسائط:** + +`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`: معلمات إضافية يتم تمريرها إلى الخدمة. + +**الإرجاع:** قاموس: استجابة تحتوي على المتجهات (مجموعة واحدة لكل نص مدخل). + +**مثال:** + +```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 يعتمد على الرسم البياني مع خيار التدفق. + +يستخدم هيكل الرسم البياني للمعرفة للعثور على السياق ذي الصلة، ثم يقوم بإنشاء +استجابة باستخدام نموذج لغوي كبير. يوفر وضع التدفق النتائج بشكل تدريجي. + +**الوسائط:** + +`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 للرمز البري. +`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 +``` + +عميل 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)` + +تهيئة الكائن الذاتي. راجع 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 بتنسيق سلكي من قيمة. + +قواعد الكشف التلقائي (عندما يكون term_type هو None): + إذا كان بالفعل قاموسًا مع مفتاح 't' -> إرجاعه كما هو (قاموس Term بالفعل) + يبدأ بـ http://, https://, urn: -> IRI + محاط بأقواس الزاوية (مثل ) -> IRI (إزالة أقواس الزاوية) + أي شيء آخر -> حرفي + +**الوسائط:** + +`value`: قيمة المصطلح (سلسلة، قاموس، أو None) +`term_type`: واحد من 'iri'، 'literal'، أو None للكشف التلقائي +`datatype`: نوع البيانات للكائنات الحرفية (مثل xsd:integer) +`language`: علامة اللغة للكائنات الحرفية (مثل en) + +**الإرجاع:** قاموس: قاموس Term بتنسيق سلكي، أو None إذا كانت القيمة هي None + + +-- + +## `BulkClient` + +```python +from trustgraph.api import BulkClient +``` + +عميل للعمليات المجمعة المتزامنة للاستيراد/التصدير. + +يوفر نقل بيانات مجمع فعال عبر WebSocket لمجموعات البيانات الكبيرة. +يغلف عمليات WebSocket غير المتزامنة باستخدام مولدات متزامنة لسهولة الاستخدام. + +ملاحظة: للحصول على دعم غير متزامن حقيقي، استخدم AsyncBulkClient بدلاً من ذلك. + +### الطرق + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +تهيئة عميل مجمع متزامن. + +**الوسائط:** + +`url`: عنوان URL الأساسي لواجهة برمجة تطبيقات TrustGraph (سيتم تحويل HTTP/HTTPS إلى WS/WSS). +`timeout`: مهلة WebSocket بالثواني. +`token`: رمز مميز اختياري للمصادقة. + +### `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 و 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` + +استيراد كميات كبيرة من تضمينات الرسم البياني إلى مسار عمل. + +يقوم بتحميل تضمينات كيانات الرسم البياني بكفاءة عبر بث 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` + +تهيئة الكائن الذاتي. راجع 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` + +احصل على مقاييس بروميثيوس كنص. + + +-- + +## `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 لجلسة/سؤال الوكيل. +`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 مع اختيارات الحواف المعبأة، أو 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` + +تهيئة الذات. راجع 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 +``` + +حافة محددة مع شرح من خطوة GraphRAG Focus. + +**الحقول:** + +`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` + +استخراج القيمة من قاموس Term بتنسيق الأسلاك. + + +-- + +## `Triple` + +```python +from trustgraph.api import Triple +``` + +ثلاثية RDF تمثل عبارة في رسم بياني للمعرفة. + +**الحقول:** + +`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 + +إنشاء كائن سلسلة جديد من الكائن المعطى. إذا تم تحديد ترميز أو +معالج أخطاء، فيجب أن يعرض الكائن مخزن بيانات سيتم فك ترميزه باستخدام الترميز ومعالج الأخطاء المحددين. +بخلاف ذلك، يتم إرجاع نتيجة 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 + +إنشاء كائن سلسلة جديد من الكائن المعطى. إذا تم تحديد ترميز أو +معالجة الأخطاء، فيجب أن يعرض الكائن مخزن بيانات سيتم فك ترميزه باستخدام الترميز ومعالج الأخطاء المحدد. +بخلاف ذلك، يتم إرجاع نتيجة 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` + +تهيئة الذات. راجع 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`: (مستوى المستندات) + +**الحقول:** + +`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` + +تهيئة الذات. راجع 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` + +تهيئة الذات. راجع 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 +``` + +تدفق جزء (Chunk) لـ 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` + +تهيئة الذات (self). راجع 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 +``` + +يتم إطلاق هذا الحدث عند حدوث أخطاء في بروتوكول 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 Gateway). + + +-- + +## `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 +``` + +الفئة الأساسية لجميع أخطاء خدمة TrustGraph. + + +-- + diff --git a/docs/python-api.ru.md b/docs/python-api.ru.md new file mode 100644 index 00000000..ad8195aa --- /dev/null +++ b/docs/python-api.ru.md @@ -0,0 +1,4071 @@ +# Справочник API TrustGraph на Python + +## Установка + +```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`: Базовый URL для API TrustGraph (по умолчанию: "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)` + +Закройте все асинхронные клиентские соединения. + +Этот метод закрывает асинхронные 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)` + +Получите асинхронного клиента для сбора метрик. + +Предоставляет доступ к метрикам Prometheus в стиле async/await. + +**Возвращает:** AsyncMetrics: Асинхронный клиент для сбора метрик. + +**Пример:** + +```python +async_metrics = api.async_metrics() +prometheus_text = await async_metrics.get() +print(prometheus_text) +``` + +### `async_socket(self)` + +Получите асинхронный WebSocket-клиент для операций потоковой передачи. + +Предоставляет доступ к WebSocket в стиле async/await с поддержкой потоковой передачи. +Это предпочтительный метод для асинхронной потоковой передачи в Python. + +**Возвращает:** 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 на низком уровне. + +Этот метод предназначен в основном для внутреннего использования, но может использоваться для прямого +доступа к API, когда это необходимо. + +**Аргументы:** + +`path`: Путь к API (относительно базового URL) +`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: Объект Flow для операций сервиса. + +**Пример:** + +```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)` + +Отправьте API-запрос в рамках одного потока. + +**Аргументы:** + +`path`: Необязательный суффикс пути для конечных точек потока. +`request`: Словарь, содержащий полезную нагрузку запроса. + +**Возвращает:** dict: Объект ответа. + +**Вызывает исключение:** + +`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 +``` + +Клиент экземпляра потока для выполнения сервисов в определенном потоке. + +Этот класс предоставляет доступ ко всем сервисам TrustGraph, включая: +Завершение текста и создание векторных представлений +Операции агентов с управлением состоянием +Запросы RAG к графам и документам +Операции с графами знаний (тройки, объекты) +Загрузка и обработка документов +Преобразование естественного языка в запрос GraphQL +Анализ структурированных данных и обнаружение схемы +Выполнение инструмента MCP +Шаблонизация запросов + +Сервисы доступны через работающий экземпляр потока, идентифицированный по ID. + +### Методы + +### `__init__(self, api, id)` + +Инициализация FlowInstance. + +**Аргументы:** + +`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`: Образец данных для анализа (текстовое содержимое) + +**Возвращает:** словарь с информацией о типе, уверенности и необязательных метаданных. + +### `diagnose_data(self, sample, schema_name=None, options=None)` + +Выполнить комплексную диагностику данных: определить тип и сгенерировать описание. + +**Аргументы:** + +`sample`: Образец данных для анализа (текстовое содержимое) +`schema_name`: Необязательное имя целевой схемы для генерации описания. +`options`: Необязательные параметры (например, разделитель для CSV). + +**Возвращает:** словарь с информацией о типе, уверенности, описании и метаданных. + +### `document_embeddings_query(self, text, user, collection, limit=10)` + +Запрос фрагментов документов с использованием семантического сходства. + +Находит фрагменты документов, содержимое которых семантически похоже на +входной текст, используя векторные представления. + +**Аргументы:** + +`text`: Текст запроса для семантического поиска. +`user`: Идентификатор пользователя/пространства. +`collection`: Идентификатор коллекции. +`limit`: Максимальное количество результатов (по умолчанию: 10). + +**Возвращает:** словарь: Результаты запроса с фрагментами, содержащими 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)` + +Выполнение запроса Retrieval-Augmented Generation (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, изображений и т.д.) для извлечения и +обработки через конвейер документов. + +**Аргументы:** + +`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={})` + +Выполнить инструмент протокола контекста модели (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`: Словарь, содержащий соответствия между именами переменных и их значениями. + +**Возвращает:** str или dict: Результат отрисованного запроса (текст или структурированный объект). + +**Вызывает исключение:** + +`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 потока. + +**Аргументы:** + +`system`: Системная подсказка, определяющая поведение помощника +`prompt`: Подсказка/вопрос пользователя + +**Возвращает:** str: Сгенерированный текст ответа + +**Пример:** + +```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 и запросы, через REST-интерфейсы без потоковой передачи. + + +Обратите внимание: для поддержки потоковой передачи используйте AsyncSocketClient. + +### Методы + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +Инициализация асинхронного клиента для управления процессами. + +**Аргументы:** + +`url`: Базовый URL для API TrustGraph. +`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)` + +Получение экземпляра клиента асинхронного потока. + +Возвращает клиент для взаимодействия со службами конкретного потока (агент, 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]` + +Перечислить все идентификаторы потоков. + +Получает идентификаторы всех потоков, которые в настоящее время развернуты в системе. + +**Возвращает:** 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 шлюза. + +Внутренний метод для выполнения аутентифицированных запросов к API TrustGraph. + +**Аргументы:** + +`path`: Путь к API (относительно базового URL) +`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)` + +Генерирует векторные представления для входных текстов. + +Преобразует тексты в числовые векторные представления, используя +настроенную модель для создания векторных представлений. Полезно для семантического поиска и +сравнения схожести. + +**Аргументы:** + +`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]` + +Отправка запроса к сервису, доступному в рамках текущего потока. + +Внутренний метод для вызова сервисов в пределах текущего экземпляра потока. + +**Аргументы:** + +`service`: Имя сервиса (например, "agent", "graph-rag", "triples") +`request_data`: Тело запроса к сервису + +**Возвращает:** dict: Объект ответа от сервиса + +**Вызывает исключения:** + +`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`: Необязательный токен для аутентификации + +### `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`: Родительский 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`: Необязательный словарь состояния для разговоров с состоянием +`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`: Дополнительные параметры, передаваемые сервису + +**Возвращает:** 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 для подстановки +`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 +``` + +Асинхронный WebSocket клиент + +### Методы + +### `__init__(self, url: str, timeout: int, token: str | None)` + +Инициализация объекта `self`. См. `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 в формате двоичных данных из значения. + +Правила автоматического определения (когда `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 в формате двоичных данных или 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`: Необязательный токен для аутентификации + +### `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 (Retrieval-Augmented Generation) к документам. + +**Аргументы:** + +`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`: Словарь метаданных с id, метаданными, пользователем, коллекцией +`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` + +Инициализация объекта. См. 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`: Максимальное количество сессий для возврата + +**Возвращает:** Список сущностей Question, отсортированный по времени (самые новые в начале) + +### `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` + +Инициализация объекта self. См. help(type(self)) для получения точного определения. + + +-- + +## `Question` + +```python +from trustgraph.api import Question +``` + +Вопрос (Question entity) - запрос пользователя, который инициировал сессию. + +**Поля (Fields):** + +`uri`: +`entity_type`: +`query`: +`timestamp`: +`question_type`: + +### Методы (Methods) + +### `__init__(self, uri: str, entity_type: str = '', query: str = '', timestamp: str = '', question_type: str = '') -> None` + +Инициализация self. См. 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` + +Инициализация self. См. 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` + +Инициализация self. См. 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` + +Инициализация self. См. 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). +encoding по умолчанию - 'utf-8'. +errors по умолчанию - '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). +encoding по умолчанию - 'utf-8'. +errors по умолчанию - '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` + +Инициализация объекта self. См. 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` + +Инициализация self. См. 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 (Retrieval-Augmented Generation). + +Используется для потоковой передачи ответов от графовых систем 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` + +Инициализация объекта self. См. 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 +``` + +Ошибка извлечения документов RAG. + + +-- + +## `FlowError` + +```python +from trustgraph.api import FlowError +``` + +Ошибка управления потоком + + +-- + +## `GatewayError` + +```python +from trustgraph.api import GatewayError +``` + +Ошибка API Gateway + + +-- + +## `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 +``` + +Ошибка сервиса обработки запросов на естественном языке. + + +-- + +## `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.zh-cn.md b/docs/python-api.zh-cn.md new file mode 100644 index 00000000..5ff8e7db --- /dev/null +++ b/docs/python-api.zh-cn.md @@ -0,0 +1,4071 @@ +# TrustGraph Python API 参考 + +## 安装 + +```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](#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 +``` + +主要的 TrustGraph API 客户端,用于同步和异步操作。 + +此类提供对所有 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)` + +初始化 TrustGraph API 客户端。 + +**参数:** + +`url`: TrustGraph API 的基本 URL (默认值: "http://localhost:8088/"") +`timeout`: 请求超时时间,单位为秒 (默认值: 60) +`token`: 可选的用于身份验证的 bearer token + +**示例:** + +```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)` + +获取一个异步批量操作客户端。 + +提供通过 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)` + +获取一个异步指标客户端。 + +提供对 Prometheus 指标的 async/await 风格访问。 + +**返回值:** AsyncMetrics: 异步指标客户端 + +**示例:** + +```python +async_metrics = api.async_metrics() +prometheus_text = await async_metrics.get() +print(prometheus_text) +``` + +### `async_socket(self)` + +获取一个异步 WebSocket 客户端,用于流式操作。 + +提供异步/等待 (async/await) 风格的 WebSocket 访问,并支持流式传输。 +这是在 Python 中进行异步流式传输的首选方法。 + +**返回值:** 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 客户端,用于管理和与流程进行交互。 + +Flows 是 TrustGraph 中的主要执行单元,提供对 +诸如代理、RAG 查询、嵌入和文档处理等服务的访问。 + +**返回值:** Flow: 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)` + +获取一个同步指标客户端,用于监控。 + +从 TrustGraph 服务获取 Prometheus 格式的指标,用于监控和可观察性。 + +**返回值:** 指标:同步指标客户端 + + +**示例:** + +```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)` + +获取一个同步的 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`: 流程实例 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)` + +列出所有活动流程实例。 + +**返回值:** list[str]: 流程实例 ID 列表 + +**示例:** + +```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 请求。 + +**参数:** + +`path`: 可选的流程端点路径后缀 +`request`: 请求负载字典 + +**返回值:** dict: 响应对象 + +**异常:** + +`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`: 要停止的流程实例 ID + +**示例:** + +```python +api.flow().stop("my-flow") +``` + + +-- + +## `FlowInstance` + +```python +from trustgraph.api import FlowInstance +``` + +用于在特定流程上执行服务的流程实例客户端。 + +此类提供对所有 TrustGraph 服务的访问,包括: +文本补全和嵌入 +具有状态管理的代理操作 +图表和文档 RAG 查询 +知识图谱操作(三元组、对象) +文档加载和处理 +自然语言到 GraphQL 查询的转换 +结构化数据分析和模式检测 +MCP 工具执行 +提示模板 + +通过运行的流程实例访问服务,该实例由 ID 标识。 + +### 方法 + +### `__init__(self, api, id)` + +初始化 FlowInstance。 + +**参数:** + +`api`: 父级 Flow 客户端 +`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 和元数据的字典。 + +### `document_embeddings_query(self, text, user, collection, limit=10)` + +使用语义相似度查询文档块。 + +查找内容在语义上与输入文本相似的文档块,使用向量嵌入。 + + +**参数:** + +`text`: 用于语义搜索的查询文本。 +`user`: 用户/键空间标识符。 +`collection`: 集合标识符。 +`limit`: 最大结果数量(默认为 10)。 + +**返回值:** 字典:包含 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`: 用户/键空间标识符 (默认值: "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) 查询。 + +图 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、图像等),以便从流程的文档管道中提取和 +处理。 + +**参数:** + +`document`: 文档内容,以字节形式表示 +`id`: 可选的文档标识符(如果为 None,则自动生成) +`metadata`: 可选的元数据(三元组列表或具有 emit 方法的对象) +`user`: 用户/键空间标识符(可选) +`collection`: 集合标识符(可选) + +**返回值:** dict: 处理响应 + +**引发:** + +`RuntimeError`: 如果提供了元数据,但没有提供 id + +**示例:** + +```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`: 如果提供了元数据,但没有提供 id + +**示例:** + +```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`: 工具参数字典 (默认: {}) + +**返回值:** 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`: 变量名称到值的映射字典 + +**返回值:** str 或 dict: 渲染后的提示结果(文本或结构化对象) + +**引发:** + +`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: 包含 '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')` + +对结构化数据执行自然语言问题。 +结合 NLP 查询转换和 GraphQL 执行。 + +**参数:** + +`question`: 自然语言问题 +`user`: Cassandra keyspace 标识符(默认为:"trustgraph") +`collection`: 数据集合标识符(默认为:"default") + +**返回值:** 包含数据和可选错误的字典。 + +### `text_completion(self, system, prompt)` + +使用流程的 LLM 执行文本补全。 + +**参数:** + +`system`: 定义助手行为的系统提示。 +`prompt`: 用户提示/问题 + +**返回值:** str: 生成的响应文本 + +**示例:** + +```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]: 匹配的三元组对象的列表 + +**引发:** + +`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 和查询)的访问,这些服务通过非流式 +REST 接口提供。 + + +注意:对于流式支持,请使用 AsyncSocketClient。 + +### 方法 + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +初始化异步流程客户端。 + +**参数:** + +`url`:TrustGraph API 的基本 URL +`timeout`:请求超时时间(以秒为单位) +`token`:可选的用于身份验证的 bearer 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)` + +获取一个异步流程实例客户端。 + +返回一个客户端,用于与特定流程的服务进行交互(代理、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]` + +列出所有流程标识符。 + +获取系统中当前部署的所有流程的ID。 + +**返回值:** 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]` + +异步向网关API发送HTTP POST请求。 + +用于向TrustGraph API发送经过身份验证的请求的内部方法。 + +**参数:** + +`path`: API端点路径(相对于基本URL) +`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 +``` + +异步流程实例客户端。 + +提供对流程范围内的服务的异步/等待访问,包括代理、 +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)` + +为输入文本生成嵌入向量。 + +将文本转换为数值向量表示,使用流程配置的嵌入模型。适用于语义搜索和相似度 +比较。 + + +**参数:** + +`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]` + +向作用域为流程的服务发送请求。 + +用于在当前流程实例中调用服务的内部方法。 + +**参数:** + +`service`: 服务名称(例如,"agent", "graph-rag", "triples") +`request_data`: 服务请求负载 + +**返回值:** dict: 服务响应对象 + +**抛出异常:** + +`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 三元组。 + +搜索与指定的 subject(主体)、predicate(谓词)和/或 +object(对象)模式匹配的三元组。 模式使用 None 作为通配符来匹配任何值。 + +**参数:** + +`s`: Subject(主体)模式(None 表示通配符) +`p`: Predicate(谓词)模式(None 表示通配符) +`o`: Object(对象)模式(None 表示通配符) +`user`: 用户标识符(None 表示所有用户) +`collection`: 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 客户端,用于流式操作。 + +提供了对基于 WebSocket 的 TrustGraph 服务的同步接口, +通过使用同步生成器包装异步 WebSocket 库,以提高易用性。 +支持从代理接收流式响应、RAG 查询和文本补全。 + +注意:这是一个围绕异步 WebSocket 操作的同步包装器。对于 +真正的异步支持,请使用 AsyncSocketClient。 + +### 方法 + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +初始化同步 WebSocket 客户端。 + +**参数:** + +`url`:TrustGraph API 的基本 URL(HTTP/HTTPS 将转换为 WS/WSS) +`timeout`:WebSocket 超时时间(以秒为单位) +`token`:可选的用于身份验证的 bearer token + +### `close(self) -> None` + +关闭 WebSocket 连接。 + +注意:在异步代码中,清理由上下文管理器自动处理。 + +### `flow(self, flow_id: str) -> 'SocketFlowInstance'` + +获取用于 WebSocket 流式操作的 flow 实例。 + +**参数:** + +`flow_id`:Flow 标识符 + +**返回值:** SocketFlowInstance:具有流式方法的 Flow 实例 + +**示例:** + +```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 流程实例,用于流式操作。 + +它提供与 REST FlowInstance 相同的接口,但具有基于 WebSocket 的 +流式支持,用于实时响应。 所有方法都支持一个可选的 +`streaming` 参数,以启用增量结果交付。 + +### 方法 + +### `__init__(self, client: trustgraph.api.socket_client.SocketClient, flow_id: str) -> None` + +初始化 socket 流程实例。 + +**参数:** + +`client`: 父 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`: 可选的状态字典,用于具有状态的对话 +`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: 包含匹配文档块的 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]` + +执行基于文档的 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 字符串、Term 字典,或 None 表示通配符 +`p`: 谓语过滤器 - URI 字符串、Term 字典,或 None 表示通配符 +`o`: 对象过滤器 - URI/字面量字符串、Term 字典,或 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 字符串、Term 字典,或 None 表示通配符 +`p`: 谓语过滤器 - URI 字符串、Term 字典,或 None 表示通配符 +`o`: 对象过滤器 - URI/字面量字符串、Term 字典,或 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 +``` + +异步 WebSocket 客户端 + +### 方法 + +### `__init__(self, url: str, timeout: int, token: str | None)` + +初始化 self。请参考 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` + +带有可选流的 Agent + +### `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 字典。 + +自动检测规则(当 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 字典,如果值是 None 则返回 None + + +-- + +## `BulkClient` + +```python +from trustgraph.api import BulkClient +``` + +用于导入/导出的同步批量操作客户端。 + +通过 WebSocket 提供高效的大数据集批量数据传输。 +使用同步生成器包装异步 WebSocket 操作,以提高易用性。 + +注意:要获得真正的异步支持,请使用 AsyncBulkClient。 + +### 方法 + +### `__init__(self, url: str, timeout: int, token: str | None) -> None` + +初始化同步批量客户端。 + +**参数:** + +`url`:TrustGraph API 的基本 URL(HTTP/HTTPS 将转换为 WS/WSS) +`timeout`:WebSocket 超时时间(以秒为单位) +`token`:可选的用于身份验证的 bearer token + +### `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]: 三元组对象的流 + +**示例:** + +```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`: 包含 id、元数据、用户、集合的元数据字典 +`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]` + +从会话 URI 开始,获取完整的 Agent 跟踪。 + +遵循溯源链:问题 -> 分析(s) -> 结论。 + +**参数:** + +`session_uri`: Agent 会话/问题的 URI。 +`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]` + +从问题 URI 开始,获取完整的 DocumentRAG 跟踪。 + +遵循溯源链: + 问题 -> 关联 -> 探索 -> 综合。 + +**参数:** + +`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`: Focus 实体 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 跟踪。 + +遵循溯源链:问题 -> 关联 -> 探索 -> Focus -> 综合 + +**参数:** + +`question_uri`: 问题实体 URI +`graph`: 命名图 (默认: urn:graph:retrieval) +`user`: 用户/密钥空间标识符 +`collection`: 集合标识符 +`api`: 用于 librarian 访问的 TrustGraph Api 实例 (可选) +`max_content`: 综合的最大内容长度 + +**返回值:** 包含 question、grounding、exploration、focus、synthesis 实体的字典 + +### `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`: 要返回的会话的最大数量 + +**返回值:** 按时间戳排序的 Question 实体列表 (最新在前) + +### `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` + +初始化 self。请参考 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` + +初始化 self。请参阅 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` + +初始化 self。请参考 help(type(self)) 以获取准确的签名。 + + +-- + +## `Focus` + +```python +from trustgraph.api import Focus +``` + +关注实体 - 使用 LLM 推理选择的边(仅限 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` + +初始化 self。请参阅 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 +``` + +分析实体 - 一个思考/行动/观察循环(仅限Agent)。 + +**字段:** + +`uri`: +`entity_type`: +`action`: +`arguments`: +`thought`: +`observation`: + +### 方法 + +### `__init__(self, uri: str, entity_type: str = '', action: str = '', arguments: str = '', thought: str = '', observation: str = '') -> None` + +初始化 self。请参考 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]]` + +将线格式的三元组转换为 (s, p, o) 元组。 + + +-- + +### `extract_term_value(term: Dict[str, Any]) -> Any` + +从线格式的 Term 字典中提取值。 + + +-- + +## `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)。 +encoding 默认为 'utf-8'。 +errors 默认为 'strict'。 + +### 方法 + +### ⟦CODE_0⟧ + +### `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)。 +encoding 默认为 'utf-8'。 +errors 默认为 'strict'。 + +### 方法 + +### ⟦CODE_0⟧ + +### `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` + +初始化 self。请参阅 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` + +初始化 self。请参考 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 +``` + +Agent final answer chunk. + +Represents the agent's final response to the user's query after completing +its reasoning and tool use. + +**Attributes:** + +`chunk_type: Always "final`: answer" + +**Fields:** + +`content`: +`end_of_message`: +`chunk_type`: +`end_of_dialog`: + +### Methods + +### `__init__(self, content: str, end_of_message: bool = False, chunk_type: str = 'final-answer', end_of_dialog: bool = False) -> None` + +Initialize self. See help(type(self)) for accurate signature. + + +-- + +## `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` + +初始化 self。有关准确的签名,请参阅 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 +``` + +自然语言处理查询服务错误 + + +-- + +## `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/tech-specs/architecture-principles.zh-cn.md b/docs/tech-specs/architecture-principles.zh-cn.md index 8062853a..3c576dc7 100644 --- a/docs/tech-specs/architecture-principles.zh-cn.md +++ b/docs/tech-specs/architecture-principles.zh-cn.md @@ -43,7 +43,11 @@ **理由**: **理想**: 单进程提取,具有完整的状态可见性,可以实现完美的实体解析 +<<<<<<< HEAD **现实**: 可扩展性要求需要并行处理能力 +======= +**现实**: 扩展性要求需要并行处理能力 +>>>>>>> 82edf2d (New md files from RunPod) **折衷**: 设计用于在分布式进程中实现确定性实体标识 **实施**: @@ -53,7 +57,11 @@ 设计用于处理复杂实体解析场景的后备机制 ## 基础 5:事件驱动架构与发布-订阅 +<<<<<<< HEAD **决策**: 实施 pub-sub 消息系统,用于系统协调 +======= +**决策**: 实现发布-订阅消息系统,用于系统协调 +>>>>>>> 82edf2d (New md files from RunPod) **理由**: 允许知识提取、存储和查询组件之间的松散耦合 @@ -65,15 +73,20 @@ 用于知识更新、提取完成和查询结果的事件流 ## 基础 6:可重入代理通信 -**决策**: 支持用于基于代理的处理的可重入 pub-sub 操作 +**决策**: 支持用于基于代理的处理的可重入发布-订阅操作 **理由**: 允许代理触发和响应彼此,从而实现复杂的代理工作流程 支持复杂的多步骤知识处理管道 允许递归和迭代处理模式 +<<<<<<< HEAD **实施**: pub-sub 系统必须安全地处理可重入调用 +======= +**实现**: +发布-订阅系统必须安全地处理可重入调用 +>>>>>>> 82edf2d (New md files from RunPod) 防止无限循环的代理协调机制 支持代理工作流程编排 @@ -87,7 +100,11 @@ pub-sub 系统必须安全地处理可重入调用 **实施**: 查询转换层:图查询 → 列式查询 +<<<<<<< HEAD 支持图操作和分析工作负载的混合存储策略 +======= +混合存储策略,支持图操作和分析工作负载 +>>>>>>> 82edf2d (New md files from RunPod) 在这两种范例中保持查询性能 -- @@ -97,8 +114,13 @@ pub-sub 系统必须安全地处理可重入调用 1. **灵活性至上**: SPO/RDF 模型提供最大的适应性 2. **LLM 优化**: 所有设计决策都考虑 LLM 交互要求 3. **语义效率**: 直接的嵌入到节点映射,以实现最佳的查询性能 +<<<<<<< HEAD 4. **务实的扩展性**: 在完美准确性和实际的分布式处理之间取得平衡 5. **事件驱动协调**: pub-sub 实现松散耦合和可扩展性 +======= +4. **务实的扩展性**: 在完美的准确性与实际的分布式处理之间取得平衡 +5. **事件驱动协调**: 发布-订阅实现松散耦合和可扩展性 +>>>>>>> 82edf2d (New md files from RunPod) 6. **代理友好**: 支持复杂的多代理处理工作流程 7. **分析兼容性**: 桥接图和列式范例,以实现全面的查询 diff --git a/docs/tech-specs/extraction-provenance-subgraph.ar.md b/docs/tech-specs/extraction-provenance-subgraph.ar.md index fd1e7708..dce883cc 100644 --- a/docs/tech-specs/extraction-provenance-subgraph.ar.md +++ b/docs/tech-specs/extraction-provenance-subgraph.ar.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD # أصل الاستخراج: نموذج الرسم البياني الفرعي ## المشكلة @@ -7,6 +8,17 @@ لكل حقيقة معرفية. يؤدي معالجة جزء واحد ينتج عنه 20 علاقة إلى إنتاج حوالي 220 ثلاثية لتتبع الأصل بالإضافة إلى حوالي 20 ثلاثية معرفية - وهو عبء إضافي يقدر بحوالي 10:1. +======= +# المصدر: نموذج الرسم البياني الفرعي. + +## المشكلة + +في الوقت الحالي، تقوم عملية تتبع مصدر البيانات في وقت الاستخراج بإنشاء تجسيد كامل لكل +ثلاثية مستخرجة: معرف فريد `stmt_uri`، و `activity_uri`، والبيانات الوصفية المرتبطة بـ PROV-O لكل حقيقة معرفية. معالجة جزء واحد +... +والتي تؤدي إلى 20 علاقة، تنتج حوالي 220 ثلاثية بيانات أصلية بالإضافة إلى +حوالي 20 ثلاثية معرفة - وهو عبء إضافي يقدر بحوالي 10:1. +>>>>>>> 82edf2d (New md files from RunPod) هذا مكلف للغاية (من حيث التخزين والفهرسة والنقل) وغير دقيق من الناحية الدلالية. تتم معالجة كل جزء بواسطة استدعاء واحد لنموذج اللغة الكبير (LLM) ينتج @@ -20,7 +32,11 @@ kg-extract-agent)، مما يترك فجوات في مسار التدقيق. ## الحل +<<<<<<< HEAD استبدال عملية التجسيد لكل ثلاثية بنموذج **رسم بياني فرعي**: سجل واحد للبيانات الوصفية لكل جزء مستخرج، ويتم مشاركته عبر جميع الثلاثيات الناتجة عن هذا الجزء. +======= +استبدل عملية التجسيد لكل ثلاثية بنموذج **رسم بياني فرعي**: سجل واحد للبيانات الوصفية لكل جزء مستخرج، ويتم مشاركته عبر جميع الثلاثيات الناتجة عن هذا الجزء. +>>>>>>> 82edf2d (New md files from RunPod) @@ -30,7 +46,11 @@ kg-extract-agent)، مما يترك فجوات في مسار التدقيق. |-----|-----| | `stmt_uri` (`https://trustgraph.ai/stmt/{uuid}`) | `subgraph_uri` (`https://trustgraph.ai/subgraph/{uuid}`) | | `statement_uri()` | `subgraph_uri()` | +<<<<<<< HEAD | `tg:reifies` (1:1، تطابق) | `tg:contains` (1:كثير، احتواء) | +======= +| `tg:reifies` (1:1، تطابق) | `tg:contains` (1:متعدد، احتواء) | +>>>>>>> 82edf2d (New md files from RunPod) ### الهيكل المستهدف @@ -94,19 +114,31 @@ kg-extract-agent)، مما يترك فجوات في مسار التدقيق. نفس النمط مثل التعريفات. نفس التغييرات. +<<<<<<< HEAD ### المعالجات التي يجب إضافتها للتتبع (مفقودة حاليًا) +======= +### المعالجات التي سيتم إضافة التتبع إليها (مفقودة حاليًا) +>>>>>>> 82edf2d (New md files from RunPod) **kg-extract-ontology** (`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) +<<<<<<< HEAD حاليًا، يقوم بإخراج ثلاثيات بدون مصدر. أضف مصدر الرسم البياني الفرعي. +======= +حاليًا، يقوم بإخراج ثلاثيات بدون مصدر. أضف مصدر الرسوم البيانية الفرعية. +>>>>>>> 82edf2d (New md files from RunPod) باستخدام نفس النمط: رسم بياني فرعي واحد لكل جزء، `tg:contains` لكل ثلاثية مستخرجة. **kg-extract-agent** (`trustgraph-flow/trustgraph/extract/kg/agent/extract.py`) +<<<<<<< HEAD حاليًا، يقوم بإخراج ثلاثيات بدون مصدر. أضف مصدر الرسم البياني الفرعي +======= +حاليًا، يقوم بإخراج ثلاثيات بدون مصدر. أضف مصدر الرسوم البيانية الفرعية +>>>>>>> 82edf2d (New md files from RunPod) باستخدام نفس النمط. ### تغييرات في مكتبة المصادر المشتركة @@ -114,9 +146,15 @@ kg-extract-agent)، مما يترك فجوات في مسار التدقيق. **`trustgraph-base/trustgraph/provenance/triples.py`** استبدل `triple_provenance_triples()` بـ `subgraph_provenance_triples()` +<<<<<<< HEAD تقبل الدالة الجديدة قائمة بالثلاثيات المستخرجة بدلاً من ثلاثية واحدة. تقوم بإنشاء `tg:contains` واحد لكل ثلاثية، كتلة نشاط/وكيل مشتركة. قم بإزالة `triple_provenance_triples()` القديم. +======= +تقبل الدالة الجديدة قائمة بالثلاثيات المستخرجة بدلاً من ثلاثية واحدة +تقوم بإنشاء `tg:contains` واحد لكل ثلاثية، كتلة نشاط/وكيل مشتركة +قم بإزالة `triple_provenance_triples()` القديم +>>>>>>> 82edf2d (New md files from RunPod) **`trustgraph-base/trustgraph/provenance/uris.py`** @@ -126,7 +164,11 @@ kg-extract-agent)، مما يترك فجوات في مسار التدقيق. استبدل `TG_REIFIES` بـ `TG_CONTAINS` +<<<<<<< HEAD ### ليس ضمن النطاق +======= +### خارج النطاق +>>>>>>> 82edf2d (New md files from RunPod) **kg-extract-topics**: معالج بنمط قديم، ولا يتم استخدامه حاليًا في العمليات القياسية. @@ -155,7 +197,11 @@ for rel in rels: triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) ``` +<<<<<<< HEAD بعد (رسم بياني فرعي): +======= +بعد (الرسم البياني الفرعي): +>>>>>>> 82edf2d (New md files from RunPod) ```python sg_uri = subgraph_uri() @@ -200,6 +246,12 @@ def subgraph_provenance_triples( ### تغيير جذري +<<<<<<< HEAD هذا تغيير جذري في نموذج التتبع. لم يتم تم إصدارها، لذا لا توجد حاجة إلى ترحيل. الكود القديم `tg:reifies` / يمكن إزالة كود `statement_uri` تمامًا. +======= +هذا تغيير جذري في نموذج التتبع. لم يتم إصدار التتبع بعد، لذا لا توجد حاجة إلى ترحيل. يمكن إزالة الكود القديم ⟦CODE_0⟧ / ⟦CODE_0⟧ مباشرةً. +been released, so no migration is needed. The old `tg:reifies` / +`statement_uri` code can be removed outright. +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/extraction-provenance-subgraph.he.md b/docs/tech-specs/extraction-provenance-subgraph.he.md index d1878243..28c15128 100644 --- a/docs/tech-specs/extraction-provenance-subgraph.he.md +++ b/docs/tech-specs/extraction-provenance-subgraph.he.md @@ -3,24 +3,42 @@ ## בעיה מעקב מקורות מידע בזמן החילוץ מייצר כיום מימוש מלא לכל טריפל +<<<<<<< HEAD שחולץ: `stmt_uri` ייחודי, `activity_uri` ו-מטא-דאטה של PROV-O עבור כל עובדה ידע בודדת. עיבוד של חלק אחד שמייצר 20 קשרים מייצר כ-220 טריפלי מעקב מקורות מידע בנוסף ל-כ-20 טריפלי ידע - תקורה של בערך 10:1. +======= +שחולץ: `stmt_uri` ייחודי, `activity_uri` ו-מטא-דאטה של PROV-O הקשורים +לכל עובדה בידע. עיבוד של חלק אחד שמניב 20 קשרים מייצר כ-220 טריפלי +מעקב מקורות מידע בנוסף ל-כ-20 טריפלי ידע - תקורה של בערך 10:1. +>>>>>>> 82edf2d (New md files from RunPod) זה יקר (אחסון, אינדקס, העברה) וגם לא מדויק מבחינה סמנטית. כל חלק מעובד על ידי קריאה אחת של מודל שפה גדול (LLM) שמייצר את כל +<<<<<<< HEAD הטריפלים שלו בעסקה אחת. המודל הנוכחי של טריפל בודד מטשטש את זה על ידי יצירת האשליה של 20 אירועי חילוץ עצמאיים. בנוסף, לשני מתוך ארבעה מעבדי החילוץ (kg-extract-ontology, +======= +הטריפלים שלו בפעולה אחת. המודל הנוכחי, שמבוסס על טריפל בודד, +מטעה בכך שהוא יוצר את האשליה של 20 אירועי חילוץ עצמאיים. + + +בנוסף, לשני מתוך ארבעת מעבדי החילוץ (kg-extract-ontology, +>>>>>>> 82edf2d (New md files from RunPod) kg-extract-agent) אין מעקב מקורות מידע כלל, מה שמשאיר פערים במסלול הביקורת. ## פתרון +<<<<<<< HEAD החליפו את הפירוט של כל שלישייה במודל תת-גרף: רשומת מוצא אחת לכל חילוץ, המשותפת לכל השלישיות שנוצרו מחלק זה. +======= +החליפו את הפירוט של כל טריפל במודל תת-גרף: רשומת מוצא אחת לכל חילוץ, המשותפת לכל הטריפלים שנוצרו מחלק זה. +>>>>>>> 82edf2d (New md files from RunPod) ### שינוי מונחים @@ -34,7 +52,11 @@ kg-extract-agent) אין מעקב מקורות מידע כלל, מה שמשאי ### מבנה מטרה +<<<<<<< HEAD כל השלישיות של המוצא נכנסות לגרף המקוּם בשם `urn:graph:source`. +======= +כל הטריפלים של המוצא נכנסים לגרף המקוּם `urn:graph:source`. +>>>>>>> 82edf2d (New md files from RunPod) ``` # Subgraph contains each extracted triple (RDF-star quoted triples) @@ -134,7 +156,11 @@ kg-extract-agent) אין מעקב מקורות מידע כלל, מה שמשאי שונה **מקור בזמן שאילתה** (`urn:graph:retrieval`): נושא נפרד, כבר משתמש בדפוס שונה (שאילתה/חקירה/מיקוד/סינתזה) +<<<<<<< HEAD **מקור של מסמך/עמוד/קטע** (מקודד PDF, מפצל): כבר משתמש +======= +**מקור של מסמך/עמוד/קטע** (מקודד PDF, חותך): כבר משתמש +>>>>>>> 82edf2d (New md files from RunPod) ב-`derived_entity_triples()` שהוא לכל ישות, ולא לכל משולש — אין בעיית יתירות @@ -175,7 +201,11 @@ prov_triples = subgraph_provenance_triples( triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) ``` +<<<<<<< HEAD ### חתימה חדשה של עוזר +======= +### חתימה חדשה עבור עוזר +>>>>>>> 82edf2d (New md files from RunPod) ```python def subgraph_provenance_triples( diff --git a/docs/tech-specs/extraction-provenance-subgraph.hi.md b/docs/tech-specs/extraction-provenance-subgraph.hi.md index 547f5d1e..2e64546b 100644 --- a/docs/tech-specs/extraction-provenance-subgraph.hi.md +++ b/docs/tech-specs/extraction-provenance-subgraph.hi.md @@ -4,7 +4,11 @@ निष्कर्षण के समय का वर्तमान स्रोत जानकारी एक पूर्ण पुन: निरूपण प्रति उत्पन्न करता है निष्कर्षित त्रिगुट: प्रत्येक ज्ञान तथ्य के लिए एक अद्वितीय `stmt_uri`, `activity_uri`, और संबंधित +<<<<<<< HEAD PROV-O मेटाडेटा। एक ऐसे खंड को संसाधित करना जो 20 संबंधों का उत्पादन करता है, उसमें लगभग 220 स्रोत जानकारी त्रिगुट होते हैं, इसके अतिरिक्त +======= +PROV-O मेटाडेटा। एक ऐसे खंड को संसाधित करना जो 20 संबंध उत्पन्न करता है, उसमें लगभग 220 स्रोत जानकारी त्रिगुट होते हैं, इसके अतिरिक्त +>>>>>>> 82edf2d (New md files from RunPod) लगभग 20 ज्ञान त्रिगुट - लगभग 10:1 का ओवरहेड। @@ -63,7 +67,11 @@ kg-extract-agent) में कोई स्रोत जानकारी न ### मात्रा की तुलना +<<<<<<< HEAD एक ऐसे खंड के लिए जो N निकाले गए त्रिगुण उत्पन्न करता है: +======= +एक ऐसे खंड के लिए जो N निकाले गए त्रिगुण (ट्रिपल्स) उत्पन्न करता है: +>>>>>>> 82edf2d (New md files from RunPod) | | पुराना (प्रति-त्रिगुण) | नया (उप-ग्राफ) | |---|---|---| @@ -99,13 +107,20 @@ kg-extract-agent) में कोई स्रोत जानकारी न **kg-extract-ontology** (`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) +<<<<<<< HEAD वर्तमान में, यह बिना किसी स्रोत जानकारी के त्रिक उत्पन्न करता है। उपग्राफ स्रोत जानकारी जोड़ें। उसी पैटर्न का उपयोग करके: प्रत्येक खंड के लिए एक उपग्राफ, प्रत्येक के लिए `tg:contains`। निकाले गए त्रिगुट। +======= +वर्तमान में, यह बिना किसी स्रोत जानकारी के त्रिक (triples) उत्पन्न करता है। उप-ग्राफ (subgraph) की स्रोत जानकारी जोड़ें। +उसी पैटर्न का उपयोग करके: प्रत्येक खंड (chunk) के लिए एक उप-ग्राफ, प्रत्येक निकाले गए त्रिक के लिए `tg:contains`। + +>>>>>>> 82edf2d (New md files from RunPod) **kg-extract-agent** (`trustgraph-flow/trustgraph/extract/kg/agent/extract.py`) +<<<<<<< HEAD वर्तमान में, यह बिना किसी स्रोत जानकारी के त्रिक (triples) उत्पन्न करता है। समान पैटर्न का उपयोग करके सबग्राफ (subgraph) स्रोत जानकारी जोड़ें। @@ -117,6 +132,19 @@ kg-extract-agent) में कोई स्रोत जानकारी न नया फ़ंक्शन एक एकल के बजाय निकाले गए त्रिपुलों की सूची को स्वीकार करता है प्रत्येक ट्रिपल के लिए एक `tg:contains` उत्पन्न करता है, साझा गतिविधि/एजेंट ब्लॉक पुराने `triple_provenance_triples()` को हटा दें +======= +वर्तमान में, यह बिना किसी स्रोत जानकारी के त्रिक (triples) उत्पन्न करता है। उप-ग्राफ (subgraph) की स्रोत जानकारी उसी पैटर्न का उपयोग करके जोड़ें। + + +### साझा स्रोत पुस्तकालय (Shared Provenance Library) में परिवर्तन + +**`trustgraph-base/trustgraph/provenance/triples.py`** + +`triple_provenance_triples()` को `subgraph_provenance_triples()` से बदलें। +नया फ़ंक्शन एक एकल त्रिक के बजाय निकाले गए त्रिकों की एक सूची स्वीकार करता है। +प्रत्येक त्रिक के लिए एक `tg:contains` उत्पन्न करता है, जो साझा गतिविधि/एजेंट ब्लॉक है। +पुराने `triple_provenance_triples()` को हटा दें। +>>>>>>> 82edf2d (New md files from RunPod) **`trustgraph-base/trustgraph/provenance/uris.py`** @@ -128,12 +156,21 @@ kg-extract-agent) में कोई स्रोत जानकारी न ### दायरे में नहीं +<<<<<<< HEAD **kg-extract-topics**: पुराना-शैली का प्रोसेसर, वर्तमान में उपयोग में नहीं है। मानक प्रक्रियाओं में। **kg-extract-rows**: पंक्तियाँ उत्पन्न करता है, ट्रिपल नहीं, अलग उत्पत्ति मॉडल। मॉडल। **क्वेरी-टाइम प्रोवेनेंस** (`urn:graph:retrieval`): एक अलग चिंता का विषय, पहले से ही एक अलग पैटर्न का उपयोग करता है (प्रश्न/अन्वेषण/फोकस/संश्लेषण)। +======= +**kg-extract-topics**: पुराना शैली का प्रोसेसर, वर्तमान में उपयोग में नहीं है। + मानक प्रक्रियाओं में। +**kg-extract-rows**: पंक्तियाँ उत्पन्न करता है, ट्रिपल नहीं, अलग उत्पत्ति मॉडल। + मॉडल। +**क्वेरी-टाइम प्रोवेनेंस** (`urn:graph:retrieval`): एक अलग विषय, + पहले से ही एक अलग पैटर्न का उपयोग करता है (प्रश्न/अन्वेषण/ध्यान/संश्लेषण)। +>>>>>>> 82edf2d (New md files from RunPod) **दस्तावेज़/पृष्ठ/खंड प्रोवेनेंस** (पीडीएफ डिकोडर, चंकर): पहले से ही उपयोग करता है `derived_entity_triples()` जो प्रति-एंटिटी है, प्रति-ट्रिपल नहीं - कोई अनावश्यकता समस्या नहीं। @@ -155,7 +192,11 @@ for rel in rels: triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) ``` +<<<<<<< HEAD (उपग्राफ के बाद): +======= +(उप-ग्राफ के बाद): +>>>>>>> 82edf2d (New md files from RunPod) ```python sg_uri = subgraph_uri() @@ -200,6 +241,12 @@ def subgraph_provenance_triples( ### महत्वपूर्ण परिवर्तन +<<<<<<< HEAD यह उत्पत्ति मॉडल में एक महत्वपूर्ण बदलाव है। उत्पत्ति (प्रोवेनेंस) का जारी किया गया है, इसलिए माइग्रेशन की आवश्यकता नहीं है। पुराना `tg:reifies` / `statement_uri` कोड पूरी तरह से हटाया जा सकता है। +======= +यह प्रामाणिकता मॉडल में एक महत्वपूर्ण बदलाव है। प्रामाणिकता अभी तक जारी नहीं की गई है, इसलिए किसी माइग्रेशन की आवश्यकता नहीं है। पुराना ⟦CODE_0⟧ / ⟦CODE_0⟧ कोड पूरी तरह से हटाया जा सकता है। +यह प्रामाणिकता मॉडल में एक महत्वपूर्ण बदलाव है। प्रामाणिकता अभी तक जारी नहीं की गई है, इसलिए किसी माइग्रेशन की आवश्यकता नहीं है। पुराना `tg:reifies` / `tg:reifies` कोड पूरी तरह से हटाया जा सकता है। +यह प्रामाणिकता मॉडल में एक महत्वपूर्ण बदलाव है। प्रामाणिकता अभी तक जारी नहीं की गई है, इसलिए किसी माइग्रेशन की आवश्यकता नहीं है। पुराना `statement_uri` / `statement_uri` कोड पूरी तरह से हटाया जा सकता है। +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/extraction-provenance-subgraph.pt.md b/docs/tech-specs/extraction-provenance-subgraph.pt.md index bab9d315..01e30636 100644 --- a/docs/tech-specs/extraction-provenance-subgraph.pt.md +++ b/docs/tech-specs/extraction-provenance-subgraph.pt.md @@ -3,6 +3,7 @@ ## Problema A proveniência em tempo de extração atualmente gera uma reificação completa para cada +<<<<<<< HEAD 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. @@ -11,10 +12,21 @@ aproximadamente 20 triplas de conhecimento — uma sobrecarga de aproximadamente 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, +======= +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 das 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, por tripla, +>>>>>>> 82edf2d (New md files from RunPod) 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, +<<<<<<< HEAD kg-extract-agent) não possuem proveniência, deixando lacunas no registro de auditoria. @@ -23,6 +35,16 @@ kg-extract-agent) não possuem proveniência, deixando lacunas no registro de au 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. +======= +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. +>>>>>>> 82edf2d (New md files from RunPod) ### Mudança de Terminologia @@ -126,7 +148,11 @@ Substituir `statement_uri()` por `subgraph_uri()` Substituir `TG_REIFIES` por `TG_CONTAINS` +<<<<<<< HEAD ### Não no Escopo +======= +### Não está no Escopo +>>>>>>> 82edf2d (New md files from RunPod) **kg-extract-topics**: processador de estilo antigo, não usado atualmente em fluxos padrão @@ -175,7 +201,11 @@ prov_triples = subgraph_provenance_triples( triples.extend(set_graph(prov_triples, GRAPH_SOURCE)) ``` +<<<<<<< HEAD ### Nova Assinatura de Auxílio +======= +### Nova Assinatura de Ajuda +>>>>>>> 82edf2d (New md files from RunPod) ```python def subgraph_provenance_triples( @@ -200,6 +230,10 @@ def subgraph_provenance_triples( ### Mudança Significativa +<<<<<<< HEAD Esta é uma mudança significativa no modelo de rastreabilidade. A rastreabilidade não +======= +Esta é uma mudança significativa no modelo de rastreabilidade. A rastreabilidade ainda não +>>>>>>> 82edf2d (New md files from RunPod) 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 index 787b952d..110fd3fe 100644 --- a/docs/tech-specs/extraction-provenance-subgraph.ru.md +++ b/docs/tech-specs/extraction-provenance-subgraph.ru.md @@ -2,6 +2,7 @@ ## Проблема +<<<<<<< HEAD В настоящее время механизм отслеживания происхождения, работающий во время извлечения, создает полную реификацию для каждого извлеченного тройства: уникальный `stmt_uri`, `activity_uri` и связанные метаданные PROV-O для каждого отдельного факта знаний. Обработка одного блока @@ -23,6 +24,29 @@ kg-extract-agent) вообще не имеют информации об отс Заменить реификацию на уровне тройств на **модель подграфа**: одна запись отслеживания происхождения для каждого блока извлечения, используемая для всех тройств, созданных из этого блока. +======= +В настоящее время механизм отслеживания происхождения, действующий во время извлечения, создает полную реификацию для каждого +извлеченного тройного набора: уникальный `stmt_uri`, `activity_uri` и связанные +метаданные PROV-O для каждого отдельного факта знаний. Обработка одного блока, +который дает 20 отношений, приводит к появлению примерно 220 тройных наборов отслеживания происхождения, помимо +примерно 20 тройных наборов знаний — это примерно 10:1 избыточности. + +Это дорого (хранение, индексация, передача) и семантически +неточно. Каждый блок обрабатывается одним вызовом LLM, который создает +все свои тройные наборы за одну транзакцию. Текущая модель для каждого тройного набора +создает иллюзию 20 независимых событий извлечения. + + +Кроме того, два из четырех процессоров извлечения (kg-extract-ontology, +kg-extract-agent) вообще не имеют информации об отслеживании происхождения, что создает пробелы в +журнале аудита. + +## Решение + +Заменить реификацию для каждого тройного набора на **модель подграфа**: один +набор отслеживания происхождения для каждого извлеченного блока, который используется +для всех тройных наборов, созданных из этого блока. +>>>>>>> 82edf2d (New md files from RunPod) ### Изменение терминологии @@ -34,7 +58,11 @@ kg-extract-agent) вообще не имеют информации об отс ### Целевая структура +<<<<<<< HEAD Все тройства отслеживания происхождения должны быть помещены в именованный граф `urn:graph:source`. +======= +Все тройные наборы отслеживания происхождения должны быть помещены в именованный граф `urn:graph:source`. +>>>>>>> 82edf2d (New md files from RunPod) ``` # Subgraph contains each extracted triple (RDF-star quoted triples) @@ -71,12 +99,20 @@ kg-extract-agent) вообще не имеют информации об отс | Тройки активности | ~9 x N | ~9 | | Тройки агентов | 2 x N | 2 | | Метаданные утверждения/подграфа | 2 x N | 2 | +<<<<<<< HEAD | **Всего троек происхождения** | **~13N** | **N + 13** | +======= +| **Общее количество троек происхождения** | **~13N** | **N + 13** | +>>>>>>> 82edf2d (New md files from RunPod) | **Пример (N=20)** | **~260** | **33** | ## Область применения +<<<<<<< HEAD ### Модули для обновления (существующее происхождение, на тройку) +======= +### Процессоры для обновления (существующее происхождение, на тройку) +>>>>>>> 82edf2d (New md files from RunPod) **kg-extract-definitions** (`trustgraph-flow/trustgraph/extract/kg/definitions/extract.py`) @@ -94,19 +130,33 @@ kg-extract-agent) вообще не имеют информации об отс Та же схема, что и для сущностей. Те же изменения. +<<<<<<< HEAD ### Модули для добавления информации о происхождении (в настоящее время отсутствуют) +======= +### Процессоры для добавления происхождения (в настоящее время отсутствуют) +>>>>>>> 82edf2d (New md files from RunPod) **kg-extract-ontology** (`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) +<<<<<<< HEAD В настоящее время генерируются тройки без указания источника. Добавить информацию об источнике подграфа, используя ту же схему: один подграф для каждого фрагмента, `tg:contains` для каждой извлеченной тройки. +======= +В настоящее время генерируются тройки данных без указания источника. Добавить информацию об источнике подграфа, +используя ту же схему: один подграф для каждого блока, `tg:contains` для каждой +извлеченной тройки данных. +>>>>>>> 82edf2d (New md files from RunPod) **kg-extract-agent** (`trustgraph-flow/trustgraph/extract/kg/agent/extract.py`) +<<<<<<< HEAD В настоящее время генерируются тройки без указания источника. Добавить информацию об источнике подграфа, +======= +В настоящее время генерируются тройки данных без указания источника. Добавить информацию об источнике подграфа, +>>>>>>> 82edf2d (New md files from RunPod) используя ту же схему. ### Изменения в общей библиотеке отслеживания происхождения данных @@ -114,8 +164,13 @@ kg-extract-agent) вообще не имеют информации об отс **`trustgraph-base/trustgraph/provenance/triples.py`** Заменить `triple_provenance_triples()` на `subgraph_provenance_triples()` +<<<<<<< HEAD Новая функция принимает список извлеченных троек вместо одной Генерирует один `tg:contains` для каждой тройки, общий блок активности/агента +======= +Новая функция принимает список извлеченных троек данных вместо одной +Генерирует один `tg:contains` для каждой тройки данных, общий блок активности/агента +>>>>>>> 82edf2d (New md files from RunPod) Удалить старый `triple_provenance_triples()` **`trustgraph-base/trustgraph/provenance/uris.py`** diff --git a/docs/tech-specs/extraction-provenance-subgraph.sw.md b/docs/tech-specs/extraction-provenance-subgraph.sw.md index 2abf3c65..9b0558f5 100644 --- a/docs/tech-specs/extraction-provenance-subgraph.sw.md +++ b/docs/tech-specs/extraction-provenance-subgraph.sw.md @@ -2,6 +2,7 @@ ## Tatizo +<<<<<<< HEAD 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 @@ -16,12 +17,32 @@ huru. Zaidi ya hayo, vichakavu viwili vya nne vya uondoaji (kg-extract-ontology, kg-extract-agent) havina utoaji wowote, na hivyo kuacha pengo katika +======= +Hivi sasa, utoaji wa taarifa wakati wa utoaji huunda uelekezaji kamili kwa kila +triple iliyotoa: `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 taarifa juu ya +triples ~20 za maarifa - mzigo wa takriban 10:1. + +Hii ni ghali (uhifadhi, urekebishaji, usambazaji) na pia si sahihi kimaana. +Kila sehemu hushughulikiwa na simu moja ya LLM ambayo hutoa triples zake zote +katika mshughuliko mmoja. Mfumo wa sasa wa kila triple huficha hili kwa +kuunda udanganyifu wa matukio 20 ya kujitenga ya utoaji. + + +Zaidi ya hayo, vichakavu viwili vya utoaji vifo (kg-extract-ontology, +kg-extract-agent) havina taarifa zozote, na hivyo kuacha pengo katika +>>>>>>> 82edf2d (New md files from RunPod) njia ya ukaguzi. ## Suluhisho Badilisha uelekezaji wa kila triple na **mfumo wa subgraph**: rekodi moja +<<<<<<< HEAD ya utoaji kwa kila uondoaji wa sehemu, inayoshirikiwa na triples zote +======= +ya taarifa kwa kila utoaji wa sehemu, inayoshirikiwa na triples zote +>>>>>>> 82edf2d (New md files from RunPod) zilizozalishwa kutoka sehemu hiyo. ### Mabadiliko ya Dhana @@ -30,11 +51,19 @@ zilizozalishwa kutoka sehemu hiyo. |-----|-----| | `stmt_uri` (`https://trustgraph.ai/stmt/{uuid}`) | `subgraph_uri` (`https://trustgraph.ai/subgraph/{uuid}`) | | `statement_uri()` | `subgraph_uri()` | +<<<<<<< HEAD | `tg:reifies` (1:1, utambulisho) | `tg:contains` (1:wengi, uwezeshaji) | ### Muundo Unaolengwa Triples zote za utoaji huwekwa katika grafu iliyoitwa `urn:graph:source`. +======= +| `tg:reifies` (1:1, utambulisho) | `tg:contains` (1:wengi, kuingia) | + +### Muundo Unaolengwa + +Triples zote za taarifa huwekwa katika grafu iliyoitwa `urn:graph:source`. +>>>>>>> 82edf2d (New md files from RunPod) ``` # Subgraph contains each extracted triple (RDF-star quoted triples) @@ -94,7 +123,11 @@ Toa kundi la shughuli/wakala/uzalishaji mara moja baada ya loop Mfano sawa na ufafanuzi. Mabadiliko sawa. +<<<<<<< HEAD ### Wasindikaji ambao Watasasishwa ili Kuongeza Asili (sasa hayapo) +======= +### Wasindikaji ambao Wataongezwa Asili (sasa hayapo) +>>>>>>> 82edf2d (New md files from RunPod) **kg-extract-ontology** (`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) @@ -109,7 +142,11 @@ triple iliyochukuliwa. Hivi sasa hutoa triples bila asili. Ongeza asili ya subgraph kwa kutumia mfano sawa. +<<<<<<< HEAD ### Mabadiliko ya Maktaba ya Asili iliyoshirikiwa +======= +### Mabadiliko ya Maktaba ya Asili Iliyoshirikiwa +>>>>>>> 82edf2d (New md files from RunPod) **`trustgraph-base/trustgraph/provenance/triples.py`** @@ -126,7 +163,11 @@ Badilisha `statement_uri()` na `subgraph_uri()` Badilisha `TG_REIFIES` na `TG_CONTAINS` +<<<<<<< HEAD ### Hayajajumuishwa katika Upeo +======= +### Hayako Katika Upeo +>>>>>>> 82edf2d (New md files from RunPod) **kg-extract-topics**: wasindikaji wa mtindo wa zamani, hawatumiki kwa sasa katika mtiririko wa kawaida @@ -200,6 +241,10 @@ def subgraph_provenance_triples( ### Mabadiliko Makubwa +<<<<<<< HEAD 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⟧ / +======= +Hii ni mabadiliko makubwa kwa mfumo wa uhakikisho. Uhakikisho haujatolewa, kwa hivyo hakuna uhamishaji unaohitajika. Msimbo wa zamani wa ⟦CODE_0⟧ / +>>>>>>> 82edf2d (New md files from RunPod) `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 index 58fd85df..749709f0 100644 --- a/docs/tech-specs/extraction-provenance-subgraph.tr.md +++ b/docs/tech-specs/extraction-provenance-subgraph.tr.md @@ -5,6 +5,7 @@ Çı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 +<<<<<<< HEAD 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. @@ -12,6 +13,15 @@ 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. +======= +ve bu parça 20 ilişki üretiyorsa, yaklaşık 220 köken bilgisi üçlüsü, +yaklaşık 20 bilgi üçlüsünün üzerine eklenir; 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 üçlülerini tek bir işlemde üretir. Mevcut üçlü bazlı model, +bu durumu 20 bağımsız çıkarma olayının yanılsamasını yaratarak gizler. +>>>>>>> 82edf2d (New md files from RunPod) Ayrıca, dört çıkarma işlemcisinden ikisi (kg-extract-ontology, @@ -20,8 +30,13 @@ izinde boşluklara neden olmaktadır. ## Çözüm +<<<<<<< HEAD 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. +======= +Her üçlü için yapılan somutlaştırmayı, **alt grafik modeli** ile değiştirin: bir veri kaynağı +kaydı, o parçadan üretilen tüm üçlüler için ortak kullanılan bir parça çıkarımı için. +>>>>>>> 82edf2d (New md files from RunPod) ### Terminoloji Değişikliği @@ -30,11 +45,19 @@ Her üçlü için yapılan somutlaştırmayı, **bir alt grafik modeli** ile de |-----|-----| | `stmt_uri` (`https://trustgraph.ai/stmt/{uuid}`) | `subgraph_uri` (`https://trustgraph.ai/subgraph/{uuid}`) | | `statement_uri()` | `subgraph_uri()` | +<<<<<<< HEAD | `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. +======= +| `tg:reifies` (1:1, özdeşlik) | `tg:contains` (1:çok, içerik) | + +### Hedef Yapı + +Tüm veri kaynağı üçlüleri, `urn:graph:source` adlı grafiğe yerleştirilir. +>>>>>>> 82edf2d (New md files from RunPod) ``` # Subgraph contains each extracted triple (RDF-star quoted triples) @@ -71,12 +94,20 @@ N sayıda çıkarılan üçlü üreten bir parça için: | Aktivite üçlüleri | ~9 x N | ~9 | | Ajan üçlüleri | 2 x N | 2 | | İfade/alt grafik meta verileri | 2 x N | 2 | +<<<<<<< HEAD | **Toplam kaynak üçlüleri** | **~13N** | **N + 13** | +======= +| **Toplam köken üçlüleri** | **~13N** | **N + 13** | +>>>>>>> 82edf2d (New md files from RunPod) | **Örnek (N=20)** | **~260** | **33** | ## Kapsam +<<<<<<< HEAD ### Güncellenecek İşlemciler (mevcut kaynak, üçlü başına) +======= +### Güncellenecek İşlemciler (mevcut köken, üçlü başına) +>>>>>>> 82edf2d (New md files from RunPod) **kg-extract-definitions** (`trustgraph-flow/trustgraph/extract/kg/definitions/extract.py`) @@ -94,28 +125,47 @@ Paylaşılan aktivite/ajan/türetme bloğunu döngüden sonra bir kez yayınlay Tanımlarla aynı desen. Aynı değişiklikler. +<<<<<<< HEAD ### Kaynak Eklenmesi Gereken İşlemciler (şu anda eksik) +======= +### Köken Eklenmesi Gereken İşlemciler (şu anda eksik) +>>>>>>> 82edf2d (New md files from RunPod) **kg-extract-ontology** (`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) +<<<<<<< HEAD Şu anda, herhangi bir kaynak bilgisi olmadan üçlüler oluşturuluyor. Alt grafik kaynak bilgisini ekleyin. +======= +Şu anda, herhangi bir köken bilgisi olmadan üçlüler oluşturuluyor. Alt grafik köken bilgisini ekleyin. +>>>>>>> 82edf2d (New md files from RunPod) 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`) +<<<<<<< HEAD Ş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 +======= +Şu anda, herhangi bir köken bilgisi olmadan üçlüler oluşturuluyor. Alt grafik köken bilgisini aynı kalıbı kullanarak ekleyin. + + +### Paylaşılan Köken Bilgisi Kütüphanesi Değişiklikleri +>>>>>>> 82edf2d (New md files from RunPod) **`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. +<<<<<<< HEAD Her üçlü için bir `tg:contains` oluşturuyor, paylaşılan etkinlik/ajan bloğu. +======= +Her üçlü için bir `tg:contains` oluşturuyor, paylaşılan aktivite/ajan bloğu. +>>>>>>> 82edf2d (New md files from RunPod) Eski `triple_provenance_triples()`'ı kaldırın. **`trustgraph-base/trustgraph/provenance/uris.py`** @@ -126,17 +176,29 @@ Eski `triple_provenance_triples()`'ı kaldırın. `TG_REIFIES`'ı `TG_CONTAINS` ile değiştirin. +<<<<<<< HEAD ### Kapsam Dışında +======= +### Kapsam Dışı +>>>>>>> 82edf2d (New md files from RunPod) **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 +<<<<<<< HEAD **Ç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. +======= +**Çalışma zamanı köken 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 hayır. + tekrar sorun yok. +>>>>>>> 82edf2d (New md files from RunPod) ## Uygulama Notları diff --git a/docs/tech-specs/extraction-provenance-subgraph.zh-cn.md b/docs/tech-specs/extraction-provenance-subgraph.zh-cn.md index 1ca33eba..7dcaf3cd 100644 --- a/docs/tech-specs/extraction-provenance-subgraph.zh-cn.md +++ b/docs/tech-specs/extraction-provenance-subgraph.zh-cn.md @@ -2,6 +2,7 @@ ## 问题 +<<<<<<< HEAD 提取时 provenance 目前为每个提取的三元组生成完整的重构:一个唯一的 ⟦CODE_0⟧、⟦CODE_1⟧,以及与每个知识事实相关的 PROV-O 元数据。处理一个块 提取时 provenance 目前为每个提取的三元组生成完整的重构:一个唯一的 `stmt_uri`、`activity_uri`,以及与每个知识事实相关的 PROV-O 元数据。处理一个块 提取时 provenance 目前为每个提取的三元组生成完整的重构:一个唯一的 ⟦CODE_0⟧、⟦CODE_1⟧,以及与每个知识事实相关的 PROV-O 元数据。处理一个块 @@ -13,6 +14,19 @@ 所有其三元组。当前的每个三元组模型 通过制造 20 个独立提取 事件的假象来掩盖这一点。 +======= +提取时段的溯源信息目前会生成完整的实体化表示。 +提取的三元组:一个唯一的 `stmt_uri`,`activity_uri`,以及与之相关的 +PROV-O 元数据,用于每个知识事实。处理一个块 +这会产生 20 个关系,并在其基础上产生约 220 个溯源三元组,而知识三元组约为 20 个,这导致了大约 10:1 的开销。 + + +这既昂贵(存储、索引、传输),又在语义上 +不准确。每个片段都由单个 LLM 调用处理,该调用在一个事务中生成 +所有三元组。当前的每个三元组模型 +通过产生 20 个独立提取 +事件的幻觉来掩盖这一点。 +>>>>>>> 82edf2d (New md files from RunPod) 此外,四个提取处理器中的两个(kg-extract-ontology、 kg-extract-agent)完全没有来源信息,这在审计 @@ -20,7 +34,11 @@ kg-extract-agent)完全没有来源信息,这在审计 ## 解决方案 +<<<<<<< HEAD 将每个三元组的显式化替换为**子图模型**:每个数据块提取一个溯源记录,该记录在从该数据块生成的所有三元组中共享。 +======= +用 **子图模型** 替换三元组级别的显式化:每个数据块提取一个溯源记录,该记录与从该数据块生成的所有三元组共享。 +>>>>>>> 82edf2d (New md files from RunPod) @@ -30,11 +48,19 @@ kg-extract-agent)完全没有来源信息,这在审计 |-----|-----| | `stmt_uri` (`https://trustgraph.ai/stmt/{uuid}`) | `subgraph_uri` (`https://trustgraph.ai/subgraph/{uuid}`) | | `statement_uri()` | `subgraph_uri()` | +<<<<<<< HEAD | `tg:reifies` (1:1, 相同) | `tg:contains` (1:多, 包含) | ### 目标结构 所有溯源三元组都放入名为 `urn:graph:source` 的命名图中。 +======= +| `tg:reifies` (1:1, 身份) | `tg:contains` (1:多, 包含) | + +### 目标结构 + +所有溯源三元组都存储在名为 `urn:graph:source` 的图中。 +>>>>>>> 82edf2d (New md files from RunPod) ``` # Subgraph contains each extracted triple (RDF-star quoted triples) @@ -81,7 +107,11 @@ kg-extract-agent)完全没有来源信息,这在审计 **kg-extract-definitions** (`trustgraph-flow/trustgraph/extract/kg/definitions/extract.py`) +<<<<<<< HEAD 目前,它在每个定义的循环内部调用 `statement_uri()` + `triple_provenance_triples()`。 +======= +当前,它在每个定义的循环内部调用 `statement_uri()` + `triple_provenance_triples()`。 +>>>>>>> 82edf2d (New md files from RunPod) 更改: @@ -94,19 +124,31 @@ kg-extract-agent)完全没有来源信息,这在审计 模式与定义相同。 更改也相同。 +<<<<<<< HEAD ### 需要添加的处理器,用于添加来源信息(目前缺失) +======= +### 需要添加的处理器,用于添加来源信息(当前缺失) +>>>>>>> 82edf2d (New md files from RunPod) **kg-extract-ontology** (`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`) +<<<<<<< HEAD 目前会生成不带来源信息的三元组。添加子图来源信息。 +======= +目前会输出不带来源信息的三元组。添加子图来源信息。 +>>>>>>> 82edf2d (New md files from RunPod) 使用相同的模式:每个块一个子图,对于每个提取的三元组使用 `tg:contains`。 **kg-extract-agent** (`trustgraph-flow/trustgraph/extract/kg/agent/extract.py`) +<<<<<<< HEAD 目前会生成不带来源信息的三元组。添加子图来源信息。 +======= +目前会输出不带来源信息的三元组。添加子图来源信息。 +>>>>>>> 82edf2d (New md files from RunPod) 使用相同的模式。 ### 共享来源库的更改 @@ -114,7 +156,11 @@ kg-extract-agent)完全没有来源信息,这在审计 **`trustgraph-base/trustgraph/provenance/triples.py`** 将 `triple_provenance_triples()` 替换为 `subgraph_provenance_triples()` +<<<<<<< HEAD 新函数接受一个提取的三元组列表,而不是单个三元组。 +======= +新函数接受提取的三元组列表,而不是单个三元组。 +>>>>>>> 82edf2d (New md files from RunPod) 为每个三元组生成一个 `tg:contains`,共享活动/代理块。 移除旧的 `triple_provenance_triples()` @@ -132,11 +178,19 @@ kg-extract-agent)完全没有来源信息,这在审计 **kg-extract-rows**: 生成的是行,而不是三元组,具有不同的数据来源模型。 **查询时的数据来源** (⟦CODE_0⟧): 独立的关注点。 模型 +<<<<<<< HEAD **查询时的数据来源信息** (`urn:graph:retrieval`):独立的关注点, 已经使用了不同的模式(提问/探索/聚焦/综合)。 **文档/页面/块的来源**(PDF解码器,分块器):已经使用了。 `derived_entity_triples()`,这对于每个实体而言,而不是每个三元组而言,因此没有 重复的问题。 +======= +**查询时的数据来源信息** (`urn:graph:retrieval`): 独立的关注点, + 已经使用了不同的模式(问题/探索/重点/综合)。 +**文档/页面/块的来源**(PDF解码器,分块器):已经使用了。 + `derived_entity_triples()`,这对于每个实体而言,而不是每个三元组而言——没有。 + 重复问题。 +>>>>>>> 82edf2d (New md files from RunPod) ## 实现说明 diff --git a/docs/tech-specs/extraction-time-provenance.ar.md b/docs/tech-specs/extraction-time-provenance.ar.md index 7d066108..0435139f 100644 --- a/docs/tech-specs/extraction-time-provenance.ar.md +++ b/docs/tech-specs/extraction-time-provenance.ar.md @@ -11,19 +11,31 @@ ### التنفيذ الحالي يعمل أصل البيانات حاليًا على النحو التالي: +<<<<<<< HEAD يتم تخزين بيانات وصف المستند كـ RDF triples في الرسم البياني المعرفي. +======= +يتم تخزين بيانات وصف المستند كـ "ثلاثيات" RDF في الرسم البياني للمعرفة. +>>>>>>> 82edf2d (New md files from RunPod) يربط معرف المستند البيانات الوصفية بالمستند، بحيث يظهر المستند كعقدة في الرسم البياني. عند استخراج الحواف (العلاقات/الحقائق) من المستندات، تربط علاقة `subjectOf` الحافة المستخرجة بالمستند المصدر. ### المشاكل في النهج الحالي +<<<<<<< HEAD 1. **تحميل البيانات الوصفية المتكرر:** يتم تجميع بيانات وصف المستند وتحميلها بشكل متكرر مع كل مجموعة من الـ triples المستخرجة من هذا المستند. هذا مضيعة ويزيد من التكرار - نفس البيانات الوصفية تنتقل كحمولة مع كل مخرج استخراج. +======= +1. **تحميل البيانات الوصفية المتكرر:** يتم تجميع بيانات وصف المستند وتحميلها بشكل متكرر مع كل مجموعة من "الثلاثيات" المستخرجة من هذا المستند. هذا مضيعة ويزيد من التكرار - حيث تنتقل نفس البيانات الوصفية كحمولة مع كل مخرج استخراج. +>>>>>>> 82edf2d (New md files from RunPod) 2. **أصل بيانات سطحي:** تربط العلاقة `subjectOf` الحالية الحقائق مباشرة بالمستند ذي المستوى الأعلى فقط. لا توجد رؤية لسلسلة التحويل - أي الصفحة التي جاءت منها الحقيقة، أو الجزء، أو طريقة الاستخراج المستخدمة. ### الحالة المرغوبة +<<<<<<< HEAD 1. **تحميل البيانات الوصفية مرة واحدة:** يجب تحميل بيانات وصف المستند مرة واحدة وإرفاقها بعقدة المستند ذات المستوى الأعلى، وليس تكرارها مع كل مجموعة من الـ triples. +======= +1. **تحميل البيانات الوصفية مرة واحدة:** يجب تحميل بيانات وصف المستند مرة واحدة وإرفاقها بعقدة المستند ذات المستوى الأعلى، وليس تكرارها مع كل مجموعة من "الثلاثيات". +>>>>>>> 82edf2d (New md files from RunPod) 2. **رسم بياني كامل لأصل البيانات:** التقاط سلسلة التحويل الكاملة من المستند المصدر عبر جميع القطع الأثرية الوسيطة وصولاً إلى الحقائق المستخرجة. على سبيل المثال، تحويل مستند PDF: @@ -40,6 +52,7 @@ → ... ``` +<<<<<<< HEAD 3. **التخزين الموحد:** يتم تخزين الرسم البياني للأصل (provenance DAG) في نفس الرسم البياني للمعرفة كما يتم تخزين المعرفة المستخرجة. يتيح ذلك الاستعلام عن الأصل بنفس الطريقة التي يتم بها الاستعلام عن المعرفة - من خلال تتبع الحواف صعودًا في السلسلة من أي حقيقة إلى موقع مصدرها الدقيق. 4. **معرفات مستقرة:** لكل قطعة أثرية وسيطة (صفحة، جزء) معرف مستقر كعقدة في الرسم البياني. @@ -47,6 +60,15 @@ 5. **الربط بين الأب والطفل:** يتم ربط المستندات المشتقة بآبائها وصولاً إلى المستند المصدر الرئيسي باستخدام أنواع علاقات متسقة. 6. **تخصيص الحقائق بدقة:** تشير العلاقة `subjectOf` في الحواف المستخرجة إلى الأصل الفوري (الجزء)، وليس المستند الرئيسي. يتم استعادة الأصل الكامل من خلال التنقل عبر الرسم البياني للأصل. +======= +3. **التخزين الموحد:** يتم تخزين الرسم البياني للأصل (provenance DAG) في نفس الرسم البياني للمعرفة مثل المعرفة المستخرجة. يتيح ذلك الاستعلام عن الأصل بنفس الطريقة التي يتم بها الاستعلام عن المعرفة - من خلال تتبع الحواف صعودًا في السلسلة من أي حقيقة إلى موقع مصدرها الدقيق. + +4. **معرفات مستقرة:** لكل قطعة أثرية وسيطة (صفحة، جزء) معرف مستقر كعقدة في الرسم البياني. + +5. **الربط بين الأبناء والآباء:** يتم ربط المستندات المشتقة بآبائها وصولاً إلى المستند المصدر الرئيسي باستخدام أنواع علاقات متسقة. + +6. **تخصيص الحقائق بدقة:** تشير العلاقة `subjectOf` في الحواف المستخرجة إلى الأصل الفوري (الجزء)، وليس المستند الرئيسي. يتم استعادة الأصل الكامل من خلال اجتياز الرسم البياني للأصل. +>>>>>>> 82edf2d (New md files from RunPod) ## حالات الاستخدام @@ -58,6 +80,7 @@ 1. يرسل المستخدم استعلامًا إلى وكيل GraphRAG. 2. يسترجع الوكيل الحقائق ذات الصلة من الرسم البياني للمعرفة لصياغة استجابة. 3. وفقًا لمواصفات الأصل في وقت الاستعلام، يقوم الوكيل بالإبلاغ عن الحقائق التي ساهمت في الاستجابة. +<<<<<<< HEAD 4. يربط كل حقيقة بمصدره (الجزء) عبر الرسم البياني للأصل. 5. ترتبط الأجزاء بالصفحات، وترتبط الصفحات بمستندات المصدر. @@ -68,6 +91,18 @@ فهم بالضبط من أين في المستند (في أي صفحة، في أي قسم) نشأت الحقيقة. **القيمة:** يمكن للمستخدمين التحقق من صحة الاستجابات التي تم إنشاؤها بواسطة الذكاء الاصطناعي مقابل المصادر الأولية، مما يعزز الثقة ويمكن المستخدمين من التحقق من الحقائق. +======= +4. ترتبط كل حقيقة بمصدرها من خلال الرسم البياني للأصل. +5. ترتبط الأجزاء بالصفحات، وترتبط الصفحات بمستندات المصدر. + +**النتيجة في تجربة المستخدم:** يعرض الواجهة استجابة نموذج اللغة (LLM) جنبًا إلى جنب مع تحديد مصدر المعلومات. يمكن للمستخدم: +رؤية الحقائق التي دعمت الاستجابة. +الانتقال من الحقائق إلى الأجزاء إلى الصفحات إلى المستندات. +مراجعة المستندات المصدر الأصلية للتحقق من الادعاءات. +فهم بالضبط من أين في المستند (في أي صفحة، في أي قسم) نشأت الحقيقة. + +**القيمة:** يمكن للمستخدمين التحقق من الاستجابات التي تم إنشاؤها بواسطة الذكاء الاصطناعي مقابل المصادر الأولية، مما يعزز الثقة ويمكن المستخدمين من التحقق من الحقائق. +>>>>>>> 82edf2d (New md files from RunPod) ### UC2: تصحيح جودة الاستخراج @@ -79,6 +114,7 @@ ### UC4: حذف البيانات / الحق في النسيان +<<<<<<< HEAD يجب إزالة مستند المصدر (بسبب اللائحة العامة لحماية البيانات، أو لأسباب قانونية، إلخ). تتبع الرسم البياني للأصل للعثور على جميع الحقائق المشتقة وإزالتها. ### UC5: حل النزاعات @@ -90,6 +126,19 @@ بعض المصادر أكثر موثوقية من غيرها. يمكن ترجيح الحقائق أو تصفيتها بناءً على سلطة/جودة مستندات الأصل. ### UC7: مقارنة مسار الاستخراج +======= +يجب إزالة مستند المصدر (بسبب GDPR، أو لأسباب قانونية، وما إلى ذلك). ابحث في الرسم البياني للأصل وأزل جميع الحقائق المشتقة. + +### UC5: حل النزاعات + +تتناقض حقيقتان مع بعضهما البعض. تتبع كلتاهما إلى مصادرهما لفهم السبب واتخاذ قرار بشأن أي منهما يجب الوثوق به (المصدر الأكثر موثوقية، أو الأحدث، وما إلى ذلك). + +### UC6: وزن سلطة المصدر + +بعض المصادر أكثر موثوقية من غيرها. يمكن وزن الحقائق أو تصفيتها بناءً على سلطة/جودة مستندات الأصل. + +### UC7: مقارنة مسارات الاستخراج +>>>>>>> 82edf2d (New md files from RunPod) قارن المخرجات من طرق/إصدارات استخراج مختلفة. أي أداة استخراج أنتجت حقائق أفضل من نفس المصدر؟ @@ -101,6 +150,7 @@ #### القدرات الحالية (تم تنفيذها بالفعل) +<<<<<<< HEAD **ربط المستندات من الأب إلى الابن:** `parent_id` الحقل في `DocumentMetadata` - يربط المستند الابن بالمستند الأب `document_type` الحقل - القيم: `"source"` (أصلي) أو `"extracted"` (مشتق) @@ -129,22 +179,66 @@ `trustgraph-flow/trustgraph/librarian/service.py` - معالج الخدمة، تحميل المستند `trustgraph-flow/trustgraph/tables/library.py` - تخزين جدول Cassandra `trustgraph-base/trustgraph/schema/services/library.py` - تعريفات المخططات +======= +**ربط المستندات من النوع "الأب-الابن":** +الحقل `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` - تعريفات المخططات. +>>>>>>> 82edf2d (New md files from RunPod) #### الثغرات التي يجب معالجتها يحتوي أمين المكتبة على اللبنات الأساسية ولكن حاليًا: +<<<<<<< HEAD 1. الربط من الأب إلى الابن ذو مستوى واحد فقط - لا توجد أدوات مساعدة لتصفح الرسوم البيانية متعددة المستويات 2. لا يوجد مفردات قياسية لأنواع العلاقات (مثل `derivedFrom`، `extractedFrom`) 3. بيانات التتبع الوصفية (طريقة الاستخراج، والثقة، وموضع الجزء) غير موحدة 4. لا توجد واجهة برمجة تطبيقات للاستعلام للتنقل عبر سلسلة التتبع الكاملة من حقيقة إلى المصدر +======= +1. ربط الأب-الابن ذو مستوى واحد فقط - لا توجد أدوات مساعدة لتصفح الرسوم البيانية متعددة المستويات. +2. لا يوجد مفردات قياسية لأنواع العلاقات (مثل `derivedFrom`، `extractedFrom`). +3. بيانات التتبع الوصفية (طريقة الاستخراج، والثقة، وموضع الجزء) غير موحدة. +4. لا توجد واجهة برمجة تطبيقات للاستعلام للتنقل عبر سلسلة التتبع الكاملة من حقيقة إلى المصدر. +>>>>>>> 82edf2d (New md files from RunPod) ## تصميم التدفق الشامل يتبع كل معالج في خط الأنابيب نمطًا متسقًا: +<<<<<<< HEAD استقبال معرف المستند من البنية التحتية جلب المحتوى من أمين المكتبة إنتاج القطع الأثرية الفرعية لكل قطعة أثرية فرعية: حفظ في أمين المكتبة، وإصدار حافة إلى الرسم البياني، وتمرير المعرف إلى البنية التحتية +======= +استقبال معرف المستند من المصدر العلوي. +جلب المحتوى من أمين المكتبة. +إنتاج القطع الأثرية الفرعية. +لكل قطعة أثرية فرعية: حفظ في أمين المكتبة، وإصدار حافة إلى الرسم البياني، وتمرير المعرف إلى المكون التالي. +>>>>>>> 82edf2d (New md files from RunPod) ### تدفقات المعالجة @@ -239,11 +333,19 @@ PDF: Document → Pages → Chunks → Triples/Embeddings Text: Document → Chunks → Triples/Embeddings ``` +<<<<<<< HEAD التصميم يتكيف مع كل من المصدر والصفحة لأن وحدة التقسيم تعالج مدخلاتها بشكل عام - فهي تستخدم أي معرف مستند تتلقاه كمعرف رئيسي، بغض النظر عما إذا كان ذلك مستند مصدر أم صفحة. ### مخطط البيانات الوصفية (PROV-O) تستخدم البيانات الوصفية المتعلقة بالأصل علم الوجود W3C PROV-O. يوفر هذا مفردات قياسية ويمكن أن يمكّن التوقيع/المصادقة المستقبلية لنتائج الاستخراج. +======= +التصميم يتكيف مع كلتا الحالتين لأن وحدة التقسيم تعالج مدخلاتها بشكل عام - فهي تستخدم أي معرف مستند تتلقاه كمعرف رئيسي، بغض النظر عما إذا كان ذلك مستندًا أصليًا أم صفحة. + +### مخطط البيانات الوصفية (PROV-O) + +تستخدم البيانات الوصفية المتعلقة بالأصل علم الوجود W3C PROV-O. يوفر هذا مفردات قياسية ويمكن أن يتيح في المستقبل التوقيع والمصادقة على مخرجات الاستخراج. +>>>>>>> 82edf2d (New md files from RunPod) #### المفاهيم الأساسية في PROV-O @@ -264,7 +366,11 @@ Text: Document → Chunks → Triples/Embeddings #### البيانات الوصفية في كل مستوى +<<<<<<< HEAD **المستند المصدر (يتم إصداره بواسطة Librarian):** +======= +**المستند الأصلي (يتم إصداره بواسطة Librarian):** +>>>>>>> 82edf2d (New md files from RunPod) ``` doc:123 a prov:Entity . doc:123 dc:title "Research Paper" . @@ -289,7 +395,11 @@ activity:pdf-extract-456 tg:componentVersion "1.2.3" . activity:pdf-extract-456 prov:startedAtTime "2024-01-15T10:30:00Z" . ``` +<<<<<<< HEAD **الجزء (يتم إصداره بواسطة وحدة التجميع):** +======= +**جزء (يتم إصداره بواسطة أداة التقسيم):** +>>>>>>> 82edf2d (New md files from RunPod) ``` chunk:123-1-1 a prov:Entity . chunk:123-1-1 prov:wasDerivedFrom page:123-1 . @@ -355,7 +465,11 @@ activity:extract-999 tg:ontology . | `tg:chunkOverlap` | Activity | التداخل المُكوَّن بين الأجزاء | | `tg:componentVersion` | Activity | إصدار مكون TG | | `tg:llmModel` | Activity | نموذج LLM المستخدم للاستخراج | +<<<<<<< HEAD | `tg:ontology` | Activity | عنوان URI للأنطولوجيا المستخدم لتوجيه الاستخراج | +======= +| `tg:ontology` | Activity | عنوان URI للدلالة المستخدم لتوجيه الاستخراج | +>>>>>>> 82edf2d (New md files from RunPod) | `tg:embeddingModel` | Activity | النموذج المستخدم للتضمينات | | `tg:sourceText` | Statement | النص الدقيق الذي تم استخراج ثلاثية منه | | `tg:sourceCharOffset` | Statement | الإزاحة الحرفية داخل الجزء حيث يبدأ النص المصدر | @@ -363,7 +477,11 @@ activity:extract-999 tg:ontology . #### تهيئة المفردات (لكل مجموعة) +<<<<<<< HEAD الرسم البياني المعرفي محايد للأنطولوجيا ويبدأ فارغًا. عند كتابة بيانات سلالة PROV-O إلى مجموعة لأول مرة، يجب تهيئة المفردات باستخدام تسميات RDF لجميع الفئات والمحددات. يضمن ذلك عرضًا قابلاً للقراءة بواسطة الإنسان في الاستعلامات وواجهة المستخدم. +======= +الرسم البياني المعرفي محايد بالنسبة للدلالات ويبدأ فارغًا. عند كتابة بيانات سلالة PROV-O إلى مجموعة لأول مرة، يجب تهيئة المفردات باستخدام تسميات RDF لجميع الفئات والمحددات. يضمن ذلك عرضًا قابلاً للقراءة بواسطة الإنسان في الاستعلامات وواجهة المستخدم. +>>>>>>> 82edf2d (New md files from RunPod) **فئات PROV-O:** ``` @@ -372,7 +490,11 @@ prov:Activity rdfs:label "Activity" . prov:Agent rdfs:label "Agent" . ``` +<<<<<<< HEAD **المُتَعَدِّيات (Predicates) الخاصة بـ PROV-O:** +======= +**المفردات (Predicates) الخاصة بـ PROV-O:** +>>>>>>> 82edf2d (New md files from RunPod) ``` prov:wasDerivedFrom rdfs:label "was derived from" . prov:wasGeneratedBy rdfs:label "was generated by" . @@ -403,12 +525,21 @@ tg:sourceCharLength rdfs:label "source character length" . **ملاحظة حول التنفيذ:** يجب أن يكون هذا الإطار اللغوي ذاتي الإعادة - آمنًا للتشغيل عدة مرات دون إنشاء تكرارات. يمكن تشغيله في معالجة المستند الأول في المجموعة، أو كخطوة منفصلة لتهيئة المجموعة. +<<<<<<< HEAD #### أصل الجزء الفرعي (طموح) للحصول على معلومات تفصيلية حول الأصل، سيكون من المفيد تسجيل المكان الدقيق داخل جزء معين حيث تم استخراج الثلاثي. هذا يسمح بـ: تسليط الضوء على النص المصدر الدقيق في واجهة المستخدم. التحقق من دقة الاستخراج مقابل المصدر. +======= +#### مصدر المعلومات التفصيلية (طموح) + +للحصول على معلومات تفصيلية حول المصدر، سيكون من المفيد تسجيل المكان الدقيق داخل جزء معين حيث تم استخراج الثلاثيات منه. هذا يسمح بـ: + +تسليط الضوء على النص المصدر الدقيق في واجهة المستخدم. +التحقق من دقة الاستخراج مقارنة بالمصدر. +>>>>>>> 82edf2d (New md files from RunPod) تصحيح جودة الاستخراج على مستوى الجملة. **مثال مع تتبع الموضع:** @@ -434,21 +565,34 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . **اعتبارات التنفيذ:** +<<<<<<< HEAD قد لا توفر استخراج البيانات باستخدام نماذج اللغة الكبيرة (LLM) بشكل طبيعي مواقع الأحرف. يمكن توجيه نموذج اللغة الكبيرة لإرجاع الجملة/العبارة المصدرية بالإضافة إلى الثلاثيات المستخرجة. بدلاً من ذلك، يمكن إجراء معالجة لاحقة لمطابقة الكيانات المستخرجة بشكل تقريبي مع النص المصدر. يوجد مقايضة بين تعقيد الاستخراج ودقة تتبع المصدر. قد يكون من الأسهل تحقيق ذلك باستخدام طرق الاستخراج المنظمة بدلاً من استخراج البيانات المجردة باستخدام نماذج اللغة الكبيرة. +======= +قد لا توفر عملية الاستخراج القائمة على نماذج اللغة الكبيرة (LLM) بشكل طبيعي مواقع الأحرف. +يمكن توجيه نموذج اللغة الكبيرة لإرجاع الجملة/العبارة المصدرية بالإضافة إلى الثلاثيات المستخرجة. +بدلاً من ذلك، يمكن إجراء معالجة لاحقة لمطابقة الكيانات المستخرجة بشكل تقريبي مع النص الأصلي. +يوجد مقايضة بين تعقيد الاستخراج ودقة تتبع المصدر. +قد يكون من الأسهل تحقيق ذلك باستخدام طرق الاستخراج المنظمة بدلاً من استخراج نماذج اللغة الكبيرة غير المنظمة. +>>>>>>> 82edf2d (New md files from RunPod) هذا الأمر مصنف على أنه طموح - يجب تنفيذ تتبع المصدر على مستوى المقطع أولاً، مع تتبع المقطع الفرعي كتحسين مستقبلي إذا كان ذلك ممكنًا. ### نموذج التخزين المزدوج +<<<<<<< HEAD يتم بناء رسم بياني لتتبع المصدر بشكل تدريجي أثناء تدفق المستندات عبر مسار العمل: +======= +يتم بناء رسم بياني (DAG) لتتبع المصدر تدريجيًا أثناء تدفق المستندات عبر مسار العمل: +>>>>>>> 82edf2d (New md files from RunPod) | التخزين | ما يتم تخزينه | الغرض | |-------|---------------|---------| | أمين المكتبة | محتوى المستند + روابط الأبناء | استرجاع المحتوى، حذف متسلسل | +<<<<<<< HEAD | الرسم البياني للمعرفة | حواف الأبناء، وبيانات وصفية | استعلامات تتبع المصدر، إسناد الحقائق | تحتفظ كلا التخزينين بنفس هيكل الرسم البياني. يحتوي أمين المكتبة على المحتوى، بينما يحتوي الرسم البياني على العلاقات ويمكنه تمكين استعلامات التصفح. @@ -464,6 +608,23 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . 4. **بناء تدريجي للرسم البياني** - يضيف كل معالج مستواه إلى الرسم البياني. يتم بناء سلسلة تتبع المصدر الكاملة بشكل تدريجي. 5. **تحسين ما بعد التقطيع** - بعد التقطيع، تحمل الرسائل كلاً من المعرف والمحتوى. تكون القطع صغيرة (2-4 كيلوبايت)، لذلك يؤدي تضمين المحتوى إلى تجنب عمليات الذهاب والإياب غير الضرورية إلى أمين المكتبة مع الحفاظ على تتبع المصدر عبر المعرف. +======= +| الرسم البياني المعرفي | حواف الأبناء، بالإضافة إلى البيانات الوصفية | استعلامات تتبع المصدر، إسناد الحقائق | + +تحتفظ كلتا الحالتين بنفس هيكل الرسم البياني. تحتفظ أمين المكتبة بالمحتوى، بينما يحتفظ الرسم البياني بالعلاقات ويمكنه تمكين استعلامات التصفح. + +### المبادئ الأساسية للتصميم + +1. **معرف المستند كوحدة تدفق** - تمرر المعالجات المعرفات، وليس المحتوى. يتم جلب المحتوى من أمين المكتبة عند الحاجة. + +2. **الإرسال مرة واحدة من المصدر** - يتم كتابة البيانات الوصفية في الرسم البياني مرة واحدة عند بدء المعالجة، وليس بشكل متكرر في المراحل اللاحقة. + +3. **نمط معالج متسق** - يتبع كل معالج نفس النمط: الاستقبال/الجلب/الإنتاج/الحفظ/الإرسال/التوجيه. + +4. **بناء تدريجي للرسم البياني** - يضيف كل معالج مستواه إلى الرسم البياني. يتم بناء سلسلة تتبع المصدر الكاملة بشكل تدريجي. + +5. **تحسين ما بعد التقسيم إلى أجزاء** - بعد التقسيم إلى أجزاء، تحمل الرسائل كلاً من المعرف والمحتوى. الأجزاء صغيرة (2-4 كيلوبايت)، لذا فإن تضمين المحتوى يتجنب عمليات الذهاب والإياب غير الضرورية إلى أمين المكتبة مع الحفاظ على تتبع المصدر عبر المعرف. +>>>>>>> 82edf2d (New md files from RunPod) ## مهام التنفيذ @@ -480,13 +641,21 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . **1. واجهة جديدة: اتصال بمخزن الثلاثيات** +<<<<<<< HEAD يحتاج أمين المكتبة إلى إرسال حواف بيانات وصفية للمستند مباشرة إلى الرسم البياني للمعرفة عند بدء المعالجة. +======= +تحتاج أمين المكتبة إلى إرسال حواف بيانات وصفية لمستندات الأبناء مباشرة إلى الرسم البياني المعرفي عند بدء المعالجة. +>>>>>>> 82edf2d (New md files from RunPod) إضافة عميل/ناشر مخزن الثلاثيات إلى خدمة أمين المكتبة. عند بدء المعالجة: إرسال بيانات وصفية للمستند الجذر كحواف في الرسم البياني (مرة واحدة). **2. مفردات أنواع المستندات** +<<<<<<< HEAD توحيد قيم `document_type` لأبناء المستند: +======= +توحيد قيم `document_type` لمستندات الأبناء: +>>>>>>> 82edf2d (New md files from RunPod) `source` - المستند الذي تم تحميله أصلاً. `page` - صفحة مستخرجة من المصدر (PDF، إلخ). `chunk` - جزء نصي مشتق من الصفحة أو المصدر. @@ -495,16 +664,26 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . | الواجهة | التغيير | |-----------|--------| +<<<<<<< HEAD | مخزن الثلاثيات | اتصال صادر جديد - إرسال حواف بيانات وصفية للمستند | +======= +| مخزن الثلاثيات | اتصال صادر جديد - إرسال حواف بيانات وصفية لمستندات الأبناء | +>>>>>>> 82edf2d (New md files from RunPod) | بدء المعالجة | إرسال البيانات الوصفية إلى الرسم البياني قبل توجيه معرف المستند | ### تغييرات مستخرج PDF #### الحالة الحالية +<<<<<<< HEAD يتلقى محتوى المستند (أو يتدفق المستندات الكبيرة). يستخرج النص من صفحات PDF. يوجه محتوى الصفحة إلى وحدة التقطيع. +======= +يتلقى محتوى المستند (أو يقوم بتدفق المستندات الكبيرة). +يستخرج النص من صفحات PDF. +يوجه محتوى الصفحة إلى وحدة تقسيم إلى أجزاء. +>>>>>>> 82edf2d (New md files from RunPod) لا يوجد تفاعل مع أمين المكتبة أو مخزن الثلاثيات. #### التغييرات المطلوبة @@ -517,36 +696,57 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . **2. واجهة جديدة: اتصال بمخزن الثلاثيات** +<<<<<<< HEAD يحتاج مستخرج PDF إلى إرسال حواف الأبناء إلى الرسم البياني للمعرفة. +======= +يحتاج مستخرج PDF إلى إرسال حواف الأبناء إلى الرسم البياني المعرفي. +>>>>>>> 82edf2d (New md files from RunPod) إضافة عميل/ناشر مخزن الثلاثيات. لكل صفحة: إرسال حافة تربط مستند الصفحة بالمستند الأصل. **3. تغيير تنسيق الإخراج** بدلًا من إرسال محتوى الصفحة مباشرةً، أرسل مُعرّف مستند الصفحة. +<<<<<<< HEAD سيقوم المقطع (Chunker) بجلب المحتوى من أمين المكتبة (librarian) باستخدام المعرّف. +======= +سيقوم المقطع (Chunker) بجلب المحتوى من المكتبة (librarian) باستخدام المعرّف. +>>>>>>> 82edf2d (New md files from RunPod) #### ملخص التغييرات في الواجهة | الواجهة | التغيير | |-----------|--------| +<<<<<<< HEAD | أمين المكتبة (Librarian) | واجهة تصدير جديدة - حفظ المستندات الفرعية | | قاعدة البيانات الثلاثية (Triple store) | واجهة تصدير جديدة - إرسال علاقات الأبناء والبنات | +======= +| المكتبة (librarian) | إخراج جديد - حفظ المستندات الفرعية | +| المستودع الثلاثي (Triple store) | إخراج جديد - إرسال علاقات الأبناء | +>>>>>>> 82edf2d (New md files from RunPod) | رسالة الإخراج | تغيير من المحتوى إلى مُعرّف المستند | ### تغييرات المقطع (Chunker) #### الحالة الحالية +<<<<<<< HEAD يستقبل محتوى الصفحة/النص يقسم إلى أجزاء (chunks) يرسل محتوى الجزء إلى المعالجات اللاحقة لا يوجد تفاعل مع أمين المكتبة أو قاعدة البيانات الثلاثية +======= +يتلقى محتوى الصفحة/النص +يقسم إلى أجزاء +يرسل محتوى الجزء إلى المعالجات اللاحقة +لا يوجد تفاعل مع المكتبة أو المستودع الثلاثي +>>>>>>> 82edf2d (New md files from RunPod) #### التغييرات المطلوبة **1. تغيير طريقة معالجة الإدخال** +<<<<<<< HEAD استقبل مُعرّف المستند بدلًا من المحتوى، وجلبه من أمين المكتبة. أضف عميل أمين المكتبة إلى خدمة المقطع. جلب محتوى الصفحة باستخدام مُعرّف المستند. @@ -560,36 +760,69 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . أرسل علاقات الأبناء والبنات إلى الرسم البياني المعرفي. أضف عميل/ناشر قاعدة البيانات الثلاثية. +======= +استقبل مُعرّف المستند بدلاً من المحتوى، وجلبه من المكتبة. +أضف عميل المكتبة إلى خدمة المقطع. +جلب محتوى الصفحة باستخدام مُعرّف المستند. + +**2. واجهة جديدة: عميل المكتبة (للكتابة)** + +احفظ كل جزء كمستند فرعي في المكتبة. +لكل جزء: اتصل بـ `add-child-document` مع `parent = مُعرّف مستند الصفحة` + +**3. واجهة جديدة: اتصال بالمستودع الثلاثي** + +أرسل علاقات الأبناء إلى الرسم البياني المعرفي. +أضف عميل/ناشر المستودع الثلاثي. +>>>>>>> 82edf2d (New md files from RunPod) لكل جزء: أرسل علاقة تربط مستند الجزء بمستند الصفحة. **4. تغيير تنسيق الإخراج** +<<<<<<< HEAD أرسل كلاً من مُعرّف مستند الجزء ومحتوى الجزء (تحسين لاحق للمقطع). تستقبل المعالجات اللاحقة المعرّف لأغراض التتبع + المحتوى للعمل به. +======= +أرسل كلاً من مُعرّف مستند الجزء ومحتوى الجزء (تحسين بعد تقسيم الجزء). +تتلقى المعالجات اللاحقة المعرّف لتتبع المصدر + المحتوى للعمل به. +>>>>>>> 82edf2d (New md files from RunPod) #### ملخص التغييرات في الواجهة | الواجهة | التغيير | |-----------|--------| | رسالة الإدخال | تغيير من المحتوى إلى مُعرّف المستند | +<<<<<<< HEAD | أمين المكتبة (Librarian) | واجهة تصدير جديدة (قراءة وكتابة) - جلب المحتوى، حفظ المستندات الفرعية | | قاعدة البيانات الثلاثية (Triple store) | واجهة تصدير جديدة - إرسال علاقات الأبناء والبنات | +======= +| المكتبة (librarian) | إخراج جديد (قراءة وكتابة) - جلب المحتوى، حفظ المستندات الفرعية | +| المستودع الثلاثي (Triple store) | إخراج جديد - إرسال علاقات الأبناء | +>>>>>>> 82edf2d (New md files from RunPod) | رسالة الإخراج | تغيير من المحتوى فقط إلى المعرّف + المحتوى | ### تغييرات مُستخرج المعرفة (Knowledge Extractor) #### الحالة الحالية +<<<<<<< HEAD يستقبل محتوى الجزء يستخرج الثلاثيات والتضمينات يرسل إلى قاعدة البيانات الثلاثية ومخزن التضمينات `subjectOf` تشير العلاقة إلى المستند ذي المستوى الأعلى (وليس الجزء) +======= +يتلقى محتوى الجزء +يستخرج الثلاثيات والتضمينات +يرسل إلى المستودع الثلاثي ومستودع التضمينات +تشير علاقة `subjectOf` إلى المستند ذي المستوى الأعلى (وليس الجزء). +>>>>>>> 82edf2d (New md files from RunPod) #### التغييرات المطلوبة **1. تغيير طريقة معالجة الإدخال** استقبل مُعرّف مستند الجزء بالإضافة إلى المحتوى. +<<<<<<< HEAD استخدم مُعرّف الجزء لأغراض الربط (المحتوى مدرج بالفعل كتحسين). **2. تحديث أثر الثلاثيات** @@ -603,12 +836,28 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . اربط معرفات كيانات التضمين بالجزء. أرسل حافة: معرف كيان التضمين → مُعرّف مستند الجزء +======= +استخدم مُعرّف الجزء لتتبع المصدر (تم تضمين المحتوى بالفعل كجزء من التحسين). + +**2. تحديث تتبع المصدر** + +اربط الثلاثيات المستخرجة بالجزء (وليس المستند ذي المستوى الأعلى). +استخدم التجريد لإنشاء حافة تشير إلى الحافة. +علاقة `subjectOf`: الثلاثية → مُعرّف مستند الجزء +الاستخدام الأول للدعم الحالي للتجريد. + +**3. تحديث تتبع التضمينات** + +اربط معرفات كيانات التضمين بالجزء. +أرسل حافة: معرف كيان التضمين → مُعرّف مستند الجزء. +>>>>>>> 82edf2d (New md files from RunPod) #### ملخص التغييرات في الواجهة | الواجهة | التغيير | |-----------|--------| | رسالة الإدخال | توقع مُعرّف الجزء + المحتوى (وليس المحتوى فقط) | +<<<<<<< HEAD | قاعدة البيانات الثلاثية | استخدم التجريد لأثر الثلاثية → الجزء | | أثر التضمين | اربط معرف الكيان → معرف الجزء | @@ -617,3 +866,13 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . أثر وقت الاستعلام: `docs/tech-specs/query-time-provenance.md` معيار PROV-O لنمذجة الأثر البيانات الوصفية المصدر الحالية في الرسم البياني المعرفي (تحتاج إلى تدقيق) +======= +| المستودع الثلاثي (Triple store) | استخدم التجريد لتتبع الثلاثية → الجزء | +| تتبع التضمينات | اربط معرف الكيان → معرف الجزء | + +## المراجع + +تتبع وقت الاستعلام: `docs/tech-specs/query-time-provenance.md` +معيار PROV-O لنمذجة التتبع. +البيانات الوصفية المصدر الحالية في الرسم البياني المعرفي (تحتاج إلى تدقيق). +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/extraction-time-provenance.es.md b/docs/tech-specs/extraction-time-provenance.es.md index e6721819..9e297568 100644 --- a/docs/tech-specs/extraction-time-provenance.es.md +++ b/docs/tech-specs/extraction-time-provenance.es.md @@ -19,13 +19,21 @@ Cuando se extraen aristas (relaciones/hechos) de los documentos, una relación ` 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. +<<<<<<< HEAD 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ó. +======= +2. **Proveniencia superficial:** La relación `subjectOf` actual solo vincula los hechos directamente al 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ó. +>>>>>>> 82edf2d (New md files from RunPod) ### 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. +<<<<<<< HEAD 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: +======= +2. **DAG de proveniencia enriquecido:** Capturar la cadena de transformación completa 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: +>>>>>>> 82edf2d (New md files from RunPod) ``` PDF file (source document with metadata) @@ -42,7 +50,11 @@ Cuando se extraen aristas (relaciones/hechos) de los documentos, una relación ` 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. +<<<<<<< HEAD 4. **Identificadores estables:** Cada artefacto intermedio (página, fragmento) tiene un identificador estable como un nodo en el grafo. +======= +4. **Identificadores estables:** Cada artefacto intermedio (página, fragmento) tiene un identificador estable como nodo en el grafo. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -61,7 +73,11 @@ Cuando se extraen aristas (relaciones/hechos) de los documentos, una relación ` 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. +<<<<<<< HEAD **Resultado de la experiencia de usuario:** La interfaz muestra la respuesta del LLM junto con la atribución de la fuente. El usuario puede: +======= +**Resultado de la experiencia del usuario:** La interfaz muestra la respuesta del LLM junto con la atribución de la fuente. El usuario puede: +>>>>>>> 82edf2d (New md files from RunPod) Ver qué hechos respaldaron la respuesta. Profundizar desde hechos → fragmentos → páginas → documentos. Examinar los documentos fuente originales para verificar las afirmaciones. @@ -95,6 +111,7 @@ Comparar los resultados de diferentes métodos/versiones de extracción. ¿Qué ## Puntos de integración +<<<<<<< HEAD ### 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. @@ -109,15 +126,36 @@ 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:** +======= +### Librarian + +El componente de "Librarian" 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áticamente. +API `list-children`: recupera todos los hijos de un documento padre. +Eliminación en cascada: eliminar un padre elimina automáticamente todos los documentos hijos. + +**Identificación de Documentos:** +>>>>>>> 82edf2d (New md files from RunPod) 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. +<<<<<<< HEAD **Soporte de metadatos:** +======= +**Soporte de Metadatos:** +>>>>>>> 82edf2d (New md files from RunPod) Campo `metadata: list[Triple]`: triples RDF para metadatos estructurados. `title`, `comments`, `tags`: metadatos básicos del documento. `time`: marca de tiempo, `kind`: tipo MIME. +<<<<<<< HEAD **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`). @@ -134,10 +172,29 @@ Entrega inteligente de contenido: documentos < 2 MB incrustados, documentos más 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. +======= +**Arquitectura de Almacenamiento:** +Los metadatos se almacenan en Cassandra (espacio de claves `librarian`, tabla `document`). +El contenido se almacena en MinIO/S3 (cubeta `library`). +Entrega inteligente de contenido: documentos < 2MB incrustados, documentos más grandes transmitidos por flujo. + +#### Archivos Clave + +`trustgraph-flow/trustgraph/librarian/librarian.py`: Operaciones principales de "Librarian". +`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 + +"Librarian" tiene los componentes básicos, pero actualmente: +1. La vinculación padre-hijo es de un solo nivel: no hay ayudantes para la travesía de DAG de varios niveles. +>>>>>>> 82edf2d (New md files from RunPod) 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. +<<<<<<< HEAD ## Diseño de flujo de extremo a extremo Cada procesador en la canalización sigue un patrón consistente: @@ -151,6 +208,21 @@ Para cada hijo: guarda en el bibliotecario, emite un borde al gráfico, reenvía Existen dos flujos dependiendo del tipo de documento: #### Flujo de documento PDF +======= +## Diseño de Flujo de Extremo a Extremo + +Cada procesador en la canalización sigue un patrón consistente: +Recibe el ID del documento desde el componente anterior. +Recupera el contenido de "Librarian". +Produce artefactos hijos. +Para cada hijo: guarda en "Librarian", emite un borde al grafo, reenvía el ID al componente posterior. + +### Flujos de Procesamiento + +Existen dos flujos dependiendo del tipo de documento: + +#### Flujo de Documentos PDF +>>>>>>> 82edf2d (New md files from RunPod) ``` ┌─────────────────────────────────────────────────────────────────────────┐ @@ -205,7 +277,11 @@ Existen dos flujos dependiendo del tipo de documento: #### Flujo de documentos de texto +<<<<<<< HEAD Los documentos de texto omiten el extractor de PDF y van directamente al fragmentador: +======= +Los documentos de texto omiten el extractor de PDF y van directamente al procesador de fragmentos: +>>>>>>> 82edf2d (New md files from RunPod) ``` ┌─────────────────────────────────────────────────────────────────────────┐ @@ -239,12 +315,17 @@ PDF: Document → Pages → Chunks → Triples/Embeddings Text: Document → Chunks → Triples/Embeddings ``` +<<<<<<< HEAD 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. +======= +El diseño se adapta a ambos casos porque el componente de división de texto (chunker) 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. +>>>>>>> 82edf2d (New md files from RunPod) ### 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. +<<<<<<< HEAD #### Conceptos principales de PROV-O | Tipo PROV-O | Uso en TrustGraph | @@ -252,6 +333,15 @@ Los metadatos de procedencia utilizan la ontología W3C PROV-O. Esto proporciona | `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 | +======= +#### Conceptos básicos de PROV-O + +| Tipo PROV-O | Uso en TrustGraph | +|-------------|------------------| +| `prov:Entity` | Documento, Página, Fragmento, Triple, Incrustación | +| `prov:Activity` | Instancias de operaciones de extracción | +| `prov:Agent` | Componentes de TG (extractor de PDF, componente de división de texto, etc.) con versiones | +>>>>>>> 82edf2d (New md files from RunPod) #### Relaciones PROV-O @@ -344,7 +434,11 @@ Predicados personalizados dentro del espacio de nombres `tg:` para metadatos esp | Predicado | Dominio | Descripción | |-----------|--------|-------------| +<<<<<<< HEAD | `tg:contains` | Subgrafo | Indica un triple contenido en este subgrafo de extracción | +======= +| `tg:contains` | Subgrafo | Apunta a un triple contenido en este subgrafo de extracción | +>>>>>>> 82edf2d (New md files from RunPod) | `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 | @@ -361,7 +455,11 @@ Predicados personalizados dentro del espacio de nombres `tg:` para metadatos esp | `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 | +<<<<<<< HEAD #### Inicialización del Vocabulario (Por Colección) +======= +#### Arranque del Vocabulario (Por Colección) +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -401,7 +499,11 @@ tg:sourceCharOffset rdfs:label "source character offset" . tg:sourceCharLength rdfs:label "source character length" . ``` +<<<<<<< HEAD **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. +======= +**Nota de implementación:** Este proceso de inicialización del vocabulario 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. +>>>>>>> 82edf2d (New md files from RunPod) #### Origen de los Sub-Fragmentos (Aspiracional) @@ -435,7 +537,11 @@ 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. +<<<<<<< HEAD Se podría solicitar al LLM que devuelva la oración/frase original junto con las triples extraídas. +======= +Se podría solicitar al LLM que devuelva la oración/frase fuente junto con las triples extraídas. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -455,15 +561,25 @@ Ambos almacenes mantienen la misma estructura DAG. El bibliotecario almacena el ### Principios de diseño clave +<<<<<<< HEAD 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. +======= +1. **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 aguas abajo. +>>>>>>> 82edf2d (New md files from RunPod) 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. +<<<<<<< HEAD 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. +======= +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. +>>>>>>> 82edf2d (New md files from RunPod) ## Tareas de implementación @@ -472,7 +588,11 @@ Ambos almacenes mantienen la misma estructura DAG. El bibliotecario almacena el #### Estado actual Inicia el procesamiento de documentos enviando el ID del documento al primer procesador. +<<<<<<< HEAD No tiene conexión con el almacén de triples; los metadatos se incluyen en los resultados de la extracción. +======= +No hay conexión con el almacén de triples; los metadatos se incluyen en los resultados de la extracción. +>>>>>>> 82edf2d (New md files from RunPod) `add-child-document` crea enlaces padre-hijo de un solo nivel. `list-children` devuelve solo los hijos inmediatos. @@ -487,9 +607,15 @@ Al iniciar el procesamiento: emitir los metadatos del documento raíz como borde **2. Vocabulario de tipos de documentos** Estandarizar los valores de `document_type` para los documentos hijo: +<<<<<<< HEAD `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. +======= +`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. +>>>>>>> 82edf2d (New md files from RunPod) #### Resumen de cambios de interfaz @@ -524,7 +650,11 @@ Para cada página: emitir un borde que vincule el documento de la página con el **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. +<<<<<<< HEAD El componente "Chunker" recuperará el contenido del "librarian" utilizando el ID. +======= +El componente "Chunker" obtendrá el contenido del "librarian" utilizando el ID. +>>>>>>> 82edf2d (New md files from RunPod) #### Resumen de Cambios en la Interfaz @@ -547,42 +677,71 @@ No interactúa con el "librarian" ni con el "triple store" **1. Cambiar el manejo de la entrada** +<<<<<<< HEAD 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 +======= +Recibir el ID del documento en lugar del contenido, obtenerlo del "librarian". +Agregar un cliente de "librarian" al servicio "chunker" +Obtener el contenido de la página utilizando el ID del documento +>>>>>>> 82edf2d (New md files from RunPod) **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 +<<<<<<< HEAD **3. Nueva interfaz: Conexión con el "Triple store"** Emitir aristas padre-hijo al grafo de conocimiento. Agregar un cliente/publicador de "triple store" +======= +**3. Nueva interfaz: Conexión al "Triple Store"** + +Emitir aristas padre-hijo al grafo de conocimiento. +Agregar un cliente/publicador del "triple store" +>>>>>>> 82edf2d (New md files from RunPod) 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"). +<<<<<<< HEAD Los procesadores posteriores reciben el ID para la trazabilidad y el contenido para trabajar con él +======= +Los procesadores posteriores reciben el ID para la trazabilidad + el contenido para trabajar con él +>>>>>>> 82edf2d (New md files from RunPod) #### Resumen de Cambios en la Interfaz | Interfaz | Cambio | |-----------|--------| | Mensaje de entrada | Cambio de contenido a ID de documento | +<<<<<<< HEAD | 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 +======= +| Librarian | Nueva salida (lectura + escritura) - obtener 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 "Knowledge Extractor" +>>>>>>> 82edf2d (New md files from RunPod) #### Estado Actual Recibe contenido del fragmento Extrae triples y embeddings +<<<<<<< HEAD Los emite al "triple store" y al almacén de "embeddings" +======= +Los emite al "triple store" y al "embedding store" +>>>>>>> 82edf2d (New md files from RunPod) La relación `subjectOf` apunta al documento de nivel superior (no al fragmento) #### Cambios Requeridos @@ -592,25 +751,42 @@ La relación `subjectOf` apunta al documento de nivel superior (no al fragmento) 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) +<<<<<<< HEAD **2. Actualizar la trazabilidad de los triples** +======= +**2. Actualizar la trazabilidad de triples** +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD **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 +======= +**3. Actualizar la trazabilidad de 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 +>>>>>>> 82edf2d (New md files from RunPod) #### Resumen de Cambios en la Interfaz | Interfaz | Cambio | |-----------|--------| +<<<<<<< HEAD | 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 | +======= +| Mensaje de entrada | Esperar 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 | +>>>>>>> 82edf2d (New md files from RunPod) ## Referencias diff --git a/docs/tech-specs/extraction-time-provenance.he.md b/docs/tech-specs/extraction-time-provenance.he.md index 16937d51..1bde4e33 100644 --- a/docs/tech-specs/extraction-time-provenance.he.md +++ b/docs/tech-specs/extraction-time-provenance.he.md @@ -19,13 +19,21 @@ 1. **טעינת מטא-נתונים חוזרת:** מטא-נתונים של מסמכים מקובצים ונטענים שוב ושוב עם כל אצווה של משולשים המחולצים ממסמך זה. זה בזבוז ומיותר - אותם מטא-נתונים מועברים כחלק מהפלט בכל חילוץ. +<<<<<<< HEAD 2. **מקור מידע שטחי:** הקשר `subjectOf` הנוכחי מקשר רק עובדות ישירות למסמך הראשי. אין נראות לגבי שרשרת השינויים - מאיזו עמוד הגיעה העובדה, מאיזה חלק, באיזו שיטת חילוץ נעשה שימוש. +======= +2. **מקור מידע שטחי:** הקשר `subjectOf` הנוכחי מקשר רק עובדות ישירות למסמך הראשי. אין נראות לגבי שרשרת השינויים - מאיזו עמוד הגיעה העובדה, מאיזה חלק, באיזו שיטת חילוץ השתמשו. +>>>>>>> 82edf2d (New md files from RunPod) ### מצב רצוי 1. **טעינת מטא-נתונים פעם אחת:** מטא-נתונים של מסמכים צריכים להיטען פעם אחת ולהיות מחוברים לצומת המסמך הראשי, ולא לחזור על עצמם עם כל אצווה של משולשים. +<<<<<<< HEAD 2. **גרף מקור מידע עשיר:** לתפוס את שרשרת השינויים המלאה ממסמך המקור דרך כל הארטיפקטים הביניים ועד לעובדות המחולצות. לדוגמה, טרנספורמציה של מסמך PDF: +======= +2. **גרף מקור מידע עשיר:** לתפוס את שרשרת השינויים המלאה מהמסמך המקור דרך כל הארטיפקטים הביניים ועד לעובדות המחולצות. לדוגמה, טרנספורמציה של מסמך PDF: +>>>>>>> 82edf2d (New md files from RunPod) ``` PDF file (source document with metadata) @@ -50,7 +58,11 @@ ## תרחישי שימוש +<<<<<<< HEAD ### UC1: הקצאת מקור בתגובות GraphRAG +======= +### תרחיש שימוש 1: הקצאת מקור בתגובות GraphRAG +>>>>>>> 82edf2d (New md files from RunPod) **תרחיש:** משתמש מריץ שאילתה של GraphRAG ומקבל תגובה מהסוכן. @@ -69,6 +81,7 @@ **ערך:** משתמשים יכולים לאמת תגובות שנוצרו על ידי AI מול מקורות ראשוניים, ובכך לבנות אמון ולאפשר בדיקת עובדות. +<<<<<<< HEAD ### UC2: ניפוי באגים של איכות חילוץ עובדה נראית שגויה. ניתן לעקוב אחורה דרך מקטע → עמוד → מסמך כדי לראות את הטקסט המקורי. האם זו הייתה שגיאת חילוץ, או שהמקור עצמו היה שגוי? @@ -90,6 +103,29 @@ למקורות מסוימים יש סמכות רבה יותר מאחרים. ניתן לשקלל או לסנן עובדות בהתאם לסמכות/איכות מסמכי המקור שלהן. ### UC7: השוואת צינורות חילוץ +======= +### תרחיש שימוש 2: ניפוי באגים של איכות חילוץ + +עובדה נראית שגויה. ניתן לחזור אחורה דרך מקטע → עמוד → מסמך כדי לראות את הטקסט המקורי. האם זו הייתה שגיאת חילוץ, או שהמקור עצמו שגוי? + +### תרחיש שימוש 3: חילוץ חוזר מצטבר + +מסמך מקור מתעדכן. אילו מקטעים/עובדות נגזרו ממנו? לבטל ולחדש רק את אלה, ולא לעבד הכל מחדש. + +### תרחיש שימוש 4: מחיקת נתונים / הזכות להימחק + +יש להסיר מסמך מקור (GDPR, סיבות משפטיות וכו'). יש לעבור ב-DAG כדי למצוא ולהסיר את כל העובדות הנגזרות. + +### תרחיש שימוש 5: פתרון קונפליקטים + +שתי עובדות סותרות אחת את השנייה. ניתן לחזור לשתי העובדות למקורות שלהן כדי להבין מדוע ולהחליט איזו מהן לתת לה עדיפות (מקור סמכותי יותר, עדכני יותר וכו'). + +### תרחיש שימוש 6: שקלול סמכות מקור + +למקורות מסוימים יש סמכות רבה יותר מאחרים. ניתן לשקלל או לסנן עובדות בהתאם לסמכות/איכות מסמכי המקור שלהן. + +### תרחיש שימוש 7: השוואת צינורות חילוץ +>>>>>>> 82edf2d (New md files from RunPod) השוואת תוצאות משיטות/גרסאות חילוץ שונות. איזה מחלץ הפיק עובדות טובות יותר מאותו מקור? @@ -257,10 +293,17 @@ Text: Document → Chunks → Triples/Embeddings | פרידיקט | משמעות | דוגמה | |-----------|---------|---------| +<<<<<<< HEAD | `prov:wasDerivedFrom` | ישות שמקורה בישות אחרת | עמוד היה-מבוסס-על מסמך | | `prov:wasGeneratedBy` | ישות שנוצרה על ידי פעילות | עמוד נוצר-על-ידי פעולת חילוץ PDF | | `prov:used` | פעילות השתמשה בישות כקלט | פעולת חילוץ PDF השתמשה במסמך | | `prov:wasAssociatedWith` | פעילות בוצעה על ידי סוכן | פעולת חילוץ PDF הייתה-קשורה ל-tg:PDFExtractor | +======= +| `prov:wasDerivedFrom` | ישות שמקורה בישות אחרת | עמוד wasDerivedFrom מסמך | +| `prov:wasGeneratedBy` | ישות שנוצרה על ידי פעילות | עמוד wasGeneratedBy PDFExtractionActivity | +| `prov:used` | פעילות השתמשה בישות כקלט | PDFExtractionActivity used Document | +| `prov:wasAssociatedWith` | פעילות בוצעה על ידי סוכן | PDFExtractionActivity wasAssociatedWith tg:PDFExtractor | +>>>>>>> 82edf2d (New md files from RunPod) #### מטא-נתונים בכל רמה @@ -275,7 +318,11 @@ doc:123 tg:pageCount 42 . doc:123 tg:mimeType "application/pdf" . ``` +<<<<<<< HEAD **עמוד (נפלט על ידי מופשט PDF):** +======= +**עמוד (נפלט על ידי מחלץ PDF):** +>>>>>>> 82edf2d (New md files from RunPod) ``` page:123-1 a prov:Entity . page:123-1 prov:wasDerivedFrom doc:123 . @@ -348,22 +395,39 @@ activity:extract-999 tg:ontology . | `tg:pageCount` | מסמך | מספר כולל של עמודים במסמך המקור | | `tg:mimeType` | מסמך | סוג MIME של המסמך המקור | | `tg:pageNumber` | עמוד | מספר עמוד במסמך המקור | +<<<<<<< HEAD | `tg:chunkIndex` | קטע | אינדקס של קטע בתוך הורה | | `tg:charOffset` | קטע | התאמה אופסט בטקסט הורה | | `tg:charLength` | קטע | אורך הקטע בתווים | | `tg:chunkSize` | פעילות | גודל קטע מוגדר | | `tg:chunkOverlap` | פעילות | חפיפה מוגדרת בין קטעים | | `tg:componentVersion` | פעילות | גרסת רכיב TG | +======= +| `tg:chunkIndex` | קטע | אינדקס של קטע בתוך ההורה | +| `tg:charOffset` | קטע | התאמה אופסט בטקסט ההורה | +| `tg:charLength` | קטע | אורך הקטע בתווים | +| `tg:chunkSize` | פעילות | גודל קטע מוגדר | +| `tg:chunkOverlap` | פעילות | חפיפה מוגדרת בין קטעים | +| `tg:componentVersion` | פעילות | גרסה של רכיב TG | +>>>>>>> 82edf2d (New md files from RunPod) | `tg:llmModel` | פעילות | מודל LLM ששימש לחילוץ | | `tg:ontology` | פעילות | אונטולוגיה ששימשה להכוונת החילוץ | | `tg:embeddingModel` | פעילות | מודל ששימש להטמעות | | `tg:sourceText` | הצהרה | הטקסט המדויק ממנו חולצה משולשת | +<<<<<<< HEAD | `tg:sourceCharOffset` | הצהרה | התאמה אופסט בתוך קטע שבו מתחיל הטקסט המקור | +======= +| `tg:sourceCharOffset` | הצהרה | התאמה אופסט בתוך הקטע שבו מתחיל הטקסט המקור | +>>>>>>> 82edf2d (New md files from RunPod) | `tg:sourceCharLength` | הצהרה | אורך הטקסט המקור בתווים | #### אתחול אוצר מילים (לכל אוסף) +<<<<<<< HEAD גרף הידע הוא ניטרלי אוטולוגי ומתחיל ריק. בעת כתיבת נתוני provenance של PROV-O לאוסף בפעם הראשונה, יש לאתחל את אוצר המילים עם תגיות RDF עבור כל מחלקות ופרדיקטים. זה מבטיח תצוגה קריאה על ידי בני אדם בשאילתות ובממשק המשתמש. +======= +גרף הידע הוא ניטרלי מבחינת אונטולוגיה ומתחיל ריק. בעת כתיבת נתוני provenance של PROV-O לאוסף בפעם הראשונה, יש לאתחל את אוצר המילים עם תגיות RDF עבור כל מחלקות ופרדיקטים. זה מבטיח תצוגה קריאה על ידי בני אדם בשאילתות ובממשק המשתמש. +>>>>>>> 82edf2d (New md files from RunPod) **מחלקות PROV-O:** ``` @@ -401,11 +465,19 @@ tg:sourceCharOffset rdfs:label "source character offset" . tg:sourceCharLength rdfs:label "source character length" . ``` +<<<<<<< HEAD **הערה בנושא יישום:** אוצר המילים הזה צריך להיות בעל תכונה של אידמפוטנטיות - בטוח להפעיל אותו מספר פעמים מבלי ליצור כפילויות. ניתן להפעיל אותו בפעם הראשונה בעיבוד מסמך באוסף, או כשלב נפרד של אתחול אוסף. #### מקור של חלקים קטנים (שאפתני) לצורך מעקב מקור מדויק יותר, יהיה שימושי לתעד בדיוק מאיפה בתוך חלק קטן נשלפה טריפלט. זה מאפשר: +======= +**הערה בנושא יישום:** אוצר המילים הזה צריך להיות בעל תכונה של "אידמפוטנטיות" - בטוח להפעיל אותו מספר פעמים מבלי ליצור כפילויות. ניתן להפעיל אותו בפעם הראשונה בעיבוד מסמך באוסף, או כשלב נפרד של אתחול אוסף. + +#### מקור (Provenance) של תת-קטע (שאיפה) + +לצורך מעקב מדויק יותר, יהיה מועיל לתעד בדיוק מאיפה בתוך קטע נשלפה טריפלט. זה מאפשר: +>>>>>>> 82edf2d (New md files from RunPod) הדגשת הטקסט המדויק ממנו נשלף הטריפלט בממשק המשתמש אימות דיוק החילוץ מול המקור @@ -434,6 +506,7 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . **שיקולי יישום:** +<<<<<<< HEAD חילוץ מבוסס מודל שפה גדול (LLM) עשוי שלא לספק באופן טבעי מיקומי תווים. ניתן לבקש מה-LLM להחזיר את המשפט/הביטוי המקורי יחד עם הטריפלים החילוצים. לחלופין, ניתן לבצע עיבוד לאחר החילוץ כדי להתאים את הישויות החילוצות בחזרה לטקסט המקור. @@ -464,6 +537,38 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . 4. **בניית גרף הדרגתית** - כל מעבד מוסיף את השכבה שלו לגרף. שרשרת מקור המידע השלמה נבנית בהדרגה. 5. **אופטימיזציה לאחר חלוקה לחלקים** - לאחר חלוקה לחלקים, הודעות נושאות גם מזהה וגם תוכן. החלקים קטנים (2-4KB), כך שכלול התוכן מונע מעברים מיותרים לספרן תוך שמירה על מקור המידע באמצעות המזהה. +======= +חילוץ מבוסס מודל שפה גדול (LLM) עשוי שלא לספק באופן טבעי מיקומי תווים +ניתן לבקש מה-LLM להחזיר את המשפט/הביטוי המקורי יחד עם הטריפלים החולצים +לחלופין, ניתן לבצע עיבוד לאחר החילוץ כדי להתאים את הישויות החולצות בחזרה לטקסט המקור +פשרה בין מורכבות החילוץ וגרנולריות המקור +ייתכן שיהיה קל יותר להשיג זאת באמצעות שיטות חילוץ מובנות מאשר חילוץ LLM חופשי + +זה מסומן כשאיפה - יש ליישם תחילה את המקור הבסיסי ברמת החלקים, כאשר מעקב אחר תת-חלקים הוא שיפור עתידי אם זה אפשרי. + +### מודל אחסון כפול + +גרף המקור נבנה בהדרגה ככל שהמסמכים עוברים דרך הצינור: + +| חנות | מה מאוחסן | מטרה | +|-------|---------------|---------| +| ספרן | תוכן מסמך + קישורים הורה-ילד | אחזור תוכן, מחיקה מדורגת | +| גרף ידע | קצוות הורה-ילד + מטא-נתונים | שאילתות מקור, הקצאת עובדות | + +שתי החנויות שומרות על מבנה גרף זהה. הספרן מחזיק בתוכן; הגרף מחזיק ביחסים ומאפשר שאילתות ניווט. + +### עקרונות עיצוב מרכזיים + +1. **מזהה מסמך כיחידת זרימה** - מעבדים מעבירים מזהים, לא תוכן. תוכן נשאב מהספרן בעת הצורך. + +2. **פליטה פעם אחת במקור** - מטא-נתונים נכתבים לגרף פעם אחת כאשר עיבוד מתחיל, ולא חוזרים על עצמם במורד הזרם. + +3. **דפוס מעבד עקבי** - כל מעבד עוקב אחר דפוס קבלה/שאילתא/יצירה/שמירה/פליטה/העברה זהה. + +4. **בניית גרף הדרגתית** - כל מעבד מוסיף את השכבה שלו לגרף. שרשרת המקור השלמה נבנית באופן מצטבר. + +5. **אופטימיזציה לאחר חלוקה לחלקים** - לאחר חלוקה לחלקים, הודעות נושאות גם מזהה וגם תוכן. החלקים קטנים (2-4KB), כך שכלול התוכן נמנע ממסעות הלוך ושוב מיותרים לספרן תוך שמירה על המקור באמצעות המזהה. +>>>>>>> 82edf2d (New md files from RunPod) ## משימות יישום @@ -471,15 +576,23 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . #### מצב נוכחי +<<<<<<< HEAD מתחיל עיבוד מסמכים על ידי שליחת מזהה מסמך למעבד הראשון. אין חיבור למאגר טריפלים - מטא-נתונים נכללים בפלט החילוץ. `add-child-document` יוצר קישורים הורה-ילד ברמה אחת. `list-children` מחזיר רק ילדים מיידיים. +======= +מתחיל עיבוד מסמכים על ידי שליחת מזהה מסמך למעבד הראשון +אין חיבור למאגר טריפלים - מטא-נתונים מקובצים עם פלטי חילוץ +`add-child-document` יוצר קישורים הורה-ילד חד-שכבתיים +`list-children` מחזיר רק ילדים מיידיים +>>>>>>> 82edf2d (New md files from RunPod) #### שינויים נדרשים **1. ממשק חדש: חיבור למאגר טריפלים** +<<<<<<< HEAD הספרן צריך לפלוט קצוות מטא-נתונים של מסמכים ישירות לגרף הידע בעת התחלת העיבוד. הוספת לקוח/מפרסם של מאגר טריפלים לשירות הספרן. בעת התחלת עיבוד: פליטת מטא-נתונים של מסמך השורש כקצוות גרף (פעם אחת). @@ -497,32 +610,71 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . |-----------|--------| | מאגר טריפלים | חיבור יוצא חד - פליטת קצוות מטא-נתונים של מסמכים | | התחלת עיבוד | פליטת מטא-נתונים לגרף לפני העברת מזהה מסמך | +======= +הספרן צריך לפלוט קצוות מטא-נתונים של מסמכים ישירות לגרף הידע בעת התחלת עיבוד. +הוסף לקוח/מפרסם של מאגר טריפלים לשירות הספרן +בעת התחלת עיבוד: פלט מטא-נתונים של מסמך שורש כקצוות גרף (פעם אחת) + +**2. אוצר מילים של סוגי מסמכים** + +תקנן ערכים של `document_type` עבור מסמכי ילד: +`source` - מסמך שהועלה במקור +`page` - עמוד שחולץ מהמקור (PDF, וכו') +`chunk` - חלק טקסט שמקורו בעמוד או במקור + +#### סיכום שינויי ממשק + +| ממשק | שינוי | +|-----------|--------| +| מאגר טריפלים | חיבור יוצא חד - פלט קצוות מטא-נתונים של מסמכים | +| התחלת עיבוד | פלט מטא-נתונים לגרף לפני העברת מזהה מסמך | +>>>>>>> 82edf2d (New md files from RunPod) ### שינויים בחולץ PDF #### מצב נוכחי +<<<<<<< HEAD מקבל תוכן מסמך (או זורם מסמכים גדולים). מחלץ טקסט מעמודי PDF. מעביר תוכן עמוד לחולץ חלקים. אין אינטראקציה עם הספרן או מאגר הטריפלים. +======= +מקבל תוכן מסמך (או זורם מסמכים גדולים) +מחלץ טקסט מעמודי PDF +מעביר תוכן עמוד לחולץ +אין אינטראקציה עם הספרן או מאגר הטריפלים +>>>>>>> 82edf2d (New md files from RunPod) #### שינויים נדרשים **1. ממשק חדש: לקוח ספרן** חולץ PDF צריך לשמור כל עמוד כמסמך ילד בספרן. +<<<<<<< HEAD הוספת לקוח ספרן לשירות חולץ PDF. עבור כל עמוד: קריאה ל-`add-child-document` עם מזהה הורה = מזהה מסמך השורש. +======= +הוסף לקוח ספרן לשירות חולץ PDF +עבור כל עמוד: התקשר ל-`add-child-document` עם parent = מזהה מסמך שורש +>>>>>>> 82edf2d (New md files from RunPod) **2. ממשק חדש: חיבור למאגר טריפלים** חולץ PDF צריך לפלוט קצוות הורה-ילד לגרף הידע. +<<<<<<< HEAD הוספת לקוח/מפרסם של מאגר טריפלים. עבור כל עמוד: פליטת קצה המקשר עמוד מסמך למסמך הורה. **3. שינוי פורמט פלט** פלט חוזה (יש לעקוב בדיוק אחר הפורמט הבא). +======= +הוסף לקוח/מפרסם של מאגר טריפלים +עבור כל עמוד: פלט קצה המקשר את מסמך העמוד למסמך הורה + +**3. שנה פורמט פלט** +פלט חוזה (יש לעקוב אחר הפורמט המדויק). +>>>>>>> 82edf2d (New md files from RunPod) במקום להעביר ישירות את תוכן העמוד, יש להעביר את מזהה המסמך של העמוד. ה-Chunker ישלוף את התוכן מה-librarian באמצעות המזהה. @@ -547,6 +699,7 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . **1. שינוי טיפול בקלט** +<<<<<<< HEAD לקבל מזהה מסמך במקום תוכן, לשלוף מה-librarian. להוסיף לקוח librarian לשירות ה-chunker לשלוף תוכן עמוד באמצעות מזהה מסמך @@ -566,6 +719,27 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . להעביר גם את מזהה מסמך החלק וגם את תוכן החלק (אופטימיזציה לאחר ה-chunker). מעבדים downstream מקבלים מזהה לצורך מעקב מקור + תוכן לעבודה איתו +======= +יש לקבל מזהה מסמך במקום תוכן, ולשלוף אותו מה-librarian. +יש להוסיף לקוח librarian לשירות ה-chunker +יש לשלוף את תוכן העמוד באמצעות מזהה המסמך + +**2. ממשק חדש: לקוח Librarian (כתיבה)** + +יש לשמור כל חלק כמסמך ילד ב-librarian. +עבור כל חלק: יש לקרוא ל-`add-child-document` עם parent = מזהה מסמך העמוד + +**3. ממשק חדש: חיבור ל-Triple store** + +יש לפלוט קשרים הורה-ילד לגרף הידע. +יש להוסיף לקוח/מפרסם triple store +עבור כל חלק: יש לפלוט קשר המקשר בין מסמך החלק למסמך העמוד + +**4. שינוי פורמט פלט** + +יש להעביר גם את מזהה מסמך החלק וגם את תוכן החלק (אופטימיזציה לאחר חלוקה). +מעבדים downstream מקבלים מזהה לצורך מעקב מקור + תוכן לעבודה +>>>>>>> 82edf2d (New md files from RunPod) #### סיכום שינויים בממשק @@ -574,13 +748,21 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . | הודעת קלט | שינוי מתוכן למזהה מסמך | | Librarian | יציאה חדשה (קריאה + כתיבה) - שליפת תוכן, שמירת מסמכים ילדים | | Triple store | יציאה חדשה - פליטת קשרים הורה-ילד | +<<<<<<< HEAD | הודעת פלט | שינוי מתוכן בלבד ל-ID + תוכן | +======= +| הודעת פלט | שינוי מתוכן בלבד ל-מזהה + תוכן | +>>>>>>> 82edf2d (New md files from RunPod) ### שינויים ב-Knowledge Extractor #### מצב נוכחי +<<<<<<< HEAD מקבל תוכן חלק +======= +מקבל תוכן של חלק +>>>>>>> 82edf2d (New md files from RunPod) מחלץ טריפל ו-embeddings פולט ל-triple store ול-embedding store `subjectOf` הקשר מצביע למסמך ברמה העליונה (ולא לחלק) @@ -589,6 +771,7 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . **1. שינוי טיפול בקלט** +<<<<<<< HEAD לקבל מזהה מסמך חלק יחד עם התוכן. להשתמש במזהה החלק לצורך קישור מעקב מקור (תוכן כלול כבר בהתאם לאופטימיזציה) @@ -597,20 +780,40 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . לקשר טריפל מחולץ לחלק (ולא למסמך ברמה העליונה). להשתמש ב-reification ליצירת קשר המצביע לקשר `subjectOf` הקשר: טריפל → מזהה מסמך חלק +======= +יש לקבל מזהה מסמך של חלק יחד עם התוכן. +יש להשתמש במזהה החלק לצורך קישור מעקב מקור (תוכן כלול כבר בהתאם לאופטימיזציה) + +**2. עדכון מעקב טריפל** + +יש לקשר טריפל מחולץ לחלק (ולא למסמך ברמה העליונה). +יש להשתמש ב-reification ליצירת קשר המצביע לקשר +`subjectOf` קשר: טריפל → מזהה מסמך של חלק +>>>>>>> 82edf2d (New md files from RunPod) שימוש ראשון בתמיכה קיימת ב-reification **3. עדכון מעקב embedding** +<<<<<<< HEAD לקשר מזהי ישויות embedding לחלק. לפלוט קשר: מזהה ישות embedding → מזהה מסמך חלק +======= +יש לקשר מזהי ישויות embedding לחלק. +יש לפלוט קשר: מזהה ישות embedding → מזהה מסמך של חלק +>>>>>>> 82edf2d (New md files from RunPod) #### סיכום שינויים בממשק | ממשק | שינוי | |-----------|--------| | הודעת קלט | מצפים למזהה חלק + תוכן (ולא רק תוכן) | +<<<<<<< HEAD | Triple store | להשתמש ב-reification למעקב טריפל → חלק | | מעקב embedding | לקשר מזהה ישות → מזהה חלק | +======= +| Triple store | שימוש ב-reification למעקב טריפל → חלק | +| מעקב embedding | קישור מזהה ישות → מזהה חלק | +>>>>>>> 82edf2d (New md files from RunPod) ## הפניות diff --git a/docs/tech-specs/extraction-time-provenance.hi.md b/docs/tech-specs/extraction-time-provenance.hi.md index 7b1ddbe9..356ab128 100644 --- a/docs/tech-specs/extraction-time-provenance.hi.md +++ b/docs/tech-specs/extraction-time-provenance.hi.md @@ -17,15 +17,25 @@ ### वर्तमान दृष्टिकोण की समस्याएं +<<<<<<< HEAD 1. **दोहरा मेटाडेटा लोडिंग:** दस्तावेज़ मेटाडेटा को प्रत्येक दस्तावेज़ से निकाले गए ट्रिपल बैच के साथ बार-बार बंडल किया जाता है और लोड किया जाता है। यह अनावश्यक और दोहराव वाला है - समान मेटाडेटा प्रत्येक निष्कर्षण आउटपुट के साथ पेलोड के रूप में यात्रा करता है। 2. **उथला प्रमाण:** वर्तमान `subjectOf` संबंध केवल तथ्यों को सीधे शीर्ष-स्तरीय दस्तावेज़ से जोड़ता है। परिवर्तन श्रृंखला में कोई दृश्यता नहीं है - तथ्य किस पृष्ठ से आया, किस भाग से, किस निष्कर्षण विधि का उपयोग किया गया था। +======= +1. **दोहरा मेटाडेटा लोडिंग:** दस्तावेज़ मेटाडेटा को प्रत्येक दस्तावेज़ से निकाले गए ट्रिपल के प्रत्येक बैच के साथ बार-बार बंडल किया जाता है और लोड किया जाता है। यह अनावश्यक और दोहराव वाला है - समान मेटाडेटा प्रत्येक निष्कर्षण आउटपुट के साथ पेलोड के रूप में यात्रा करता है। + +2. **उथला प्रमाण:** वर्तमान `subjectOf` संबंध केवल तथ्यों को सीधे शीर्ष-स्तरीय दस्तावेज़ से जोड़ता है। परिवर्तन श्रृंखला में कोई दृश्यता नहीं है - तथ्य किस पृष्ठ से आया, किस खंड से, किस निष्कर्षण विधि का उपयोग किया गया था। +>>>>>>> 82edf2d (New md files from RunPod) ### वांछित स्थिति 1. **मेटाडेटा को एक बार लोड करें:** दस्तावेज़ मेटाडेटा को एक बार लोड किया जाना चाहिए और शीर्ष-स्तरीय दस्तावेज़ नोड से जोड़ा जाना चाहिए, न कि प्रत्येक ट्रिपल बैच के साथ दोहराया जाना चाहिए। +<<<<<<< HEAD 2. **समृद्ध प्रमाण DAG:** स्रोत दस्तावेज़ से सभी मध्यवर्ती कलाकृतियों से लेकर निकाले गए तथ्यों तक, संपूर्ण परिवर्तन श्रृंखला को कैप्चर करें। उदाहरण के लिए, एक PDF दस्तावेज़ रूपांतरण: +======= +2. **समृद्ध प्रमाण DAG:** स्रोत दस्तावेज़ से सभी मध्यवर्ती कलाकृतियों से लेकर निकाले गए तथ्यों तक, पूर्ण परिवर्तन श्रृंखला को कैप्चर करें। उदाहरण के लिए, एक PDF दस्तावेज़ रूपांतरण: +>>>>>>> 82edf2d (New md files from RunPod) ``` PDF file (source document with metadata) @@ -40,11 +50,19 @@ → ... ``` +<<<<<<< HEAD 3. **एकीकृत भंडारण:** उत्पत्ति (provenance) DAG को उसी ज्ञान ग्राफ में संग्रहीत किया जाता है जैसे कि निकाले गए ज्ञान को। यह उत्पत्ति को ज्ञान की तरह ही क्वेरी करने की अनुमति देता है - किसी भी तथ्य से लेकर उसके सटीक स्रोत स्थान तक, श्रृंखला में किनारों का पालन करके। 4. **स्थिर आईडी:** प्रत्येक मध्यवर्ती कलाकृति (पेज, चंक) का ग्राफ में एक नोड के रूप में एक स्थिर आईडी होता है। 5. **पैरेंट-चाइल्ड लिंकिंग:** व्युत्पन्न दस्तावेज़ों को सुसंगत संबंध प्रकारों का उपयोग करके शीर्ष-स्तरीय स्रोत दस्तावेज़ तक उनके माता-पिता से जोड़ा जाता है। +======= +3. **एकीकृत भंडारण:** उत्पत्ति (provenance) DAG को उसी ज्ञान ग्राफ में संग्रहीत किया जाता है जैसे कि निकाले गए ज्ञान को। यह उत्पत्ति को ज्ञान की तरह ही क्वेरी करने की अनुमति देता है - किसी भी तथ्य से लेकर उसके सटीक स्रोत स्थान तक, श्रृंखला में वापस किनारों का पालन करना। + +4. **स्थिर आईडी:** प्रत्येक मध्यवर्ती कलाकृति (पेज, चंक) का ग्राफ में एक नोड के रूप में एक स्थिर आईडी होता है। + +5. **माता-पिता-बच्चे संबंध:** व्युत्पन्न दस्तावेज़ों को सुसंगत संबंध प्रकारों का उपयोग करके शीर्ष-स्तरीय स्रोत दस्तावेज़ तक उनके माता-पिता से जोड़ा जाता है। +>>>>>>> 82edf2d (New md files from RunPod) 6. **सटीक तथ्यattribution:** निकाले गए किनारों पर `subjectOf` संबंध तत्काल माता-पिता (चंक) की ओर इशारा करता है, न कि शीर्ष-स्तरीय दस्तावेज़ की ओर। पूर्ण उत्पत्ति को DAG के माध्यम से ऊपर की ओर ट्रैवर्स करके पुनर्प्राप्त किया जाता है। @@ -52,6 +70,7 @@ ### UC1: GraphRAG प्रतिक्रियाओं में स्रोत attribution +<<<<<<< HEAD **परिदृश्य:** एक उपयोगकर्ता GraphRAG क्वेरी चलाता है और एजेंट से एक प्रतिक्रिया प्राप्त करता है। **प्रवाह:** @@ -66,6 +85,22 @@ तथ्यों → चंक → पृष्ठ → दस्तावेज़ से ड्रिल डाउन कर सकते हैं दावों को सत्यापित करने के लिए मूल स्रोत दस्तावेज़ों की समीक्षा कर सकते हैं यह समझ सकते हैं कि एक तथ्य दस्तावेज़ में कहाँ से (किस पृष्ठ, किस अनुभाग से) उत्पन्न हुआ था +======= +**परिदृश्य:** एक उपयोगकर्ता GraphRAG क्वेरी चलाता है और एजेंट से प्रतिक्रिया प्राप्त करता है। + +**प्रक्रिया:** +1. उपयोगकर्ता GraphRAG एजेंट को एक क्वेरी सबमिट करता है। +2. एजेंट प्रतिक्रिया तैयार करने के लिए ज्ञान ग्राफ से प्रासंगिक तथ्यों को पुनः प्राप्त करता है। +3. क्वेरी-समय provenance विनिर्देश के अनुसार, एजेंट उन तथ्यों की रिपोर्ट करता है जिन्होंने प्रतिक्रिया में योगदान दिया। +4. प्रत्येक तथ्य अपने स्रोत चंक से provenance DAG के माध्यम से जुड़ा होता है। +5. चंक पृष्ठों से जुड़े होते हैं, पृष्ठ स्रोत दस्तावेज़ों से जुड़े होते हैं। + +**उपयोगकर्ता अनुभव परिणाम:** इंटरफ़ेस LLM प्रतिक्रिया के साथ स्रोत attribution प्रदर्शित करता है। उपयोगकर्ता निम्न कार्य कर सकते हैं: +प्रतिक्रिया का समर्थन करने वाले तथ्यों को देखें। +तथ्यों → चंक → पृष्ठ → दस्तावेज़ से नीचे ड्रिल करें। +दावों को सत्यापित करने के लिए मूल स्रोत दस्तावेज़ों की समीक्षा करें। +समझें कि एक तथ्य दस्तावेज़ में (किस पृष्ठ पर, किस अनुभाग में) से उत्पन्न हुआ था। +>>>>>>> 82edf2d (New md files from RunPod) **मूल्य:** उपयोगकर्ता AI-जनित प्रतिक्रियाओं को प्राथमिक स्रोतों के विरुद्ध सत्यापित कर सकते हैं, जिससे विश्वास बढ़ता है और तथ्य-जांच सक्षम होती है। @@ -75,7 +110,11 @@ ### UC3: वृद्धिशील पुन: निष्कर्षण +<<<<<<< HEAD स्रोत दस्तावेज़ अपडेट किया गया है। किन चंक/तथ्यों को इससे व्युत्पन्न किया गया था? केवल उन चंक/तथ्यों को अमान्य करें और पुन: उत्पन्न करें, न कि सब कुछ को पुन: संसाधित करें। +======= +स्रोत दस्तावेज़ अपडेट किया गया है। किन चंक/तथ्यों को इससे व्युत्पन्न किया गया था? केवल उन चंक को अमान्य करें और पुन: उत्पन्न करें, न कि सब कुछ को फिर से संसाधित करें। +>>>>>>> 82edf2d (New md files from RunPod) ### UC4: डेटा हटाना / भुलाए जाने का अधिकार @@ -91,7 +130,11 @@ ### UC7: निष्कर्षण पाइपलाइन तुलना +<<<<<<< HEAD विभिन्न निष्कर्षण विधियों/संस्करणों से आउटपुट की तुलना करें। किस निष्कर्षण ने समान स्रोत से बेहतर तथ्य उत्पन्न किए? +======= +विभिन्न निष्कर्षण विधियों/संस्करणों से प्राप्त परिणामों की तुलना करें। किस निष्कर्षण ने समान स्रोत से बेहतर तथ्य उत्पन्न किए? +>>>>>>> 82edf2d (New md files from RunPod) ## एकीकरण बिंदु @@ -106,7 +149,11 @@ `document_type` फ़ील्ड - मान: `"source"` (मूल) या `"extracted"` (व्युत्पन्न) `add-child-document` एपीआई - स्वचालित `document_type = "extracted"` के साथ चाइल्ड दस्तावेज़ बनाता है `list-children` एपीआई - एक पैरेंट दस्तावेज़ के सभी चाइल्ड को पुनः प्राप्त करता है +<<<<<<< HEAD कैस्केड डिलीशन - एक पैरेंट को हटाने से स्वचालित रूप से सभी चाइल्ड दस्तावेज़ हटा दिए जाते हैं +======= +कैस्केड डिलीशन - एक पैरेंट को हटाने से स्वचालित रूप से सभी चाइल्ड दस्तावेज़ हट जाते हैं +>>>>>>> 82edf2d (New md files from RunPod) **दस्तावेज़ पहचान:** दस्तावेज़ आईडी क्लाइंट द्वारा निर्दिष्ट हैं (स्वचालित रूप से उत्पन्न नहीं) @@ -121,7 +168,11 @@ **भंडारण आर्किटेक्चर:** मेटाडेटा कैसेंड्रा में संग्रहीत है (`librarian` कीस्पेस, `document` टेबल) सामग्री MinIO/S3 ब्लब स्टोरेज में संग्रहीत है (`library` बकेट) +<<<<<<< HEAD स्मार्ट सामग्री वितरण: 2MB से कम दस्तावेज़ एम्बेडेड हैं, बड़े दस्तावेज़ स्ट्रीम किए जाते हैं +======= +स्मार्ट सामग्री वितरण: 2MB से छोटे दस्तावेज़ एम्बेडेड होते हैं, बड़े दस्तावेज़ स्ट्रीम किए जाते हैं +>>>>>>> 82edf2d (New md files from RunPod) #### मुख्य फाइलें @@ -232,7 +283,11 @@ └─────────────────────────────────────────────────────────────────────────┘ ``` +<<<<<<< HEAD परिणामी निर्देशित एसाइक्लिक ग्राफ (DAG) एक स्तर छोटा होता है: +======= +परिणामी DAG एक स्तर छोटा होता है: +>>>>>>> 82edf2d (New md files from RunPod) ``` PDF: Document → Pages → Chunks → Triples/Embeddings @@ -257,10 +312,17 @@ Text: Document → Chunks → Triples/Embeddings | विधेय | अर्थ | उदाहरण | |-----------|---------|---------| +<<<<<<< HEAD | `prov:wasDerivedFrom` | एक इकाई से व्युत्पन्न अन्य इकाई | पृष्ठ दस्तावेज़ से व्युत्पन्न था | | `prov:wasGeneratedBy` | एक गतिविधि द्वारा उत्पन्न इकाई | पृष्ठ पीडीएफ निष्कर्षण गतिविधि द्वारा उत्पन्न किया गया था | | `prov:used` | गतिविधि ने एक इकाई को इनपुट के रूप में उपयोग किया | पीडीएफ निष्कर्षण गतिविधि ने दस्तावेज़ का उपयोग किया | | `prov:wasAssociatedWith` | एक एजेंट द्वारा की गई गतिविधि | पीडीएफ निष्कर्षण गतिविधि tg:पीडीएफएक्सट्रैक्टर से जुड़ी थी | +======= +| `prov:wasDerivedFrom` | एक इकाई किसी अन्य इकाई से प्राप्त हुई | पृष्ठ दस्तावेज़ से प्राप्त हुआ | +| `prov:wasGeneratedBy` | एक इकाई एक गतिविधि द्वारा उत्पन्न हुई | पृष्ठ पीडीएफ निष्कर्षण गतिविधि द्वारा उत्पन्न हुआ | +| `prov:used` | एक गतिविधि ने एक इकाई को इनपुट के रूप में उपयोग किया | पीडीएफ निष्कर्षण गतिविधि ने दस्तावेज़ का उपयोग किया | +| `prov:wasAssociatedWith` | एक गतिविधि एक एजेंट द्वारा की गई | पीडीएफ निष्कर्षण गतिविधि tg:पीडीएफएक्सट्रैक्टर से जुड़ी थी | +>>>>>>> 82edf2d (New md files from RunPod) #### प्रत्येक स्तर पर मेटाडेटा @@ -275,7 +337,11 @@ doc:123 tg:pageCount 42 . doc:123 tg:mimeType "application/pdf" . ``` +<<<<<<< HEAD **पृष्ठ (पीडीएफ एक्सट्रैक्टर द्वारा उत्सर्जित):** +======= +**पृष्ठ (पीडीएफ एक्सट्रैक्टर द्वारा उत्पन्न):** +>>>>>>> 82edf2d (New md files from RunPod) ``` page:123-1 a prov:Entity . page:123-1 prov:wasDerivedFrom doc:123 . @@ -340,7 +406,11 @@ activity:extract-999 tg:ontology . #### ट्रस्टग्राफ नेमस्पेस एक्सटेंशन +<<<<<<< HEAD निष्कर्षण-विशिष्ट मेटाडेटा के लिए `tg:` नेमस्पेस के अंतर्गत कस्टम प्रेडिकेट: +======= +निष्कर्षण-विशिष्ट मेटाडेटा के लिए `tg:` नेमस्पेस के तहत कस्टम प्रेडिकेट: +>>>>>>> 82edf2d (New md files from RunPod) | प्रेडिकेट | डोमेन | विवरण | |-----------|--------|-------------| @@ -352,10 +422,17 @@ activity:extract-999 tg:ontology . | `tg:charOffset` | चंक | मूल पाठ में कैरेक्टर ऑफसेट | | `tg:charLength` | चंक | कैरेक्टर में चंक की लंबाई | | `tg:chunkSize` | गतिविधि | कॉन्फ़िगर किया गया चंक आकार | +<<<<<<< HEAD | `tg:chunkOverlap` | गतिविधि | चंक के बीच कॉन्फ़िगर किया गया ओवरलैप | | `tg:componentVersion` | गतिविधि | टीजी घटक का संस्करण | | `tg:llmModel` | गतिविधि | निष्कर्षण के लिए उपयोग किया गया एलएलएम (LLM) | | `tg:ontology` | गतिविधि | निष्कर्षण का मार्गदर्शन करने के लिए उपयोग किया गया ऑन्टोलॉजी यूआरआई | +======= +| `tg:chunkOverlap` | गतिविधि | चंक्स के बीच कॉन्फ़िगर किया गया ओवरलैप | +| `tg:componentVersion` | गतिविधि | टीजी घटक का संस्करण | +| `tg:llmModel` | गतिविधि | निष्कर्षण के लिए उपयोग किया गया एलएलएम (LLM) | +| `tg:ontology` | गतिविधि | निष्कर्षण को निर्देशित करने के लिए उपयोग किया गया ऑन्टोलॉजी यूआरआई | +>>>>>>> 82edf2d (New md files from RunPod) | `tg:embeddingModel` | गतिविधि | एम्बेडिंग के लिए उपयोग किया गया मॉडल | | `tg:sourceText` | स्टेटमेंट | ट्रिपल से निकाले गए सटीक पाठ | | `tg:sourceCharOffset` | स्टेटमेंट | चंक के भीतर स्रोत पाठ की शुरुआत का कैरेक्टर ऑफसेट | @@ -401,11 +478,19 @@ tg:sourceCharOffset rdfs:label "source character offset" . tg:sourceCharLength rdfs:label "source character length" . ``` +<<<<<<< HEAD **कार्यान्वयन नोट:** यह शब्दावली बूटस्ट्रैप आइडेंम्पोटेंट होना चाहिए - बिना डुप्लिकेट बनाए कई बार चलाने के लिए सुरक्षित। इसे किसी संग्रह में पहली बार दस्तावेज़ प्रसंस्करण के दौरान या एक अलग संग्रह आरंभीकरण चरण के रूप में ट्रिगर किया जा सकता है। #### उप-खंड उत्पत्ति (आदर्श) अधिक बारीक उत्पत्ति के लिए, यह महत्वपूर्ण होगा कि एक त्रिक को एक खंड के भीतर से ठीक कहाँ से निकाला गया था, इसका रिकॉर्ड रखा जाए। यह निम्नलिखित को सक्षम करता है: +======= +**कार्यान्वयन नोट:** यह शब्दावली बूटस्ट्रैप आइडेंम्पोटेंट होना चाहिए - डुप्लिकेट बनाए बिना कई बार चलाने के लिए सुरक्षित। इसे किसी संग्रह में पहली बार दस्तावेज़ प्रसंस्करण के दौरान या एक अलग संग्रह आरंभीकरण चरण के रूप में ट्रिगर किया जा सकता है। + +#### उप-खंड उत्पत्ति (आकांक्षी) + +अधिक बारीक उत्पत्ति के लिए, यह महत्वपूर्ण होगा कि एक त्रिक को एक खंड के भीतर से कहाँ से निकाला गया था, यह सटीक रूप से रिकॉर्ड किया जाए। यह निम्नलिखित को सक्षम करता है: +>>>>>>> 82edf2d (New md files from RunPod) यूआई में सटीक स्रोत पाठ को हाइलाइट करना स्रोत के विरुद्ध निष्कर्षण सटीकता को सत्यापित करना @@ -444,11 +529,16 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . ### दोहरी भंडारण मॉडल +<<<<<<< HEAD उत्पत्ति डीएजी (DAG) को क्रमिक रूप से बनाया जाता है क्योंकि दस्तावेज़ पाइपलाइन के माध्यम से प्रवाहित होते हैं: +======= +उत्पत्ति DAG (डायरेक्टेड एसाइक्लिक ग्राफ) को क्रमिक रूप से बनाया जाता है क्योंकि दस्तावेज़ पाइपलाइन के माध्यम से प्रवाहित होते हैं: +>>>>>>> 82edf2d (New md files from RunPod) | स्टोर | क्या संग्रहीत है | उद्देश्य | |-------|---------------|---------| | लाइब्रेरियन | दस्तावेज़ सामग्री + माता-पिता-बच्चे लिंक | सामग्री पुनर्प्राप्ति, कैस्केड विलोपन | +<<<<<<< HEAD | ज्ञान ग्राफ | माता-पिता-बच्चे किनारे + मेटाडेटा | उत्पत्ति प्रश्न, तथ्य का श्रेय | दोनों स्टोर समान डीएजी संरचना बनाए रखते हैं। लाइब्रेरियन सामग्री रखता है; ग्राफ संबंधों को रखता है और ट्रैवर्सल प्रश्नों को सक्षम करता है। @@ -456,14 +546,29 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . ### प्रमुख डिज़ाइन सिद्धांत 1. **दस्तावेज़ आईडी प्रवाह की इकाई के रूप में** - प्रोसेसर आईडी, सामग्री नहीं, पास करते हैं। जब आवश्यक हो तो सामग्री लाइब्रेरियन से प्राप्त की जाती है। +======= +| नॉलेज ग्राफ | माता-पिता-बच्चे किनारे + मेटाडेटा | उत्पत्ति प्रश्न, तथ्य का श्रेय | + +दोनों स्टोर समान DAG संरचना बनाए रखते हैं। लाइब्रेरियन सामग्री रखता है; ग्राफ संबंधों को रखता है और ट्रैवर्सल प्रश्नों को सक्षम बनाता है। + +### प्रमुख डिज़ाइन सिद्धांत + +1. **दस्तावेज़ आईडी प्रवाह की इकाई के रूप में** - प्रोसेसर आईडी, सामग्री नहीं, पास करते हैं। जब आवश्यक हो तो सामग्री को लाइब्रेरियन से प्राप्त किया जाता है। +>>>>>>> 82edf2d (New md files from RunPod) 2. **स्रोत पर एक बार उत्सर्जित करें** - प्रसंस्करण शुरू होने पर मेटाडेटा को ग्राफ में एक बार लिखा जाता है, न कि बाद में दोहराया जाता है। 3. **संगत प्रोसेसर पैटर्न** - प्रत्येक प्रोसेसर एक ही प्राप्त/प्राप्त/उत्पादित/सहेजें/उत्सर्जित/फॉरवर्ड पैटर्न का पालन करता है। +<<<<<<< HEAD 4. **प्रगतिशील डीएजी निर्माण** - प्रत्येक प्रोसेसर अपने स्तर को डीएजी में जोड़ता है। पूर्ण उत्पत्ति श्रृंखला क्रमिक रूप से बनाई जाती है। 5. **चंक-प्रोसेसर के बाद अनुकूलन** - चंकिंग के बाद, संदेशों में आईडी और सामग्री दोनों होते हैं। चंक छोटे होते हैं (2-4KB), इसलिए सामग्री को शामिल करने से अनावश्यक लाइब्रेरियन राउंड-ट्रिप से बचा जा सकता है, जबकि आईडी के माध्यम से उत्पत्ति को संरक्षित किया जा सकता है। +======= +4. **प्रगतिशील DAG निर्माण** - प्रत्येक प्रोसेसर अपने स्तर को DAG में जोड़ता है। पूर्ण उत्पत्ति श्रृंखला क्रमिक रूप से बनाई जाती है। + +5. **चंक-प्रोसेसर के बाद अनुकूलन** - चंकिंग के बाद, संदेशों में आईडी और सामग्री दोनों होते हैं। चंक छोटे होते हैं (2-4KB), इसलिए सामग्री को शामिल करने से अनावश्यक लाइब्रेरियन राउंड-ट्रिप से बचा जाता है, जबकि आईडी के माध्यम से उत्पत्ति को संरक्षित किया जाता है। +>>>>>>> 82edf2d (New md files from RunPod) ## कार्यान्वयन कार्य @@ -480,7 +585,11 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . **1. नया इंटरफ़ेस: ट्रिपल स्टोर कनेक्शन** +<<<<<<< HEAD लाइब्रेरियन को प्रसंस्करण शुरू करते समय दस्तावेज़ मेटाडेटा किनारों को सीधे ज्ञान ग्राफ में उत्सर्जित करने की आवश्यकता है। +======= +लाइब्रेरियन को प्रसंस्करण शुरू करते समय दस्तावेज़ मेटाडेटा किनारों को सीधे नॉलेज ग्राफ में उत्सर्जित करने की आवश्यकता है। +>>>>>>> 82edf2d (New md files from RunPod) लाइब्रेरियन सेवा में ट्रिपल स्टोर क्लाइंट/प्रकाशक जोड़ें। प्रसंस्करण शुरू होने पर: रूट दस्तावेज़ मेटाडेटा को ग्राफ किनारों के रूप में उत्सर्जित करें (एक बार)। @@ -488,7 +597,11 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . चाइल्ड दस्तावेज़ों के लिए `document_type` मानों का मानकीकरण करें: `source` - मूल अपलोड किया गया दस्तावेज़। +<<<<<<< HEAD `page` - स्रोत से निकाला गया पृष्ठ (पीडीएफ, आदि)। +======= +`page` - स्रोत (पीडीएफ, आदि) से निकाला गया पृष्ठ। +>>>>>>> 82edf2d (New md files from RunPod) `chunk` - पृष्ठ या स्रोत से प्राप्त पाठ चंक। #### इंटरफ़ेस परिवर्तन सारांश @@ -511,20 +624,32 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . **1. नया इंटरफ़ेस: लाइब्रेरियन क्लाइंट** +<<<<<<< HEAD पीडीएफ एक्सट्रैक्टर को प्रत्येक पृष्ठ को लाइब्रेरियन में एक चाइल्ड दस्तावेज़ के रूप में सहेजना होगा। +======= +पीडीएफ एक्सट्रैक्टर को प्रत्येक पृष्ठ को लाइब्रेरियन में एक चाइल्ड दस्तावेज़ के रूप में सहेजने की आवश्यकता है। +>>>>>>> 82edf2d (New md files from RunPod) पीडीएफ एक्सट्रैक्टर सेवा में लाइब्रेरियन क्लाइंट जोड़ें। प्रत्येक पृष्ठ के लिए: `add-child-document` को रूट दस्तावेज़ आईडी के साथ कॉल करें। **2. नया इंटरफ़ेस: ट्रिपल स्टोर कनेक्शन** +<<<<<<< HEAD पीडीएफ एक्सट्रैक्टर को ज्ञान ग्राफ में माता-पिता-बच्चे किनारे उत्सर्जित करने की आवश्यकता है। +======= +पीडीएफ एक्सट्रैक्टर को नॉलेज ग्राफ में माता-पिता-बच्चे किनारों को उत्सर्जित करने की आवश्यकता है। +>>>>>>> 82edf2d (New md files from RunPod) ट्रिपल स्टोर क्लाइंट/प्रकाशक जोड़ें। प्रत्येक पृष्ठ के लिए: पृष्ठ दस्तावेज़ को माता-पिता दस्तावेज़ से जोड़ने वाले किनारे को उत्सर्जित करें। **3. आउटपुट प्रारूप बदलें** सीधे पृष्ठ सामग्री अग्रेषित करने के बजाय, पृष्ठ दस्तावेज़ आईडी अग्रेषित करें। +<<<<<<< HEAD चंकर लाइब्रेरियन का उपयोग करके आईडी के साथ सामग्री प्राप्त करेगा +======= +चंकर लाइब्रेरियन का उपयोग करके आईडी के साथ सामग्री प्राप्त करेगा। +>>>>>>> 82edf2d (New md files from RunPod) #### इंटरफ़ेस परिवर्तनों का सारांश @@ -589,7 +714,11 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . **1. इनपुट हैंडलिंग बदलें** +<<<<<<< HEAD टुकड़े दस्तावेज़ आईडी के साथ-साथ सामग्री प्राप्त करें। +======= +सामग्री के साथ-साथ टुकड़े दस्तावेज़ आईडी प्राप्त करें। +>>>>>>> 82edf2d (New md files from RunPod) उत्पत्ति लिंकिंग के लिए टुकड़े आईडी का उपयोग करें (सामग्री पहले से ही अनुकूलन के अनुसार शामिल है) **2. ट्रिपल उत्पत्ति को अपडेट करें** @@ -601,16 +730,27 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . **3. एम्बेडिंग उत्पत्ति को अपडेट करें** +<<<<<<< HEAD एम्बेडिंग इकाई आईडी को टुकड़े से लिंक करें। किनारा उत्सर्जित करें: एम्बेडिंग इकाई आईडी → टुकड़े दस्तावेज़ आईडी +======= +एम्बेडिंग एंटिटी आईडी को टुकड़े से लिंक करें। +किनारा उत्सर्जित करें: एम्बेडिंग एंटिटी आईडी → टुकड़े दस्तावेज़ आईडी +>>>>>>> 82edf2d (New md files from RunPod) #### इंटरफ़ेस परिवर्तनों का सारांश | इंटरफ़ेस | परिवर्तन | |-----------|--------| +<<<<<<< HEAD | इनपुट संदेश | टुकड़े आईडी + सामग्री की अपेक्षा करें (केवल सामग्री नहीं) | | ट्रिपल स्टोर | ट्रिपल → टुकड़े उत्पत्ति के लिए पुन: उपयोग का उपयोग करें | | एम्बेडिंग उत्पत्ति | इकाई आईडी → टुकड़े आईडी से लिंक करें | +======= +| इनपुट संदेश | सामग्री के साथ टुकड़े आईडी + सामग्री की अपेक्षा करें (केवल सामग्री नहीं) | +| ट्रिपल स्टोर | ट्रिपल → टुकड़े उत्पत्ति के लिए पुन: उपयोग का उपयोग करें | +| एम्बेडिंग उत्पत्ति | एंटिटी आईडी → टुकड़े आईडी से लिंक करें | +>>>>>>> 82edf2d (New md files from RunPod) ## संदर्भ diff --git a/docs/tech-specs/extraction-time-provenance.pt.md b/docs/tech-specs/extraction-time-provenance.pt.md index e5c9b10c..a37b59f8 100644 --- a/docs/tech-specs/extraction-time-provenance.pt.md +++ b/docs/tech-specs/extraction-time-provenance.pt.md @@ -17,7 +17,11 @@ Quando arestas (relacionamentos/fatos) são extraídas de documentos, um relacio ### Problemas com a Abordagem Atual +<<<<<<< HEAD 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. +======= +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 útil com cada saída de extração. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -40,13 +44,21 @@ Quando arestas (relacionamentos/fatos) são extraídas de documentos, um relacio → ... ``` +<<<<<<< HEAD 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. +======= +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 até sua localização de origem exata. +>>>>>>> 82edf2d (New md files from RunPod) 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. +<<<<<<< HEAD 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. +======= +6. **Atribuição precisa de fatos:** O relacionamento `subjectOf` nas arestas extraídas aponta para o pai imediato (trecho), e não para o documento de nível superior. A proveniência completa é recuperada percorrendo o DAG. +>>>>>>> 82edf2d (New md files from RunPod) ## Casos de Uso @@ -62,7 +74,11 @@ Quando arestas (relacionamentos/fatos) são extraídas de documentos, um relacio 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: +<<<<<<< HEAD Ver quais fatos apoiaram a resposta. +======= +Ver quais fatos suportaram a resposta. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -73,7 +89,11 @@ Entender exatamente onde em um documento (qual página, qual seção) um fato se 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? +<<<<<<< HEAD ### UC3: Reextração Incremental +======= +### UC3: Re-extração Incremental +>>>>>>> 82edf2d (New md files from RunPod) O documento de origem é atualizado. Quais trechos/fatos foram derivados dele? Invalide e regenere apenas esses, em vez de reprocessar tudo. @@ -83,7 +103,11 @@ Um documento de origem deve ser removido (GDPR, legal, etc.). Percorra o DAG par ### UC5: Resolução de Conflitos +<<<<<<< HEAD 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.). +======= +Dois fatos se contradizem. Rastreie ambos de volta às suas fontes para entender o porquê e decidir qual confiar (fonte mais autoritária, mais recente, etc.). +>>>>>>> 82edf2d (New md files from RunPod) ### UC6: Ponderação da Autoridade da Fonte @@ -97,7 +121,11 @@ Compare os resultados de diferentes métodos/versões de extração. Qual extrat ### Bibliotecário +<<<<<<< HEAD O componente bibliotecário já fornece armazenamento de documentos com IDs de documento exclusivos. O sistema de rastreabilidade se integra com essa infraestrutura existente. +======= +O componente bibliotecário já fornece armazenamento de documentos com IDs de documentos exclusivos. O sistema de rastreabilidade se integra a essa infraestrutura existente. +>>>>>>> 82edf2d (New md files from RunPod) #### Capacidades Existentes (já implementadas) @@ -109,9 +137,15 @@ 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:** +<<<<<<< HEAD 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 +======= +Os IDs dos documentos são especificados pelo cliente (não gerados automaticamente) +Documentos indexados por `(user, document_id)` composto no Cassandra +IDs de objetos (UUIDs) gerados internamente para armazenamento de blobs +>>>>>>> 82edf2d (New md files from RunPod) **Suporte a Metadados:** Campo `metadata: list[Triple]` - triplas RDF para metadados estruturados @@ -126,7 +160,11 @@ Entrega inteligente de conteúdo: documentos < 2MB incorporados, documentos maio #### Arquivos Chave `trustgraph-flow/trustgraph/librarian/librarian.py` - Operações principais do bibliotecário +<<<<<<< HEAD `trustgraph-flow/trustgraph/librarian/service.py` - Processador de serviço, carregamento de documento +======= +`trustgraph-flow/trustgraph/librarian/service.py` - Processador de serviço, carregamento de documentos +>>>>>>> 82edf2d (New md files from RunPod) `trustgraph-flow/trustgraph/tables/library.py` - Armazenamento de tabela Cassandra `trustgraph-base/trustgraph/schema/services/library.py` - Definições de esquema @@ -136,7 +174,11 @@ 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 +<<<<<<< HEAD 4. Não há API de consulta para percorrer toda a cadeia de rastreabilidade de um fato até a fonte +======= +4. Não há API de consulta para percorrer toda a cadeia de rastreabilidade de um fato até a origem +>>>>>>> 82edf2d (New md files from RunPod) ## Design de Fluxo de Extremo a Extremo @@ -232,7 +274,11 @@ Documentos de texto ignoram o extrator de PDF e vão diretamente para o processa └─────────────────────────────────────────────────────────────────────────┘ ``` +<<<<<<< HEAD O grafo acíclico dirigido (DAG) resultante é um nível mais curto: +======= +O grafo acíclico direcionado (DAG) resultante é um nível mais curto: +>>>>>>> 82edf2d (New md files from RunPod) ``` PDF: Document → Pages → Chunks → Triples/Embeddings @@ -257,10 +303,17 @@ Os metadados de procedência utilizam a ontologia W3C PROV-O. Isso fornece um vo | Predicado | Significado | Exemplo | |-----------|---------|---------| +<<<<<<< HEAD | `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 | +======= +| `prov:wasDerivedFrom` | Entidade derivada de outra entidade | Página derivadaDocumento | +| `prov:wasGeneratedBy` | Entidade gerada por uma atividade | Página geradaPor AtividadeDeExtraçãoDePDF | +| `prov:used` | Atividade que usou uma entidade como entrada | AtividadeDeExtraçãoDePDF usou Documento | +| `prov:wasAssociatedWith` | Atividade realizada por um agente | AtividadeDeExtraçãoDePDF associadaA tg:ExtratorDePDF | +>>>>>>> 82edf2d (New md files from RunPod) #### Metadados em Cada Nível @@ -336,7 +389,11 @@ As incorporações são armazenadas no armazenamento vetorial com metadados, e n | modelo | Modelo de incorporação usado | `text-embedding-ada-002` | | component_version | Versão do incorporador TG | `1.0.0` | +<<<<<<< HEAD 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. +======= +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 travessia ascendente do DAG até o documento original. +>>>>>>> 82edf2d (New md files from RunPod) #### Extensões do Namespace TrustGraph @@ -381,7 +438,11 @@ prov:wasAssociatedWith rdfs:label "was associated with" . prov:startedAtTime rdfs:label "started at" . ``` +<<<<<<< HEAD **Predicados TrustGraph:** +======= +**Predicados do TrustGraph:** +>>>>>>> 82edf2d (New md files from RunPod) ``` tg:contains rdfs:label "contains" . tg:pageCount rdfs:label "page count" . @@ -401,14 +462,22 @@ tg:sourceCharOffset rdfs:label "source character offset" . tg:sourceCharLength rdfs:label "source character length" . ``` +<<<<<<< HEAD **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. +======= +**Observação sobre a implementação:** Este vocabulário de inicialização 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. +>>>>>>> 82edf2d (New md files from RunPod) #### 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 +<<<<<<< HEAD Verificar a precisão da extração em relação à fonte +======= +Verificar a precisão da extração em relação à origem +>>>>>>> 82edf2d (New md files from RunPod) Depurar a qualidade da extração no nível da frase **Exemplo com rastreamento de posição:** @@ -436,7 +505,11 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . 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. +<<<<<<< HEAD Alternativamente, pós-processe para fazer uma correspondência aproximada das entidades extraídas com o texto de origem. +======= +Alternativamente, pós-processar para fazer uma correspondência aproximada das entidades extraídas com o texto de origem. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -448,6 +521,7 @@ O grafo de procedência é construído progressivamente à medida que os documen | Armazenamento | O que é armazenado | Propósito | |-------|---------------|---------| +<<<<<<< HEAD | 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 | @@ -456,6 +530,16 @@ Ambos os armazenamentos mantêm a mesma estrutura de grafo. O bibliotecário arm ### 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. +======= +| Librarian | Conteúdo do documento + links pai-filho | Recuperação de conteúdo, exclusão em cascata | +| Knowledge Graph | Arestas pai-filho + metadados | Consultas de procedência, atribuição de fatos | + +Ambos os armazenamentos mantêm a mesma estrutura de grafo. O librarian 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 librarian quando necessário. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -463,21 +547,34 @@ Ambos os armazenamentos mantêm a mesma estrutura de grafo. O bibliotecário arm 4. **Construção progressiva do grafo** - Cada processador adiciona seu nível ao grafo. A cadeia completa de procedência é construída incrementalmente. +<<<<<<< HEAD 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 +======= +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 librarian, preservando a procedência por meio do ID. + +## Tarefas de Implementação + +### Alterações no Librarian +>>>>>>> 82edf2d (New md files from RunPod) #### Estado Atual Inicia o processamento do documento enviando o ID do documento para o primeiro processador. +<<<<<<< HEAD Não possui conexão com o armazenamento de triplas - os metadados são agrupados com as saídas de extração. +======= +Não possui conexão com o triple store - os metadados são agrupados com as saídas de extração. +>>>>>>> 82edf2d (New md files from RunPod) `add-child-document` cria links pai-filho de um nível. `list-children` retorna apenas os filhos imediatos. #### Alterações Necessárias +<<<<<<< HEAD **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. @@ -487,6 +584,17 @@ Na inicialização do processamento: emita os metadados do documento raiz como b **2. Vocabulário de tipo de documento** Padronize os valores de `document_type` para documentos filhos: +======= +**1. Nova interface: Conexão com o triple store** + +O librarian precisa emitir as bordas de metadados do documento diretamente para o knowledge graph ao iniciar o processamento. +Adicionar cliente/publicador do triple store ao serviço do librarian. +Na inicialização do processamento: emitir os metadados do documento raiz como bordas do grafo (uma vez). + +**2. Vocabulário de tipo de documento** + +Padronizar os valores de `document_type` para documentos filhos: +>>>>>>> 82edf2d (New md files from RunPod) `source` - documento original carregado. `page` - página extraída da fonte (PDF, etc.). `chunk` - fragmento de texto derivado da página ou da fonte. @@ -495,8 +603,13 @@ Padronize os valores de `document_type` para documentos filhos: | Interface | Alteração | |-----------|--------| +<<<<<<< HEAD | 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 | +======= +| Triple store | Nova conexão de saída - emitir bordas de metadados do documento | +| Início do processamento | Emitir metadados para o grafo antes de encaminhar o ID do documento | +>>>>>>> 82edf2d (New md files from RunPod) ### Alterações no Extrator de PDF @@ -505,6 +618,7 @@ Padronize os valores de `document_type` para documentos filhos: 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. +<<<<<<< HEAD Não interage com o bibliotecário ou o armazenamento de triplas. #### Alterações Necessárias @@ -520,6 +634,23 @@ Para cada página: chame `add-child-document` com pai = ID do documento raiz. 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. +======= +Não interage com o librarian ou o triple store. + +#### Alterações Necessárias + +**1. Nova interface: Cliente do librarian** + +O extrator de PDF precisa salvar cada página como um documento filho no librarian. +Adicionar cliente do librarian ao serviço do extrator de PDF. +Para cada página: chamar `add-child-document` com pai = ID do documento raiz. + +**2. Nova interface: Conexão com o triple store** + +O extrator de PDF precisa emitir bordas pai-filho para o knowledge graph. +Adicionar cliente/publicador do triple store. +Para cada página: emitir uma borda que vincule o documento da página ao documento pai. +>>>>>>> 82edf2d (New md files from RunPod) **3. Alterar o formato de saída** diff --git a/docs/tech-specs/extraction-time-provenance.ru.md b/docs/tech-specs/extraction-time-provenance.ru.md index cdd896ce..ed58c496 100644 --- a/docs/tech-specs/extraction-time-provenance.ru.md +++ b/docs/tech-specs/extraction-time-provenance.ru.md @@ -25,7 +25,11 @@ 1. **Загрузка метаданных один раз:** Метаданные документа должны быть загружены один раз и привязаны к узлу верхнего уровня документа, а не повторяться с каждой партией триплетов. +<<<<<<< HEAD 2. **Разветвленная структура данных о происхождении:** Захватите полную цепочку преобразований от исходного документа через все промежуточные артефакты до извлеченных фактов. Например, преобразование PDF-документа: +======= +2. **Разветвленная структура происхождения данных:** Захватите полную цепочку преобразований от исходного документа через все промежуточные артефакты до извлеченных фактов. Например, преобразование PDF-документа: +>>>>>>> 82edf2d (New md files from RunPod) ``` PDF file (source document with metadata) @@ -40,7 +44,11 @@ → ... ``` +<<<<<<< HEAD 3. **Унифицированное хранилище:** Граф происхождения хранится в той же базе знаний, что и извлеченные знания. Это позволяет запрашивать происхождение так же, как и знания, прослеживая связи обратно по цепочке от любого факта к его точному источнику. +======= +3. **Унифицированное хранилище:** Граф происхождения хранится в той же базе знаний, что и извлеченные знания. Это позволяет запрашивать происхождение так же, как и знания, прослеживая связи вверх по цепочке от любого факта к его точному источнику. +>>>>>>> 82edf2d (New md files from RunPod) 4. **Стабильные идентификаторы:** Каждый промежуточный артефакт (страница, фрагмент) имеет стабильный идентификатор в виде узла в графе. @@ -57,20 +65,32 @@ **Процесс:** 1. Пользователь отправляет запрос агенту GraphRAG. 2. Агент извлекает соответствующие факты из базы знаний для формирования ответа. +<<<<<<< HEAD 3. В соответствии со спецификацией происхождения во время запроса, агент сообщает, какие факты внесли вклад в ответ. +======= +3. В соответствии со спецификацией происхождения для запросов, агент сообщает, какие факты послужили основой для ответа. +>>>>>>> 82edf2d (New md files from RunPod) 4. Каждый факт связан с его исходным фрагментом через граф происхождения. 5. Фрагменты связаны со страницами, страницы связаны с исходными документами. **Результат для пользователя:** Интерфейс отображает ответ LLM вместе с указанием источника. Пользователь может: +<<<<<<< HEAD Увидеть, какие факты подтверждают ответ. Переходить от фактов к фрагментам, страницам и документам. Просматривать исходные документы для проверки утверждений. Понимать, откуда в документе (на какой странице, в каком разделе) произошел факт. +======= +Увидеть, какие факты послужили основой для ответа. +Переходить от фактов к фрагментам, страницам и документам. +Просматривать исходные документы для проверки утверждений. +Понимать, откуда в документе (на какой странице, в каком разделе) произошел тот или иной факт. +>>>>>>> 82edf2d (New md files from RunPod) **Преимущество:** Пользователи могут проверять ответы, сгенерированные ИИ, по сравнению с первичными источниками, что повышает доверие и позволяет проводить проверку фактов. ### UC2: Отладка качества извлечения +<<<<<<< HEAD Факт кажется неверным. Проследите обратно через фрагмент, страницу и документ, чтобы увидеть исходный текст. Это была ошибка извлечения, или исходный документ был неверным? ### UC3: Инкрементное повторное извлечение @@ -84,6 +104,21 @@ ### UC5: Разрешение конфликтов Два факта противоречат друг другу. Проследите оба обратно к их источникам, чтобы понять, почему, и решить, кому доверять (более авторитетному источнику, более свежему и т.д.). +======= +Факт кажется неверным. Проследите по цепочке от фрагмента к странице и документу, чтобы увидеть исходный текст. Была ли это ошибка извлечения, или исходный текст был неверным? + +### UC3: Инкрементное повторное извлечение + +Исходный документ был обновлен. Какие фрагменты/факты были получены из него? Отмените и перегенерируйте только эти, а не перерабатывайте все. + +### UC4: Удаление данных / Право на забвение + +Исходный документ должен быть удален (GDPR, юридические требования и т.д.). Пройдите по графу, чтобы найти и удалить все производные факты. + +### UC5: Разрешение конфликтов + +Два факта противоречат друг другу. Проследите оба факта до их источников, чтобы понять причину и решить, кому доверять (более авторитетному источнику, более свежему и т.д.). +>>>>>>> 82edf2d (New md files from RunPod) ### UC6: Взвешивание авторитетности источника @@ -103,7 +138,11 @@ **Связывание документов "родитель-потомок":** Поле `parent_id` в `DocumentMetadata` - связывает дочерний документ с родительским документом. +<<<<<<< HEAD Поле `document_type` - значения: `"source"` (оригинальный) или `"extracted"` (производный). +======= +Поле `document_type` - значения: `"source"` (исходный) или `"extracted"` (производный). +>>>>>>> 82edf2d (New md files from RunPod) API `add-child-document` - создает дочерний документ с автоматическим `document_type = "extracted"`. API `list-children` - извлекает все дочерние документы родительского документа. Каскадное удаление - удаление родительского документа автоматически удаляет все дочерние документы. @@ -130,12 +169,20 @@ API `list-children` - извлекает все дочерние докумен `trustgraph-flow/trustgraph/tables/library.py` - Хранилище таблиц Cassandra. `trustgraph-base/trustgraph/schema/services/library.py` - Определения схемы. +<<<<<<< HEAD #### Необходимые улучшения +======= +#### Проблемы, требующие решения +>>>>>>> 82edf2d (New md files from RunPod) "Библиотекарь" имеет необходимые компоненты, но в настоящее время: 1. Связывание "родитель-потомок" ограничено одним уровнем - отсутствуют вспомогательные функции для обхода многоуровневых графов. 2. Отсутствует стандартная терминология для типов отношений (например, `derivedFrom`, `extractedFrom`). +<<<<<<< HEAD 3. Метаданные происхождения (метод извлечения, уверенность, позиция фрагмента) не стандартизированы. +======= +3. Метаданные происхождения (метод извлечения, достоверность, позиция фрагмента) не стандартизированы. +>>>>>>> 82edf2d (New md files from RunPod) 4. Отсутствует API запросов для прослеживания полной цепочки происхождения от факта до исходного источника. ## Проектирование сквозного потока @@ -289,7 +336,11 @@ activity:pdf-extract-456 tg:componentVersion "1.2.3" . activity:pdf-extract-456 prov:startedAtTime "2024-01-15T10:30:00Z" . ``` +<<<<<<< HEAD **Раздел (выдан разделителем):** +======= +**Раздел (выдан Компоновщиком):** +>>>>>>> 82edf2d (New md files from RunPod) ``` chunk:123-1-1 a prov:Entity . chunk:123-1-1 prov:wasDerivedFrom page:123-1 . @@ -306,7 +357,11 @@ activity:chunk-789 tg:chunkSize 2048 . activity:chunk-789 tg:chunkOverlap 200 . ``` +<<<<<<< HEAD **Жирный шрифт (вывод Knowledge Extractor):** +======= +**Жирный шрифт (выделен извлечением знаний):** +>>>>>>> 82edf2d (New md files from RunPod) ``` # The extracted triple (edge) entity:JohnSmith rel:worksAt entity:AcmeCorp . @@ -324,7 +379,11 @@ activity:extract-999 tg:llmModel "claude-3" . activity:extract-999 tg:ontology . ``` +<<<<<<< HEAD **Встраивание (хранится в векторной базе данных, а не в тройной базе данных):** +======= +**Встраивания (хранятся в векторной базе данных, а не в тройной базе данных):** +>>>>>>> 82edf2d (New md files from RunPod) Встраивания хранятся в векторной базе данных вместе с метаданными, а не в виде RDF-троек. Каждая запись встраивания содержит: @@ -336,7 +395,11 @@ activity:extract-999 tg:ontology . | model | Используемая модель встраивания | `text-embedding-ada-002` | | component_version | Версия компонента TG | `1.0.0` | +<<<<<<< HEAD Поле `entity` связывает встраивание с графом знаний (URI узла). Поле `chunk_id` предоставляет информацию о происхождении, указывающую на исходный фрагмент, что позволяет проследить путь до исходного документа. +======= +Поле `entity` связывает встраивание с графом знаний (URI узла). Поле `chunk_id` предоставляет информацию о происхождении, указывающую на исходный фрагмент, что позволяет проследить путь вверх по DAG к исходному документу. +>>>>>>> 82edf2d (New md files from RunPod) #### Расширения пространства имен TrustGraph @@ -348,7 +411,11 @@ activity:extract-999 tg:ontology . | `tg:pageCount` | Документ | Общее количество страниц в исходном документе | | `tg:mimeType` | Документ | MIME-тип исходного документа | | `tg:pageNumber` | Страница | Номер страницы в исходном документе | +<<<<<<< HEAD | `tg:chunkIndex` | Фрагмент | Индекс фрагмента внутри родительского фрагмента | +======= +| `tg:chunkIndex` | Фрагмент | Индекс фрагмента внутри родительского элемента | +>>>>>>> 82edf2d (New md files from RunPod) | `tg:charOffset` | Фрагмент | Смещение символов в родительском тексте | | `tg:charLength` | Фрагмент | Длина фрагмента в символах | | `tg:chunkSize` | Действие | Настроенный размер фрагмента | @@ -363,7 +430,11 @@ activity:extract-999 tg:ontology . #### Начальная загрузка словаря (для каждой коллекции) +<<<<<<< HEAD Граф знаний является онтологически нейтральным и изначально пуст. При первом добавлении данных о происхождении PROV-O в коллекцию словарь должен быть инициализирован с помощью RDF-меток для всех классов и предикатов. Это обеспечивает удобочитаемое отображение в запросах и пользовательском интерфейсе. +======= +Граф знаний является онтологически нейтральным и изначально пуст. При записи данных о происхождении PROV-O в коллекцию в первый раз словарь должен быть инициализирован с помощью меток RDF для всех классов и предикатов. Это обеспечивает удобочитаемое отображение в запросах и пользовательском интерфейсе. +>>>>>>> 82edf2d (New md files from RunPod) **Классы PROV-O:** ``` @@ -401,11 +472,19 @@ tg:sourceCharOffset rdfs:label "source character offset" . tg:sourceCharLength rdfs:label "source character length" . ``` +<<<<<<< HEAD **Примечания по реализации:** Этот механизм начальной загрузки словаря должен быть идемпотентным, то есть его можно безопасно запускать несколько раз без создания дубликатов. Его можно запускать при первой обработке документа в коллекции или как отдельный этап инициализации коллекции. #### Происхождение подраздела (желательно) Для более детальной информации о происхождении полезно записывать, из какой именно части фрагмента была извлечена тройка. Это позволяет: +======= +**Примечания по реализации:** Этот начальный набор словаря должен быть идемпотентным - его можно безопасно запускать несколько раз без создания дубликатов. Его можно запускать при первой обработке документа в коллекции или как отдельный этап инициализации коллекции. + +#### Происхождение под-фрагментов (желательно) + +Для более детальной информации о происхождении, было бы полезно записывать, из какой именно части фрагмента была извлечена тройка. Это позволяет: +>>>>>>> 82edf2d (New md files from RunPod) Выделять точный исходный текст в пользовательском интерфейсе Проверять точность извлечения по отношению к исходному тексту @@ -435,11 +514,16 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . **Соображения по реализации:** Извлечение на основе LLM может не всегда предоставлять информацию о позициях символов. +<<<<<<< HEAD Можно запросить LLM, чтобы он возвращал исходное предложение/фразу вместе с извлеченными тройками. +======= +Можно запросить LLM, чтобы она возвращала исходное предложение/фразу вместе с извлеченными тройками. +>>>>>>> 82edf2d (New md files from RunPod) Альтернативно, можно выполнить постобработку для сопоставления извлеченных сущностей с исходным текстом. Компромисс между сложностью извлечения и детализацией происхождения. Может быть проще реализовать с использованием структурированных методов извлечения, чем с использованием LLM для извлечения в свободной форме. +<<<<<<< HEAD Это обозначено как перспективное направление - сначала следует реализовать базовое отслеживание происхождения на уровне фрагментов, а отслеживание подфрагментов следует рассматривать как улучшение в будущем, если это будет возможно. ### Двухуровневая модель хранения @@ -452,12 +536,30 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . | Граф знаний | Ребра "родитель-потомок" + метаданные | Запросы происхождения, атрибуция фактов | Оба хранилища поддерживают одну и ту же структуру графа. Библиотекарь хранит содержимое, а граф хранит отношения и обеспечивает возможности запросов для обхода. +======= +Это обозначено как перспективное направление - сначала следует реализовать базовое отслеживание происхождения на уровне фрагментов, а отслеживание подфрагментов следует рассматривать как улучшение в будущем, если это возможно. + +### Двухуровневая модель хранения + +Граф происхождения строится постепенно по мере прохождения документов по конвейеру: + +| Хранилище | Что хранится | Назначение | +|-------|---------------|---------| +| Библиотекарь | Содержимое документа + ссылки родитель-потомок | Извлечение содержимого, каскадное удаление | +| Граф знаний | Ребра родитель-потомок + метаданные | Запросы происхождения, атрибуция фактов | + +Оба хранилища поддерживают одну и ту же структуру графа. Библиотекарь хранит содержимое, а граф хранит отношения и обеспечивает возможность выполнения запросов для обхода графа. +>>>>>>> 82edf2d (New md files from RunPod) ### Основные принципы проектирования 1. **Идентификатор документа как единица потока данных** - Процессоры передают идентификаторы, а не содержимое. Содержимое извлекается из библиотеки, когда это необходимо. +<<<<<<< HEAD 2. **Отправка данных только в исходной точке** - Метаданные записываются в граф только один раз при начале обработки, а не повторяются далее по цепочке. +======= +2. **Однократная отправка данных в источнике** - Метаданные записываются в граф один раз при начале обработки, а не повторяются далее по цепочке. +>>>>>>> 82edf2d (New md files from RunPod) 3. **Единый шаблон для процессоров** - Каждый процессор следует одному и тому же шаблону: прием/извлечение/создание/сохранение/отправка/передача. @@ -473,7 +575,11 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . Инициирует обработку документа, отправляя идентификатор документа первому процессору. Нет подключения к хранилищу тройных данных - метаданные добавляются к результатам извлечения. +<<<<<<< HEAD `add-child-document` создает одноуровневые ссылки "родитель-потомок". +======= +`add-child-document` создает одноуровневые ссылки родитель-потомок. +>>>>>>> 82edf2d (New md files from RunPod) `list-children` возвращает только непосредственные потомки. #### Необходимые изменения @@ -486,7 +592,11 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . **2. Словарь типов документов** +<<<<<<< HEAD Стандартизировать значения `document_type` для дочерних документов: +======= +Стандартизировать значения `document_type` для документов-потомков: +>>>>>>> 82edf2d (New md files from RunPod) `source` - исходный загруженный документ. `page` - страница, извлеченная из источника (PDF и т.д.). `chunk` - текстовый фрагмент, полученный из страницы или источника. @@ -498,7 +608,11 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . | Хранилище тройных данных | Новый исходящий канал - отправка ребер метаданных документа | | Инициация обработки | Отправка метаданных в граф перед передачей идентификатора документа | +<<<<<<< HEAD ### Изменения в извлечении данных из PDF +======= +### Изменения в извлечении PDF +>>>>>>> 82edf2d (New md files from RunPod) #### Текущее состояние @@ -511,13 +625,22 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . **1. Новый интерфейс: Клиент библиотеки** +<<<<<<< HEAD Извлечение данных из PDF должно сохранять каждую страницу как дочерний документ в библиотеке. Добавить клиент библиотеки в сервис извлечения данных из PDF. +======= +Извлечение PDF должно сохранять каждую страницу как документ-потомок в библиотеке. +Добавить клиент библиотеки в сервис извлечения PDF. +>>>>>>> 82edf2d (New md files from RunPod) Для каждой страницы: вызвать `add-child-document` с parent = идентификатор корневого документа. **2. Новый интерфейс: Подключение к хранилищу тройных данных** +<<<<<<< HEAD Извлечение данных из PDF должно отправлять ребра "родитель-потомок" в граф знаний. +======= +Извлечение PDF должно отправлять ребра родитель-потомок в граф знаний. +>>>>>>> 82edf2d (New md files from RunPod) Добавить клиент/публикатор хранилища тройных данных. Для каждой страницы: отправлять ребро, связывающее документ страницы с родительским документом. @@ -534,7 +657,11 @@ Chunker будет извлекать содержимое из хранилищ | Тройной магазин | Новый исходящий поток - генерация связей родитель-потомок | | Сообщение вывода | Изменение с содержимого на идентификатор документа | +<<<<<<< HEAD ### Изменения Chunker +======= +### Изменения в Chunker +>>>>>>> 82edf2d (New md files from RunPod) #### Текущее состояние @@ -576,20 +703,32 @@ Chunker будет извлекать содержимое из хранилищ | Тройной магазин | Новый исходящий поток - генерация связей родитель-потомок | | Сообщение вывода | Изменение с содержимого только на идентификатор + содержимое | +<<<<<<< HEAD ### Изменения Knowledge Extractor +======= +### Изменения в Knowledge Extractor +>>>>>>> 82edf2d (New md files from RunPod) #### Текущее состояние Получает содержимое фрагмента Извлекает тройки и вложения +<<<<<<< HEAD Передает в тройной магазин и хранилище вложений +======= +Отправляет в тройной магазин и хранилище вложений +>>>>>>> 82edf2d (New md files from RunPod) `subjectOf` отношение указывает на верхний уровень документа (а не на фрагмент) #### Необходимые изменения **1. Изменение обработки входных данных** +<<<<<<< HEAD Получайте идентификатор фрагмента вместе с содержимым. +======= +Получайте идентификатор документа фрагмента вместе с содержимым. +>>>>>>> 82edf2d (New md files from RunPod) Используйте идентификатор фрагмента для отслеживания происхождения (содержимое уже включено в соответствии с оптимизацией) **2. Обновление отслеживания происхождения тройками** @@ -610,7 +749,11 @@ Chunker будет извлекать содержимое из хранилищ |-----------|--------| | Сообщение ввода | Ожидается идентификатор фрагмента + содержимое (а не только содержимое) | | Тройной магазин | Используйте реификацию для отслеживания происхождения тройки → фрагмент | +<<<<<<< HEAD | Отслеживание происхождения вложениями | Свяжите идентификатор сущности → идентификатор фрагмента | +======= +| Отслеживание происхождения вложений | Свяжите идентификатор сущности → идентификатор фрагмента | +>>>>>>> 82edf2d (New md files from RunPod) ## Ссылки diff --git a/docs/tech-specs/extraction-time-provenance.sw.md b/docs/tech-specs/extraction-time-provenance.sw.md index a52613ff..c4025818 100644 --- a/docs/tech-specs/extraction-time-provenance.sw.md +++ b/docs/tech-specs/extraction-time-provenance.sw.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD # Asili ya Data Wakati wa Utoaji: Safu ya Chanzo ## Muhtasari @@ -26,6 +27,36 @@ Wakati uhusiano (maelezo/ukweli) unachukuliwa kutoka kwa hati, uhusiano wa `subj 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: +======= +# Asili ya Data Wakati wa Uvunaji: Safu ya Chanzo + +## Muhtasari + +Hati hii ina rekodi za maelezo kuhusu asili ya data wakati wa uvunaji kwa ajili ya kazi zijazo za kubuni. Asili ya data wakati wa uvunaji inarejelea "safu ya chanzo" - ambako data ilitoka awali, jinsi ilivyovunwa na kubadilishwa. + +Hii ni tofauti na asili ya data wakati wa utafutaji (angalia `query-time-provenance.md`) ambayo inarejelea hoja za msimuizi. + +## Tatizo + +### Utendaji Sasa + +Hivi sasa, asili ya data inafanya kazi kama ifuatavyo: +Meta-data ya hati inahifadhiwa kama triple za RDF katika grafu ya maarifa. +Kitambulisho cha hati (document ID) huunganisha meta-data na hati, hivyo hati inaonekana kama nodi katika grafu. +Wakati uhusiano (relationships/facts) unavyovunwa kutoka kwa hati, uhusiano wa `subjectOf` huunganisha uhusiano uliovunwa na hati ya asili. + +### Matatizo ya Mbinu Hali + +1. **Upakiaji wa meta-data unaorudia-rudia:** Meta-data ya hati huunganishwa na kupakiwa mara kwa mara na kila kundi la triple zinazovunwa kutoka kwa hati hiyo. Hii ni matumizi ya rasilimali na kurudia - meta-data sawa husafiri kama mizigo na kila matokeo ya uvunaji. + +2. **Asili ya data ya kawaida:** Uhusiano wa `subjectOf` unaoonekana sasa huunganisha tu ukweli moja kwa moja na hati ya juu. Hakuna uwazi kuhusu mnyororo wa mabadiliko - ukurasa gani ukweli ulikuja, kipande gani, njia gani ya uvunaji iliyotumika. + +### Hali Inayotakikana + +1. **Pakia meta-data mara moja:** Meta-data ya hati inapaswa kupakiwa mara moja na kuunganishwa na nodi ya hati ya juu, sio kurudiwa na kila kundi la triple. + +2. **Grafu ya asili ya data yenye maelezo:** Rekodi mnyororo kamili wa mabadiliko kutoka kwa hati ya asili kupitia kwa vitu vyote vya kati hadi kwa ukweli uliovunwa. Kwa mfano, mabadiliko ya hati ya PDF: +>>>>>>> 82edf2d (New md files from RunPod) ``` PDF file (source document with metadata) @@ -44,9 +75,15 @@ Wakati uhusiano (maelezo/ukweli) unachukuliwa kutoka kwa hati, uhusiano wa `subj 4. **Kitambulisho cha kudumu:** Kila kitu (artifact) cha kati (ukurasa, sehemu) kina kitambulisho cha kudumu kama node katika mfumo. +<<<<<<< HEAD 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. +======= +5. **Uunganisho wa mzazi-mtoto:** Hati zilizoundwa zinaunganishwa na wazazi wao hadi hati ya asili ya juu zaidi kwa kutumia aina za uhusiano sawa. + +6. **Uhusiano sahihi wa ukweli:** Uhusiano wa `subjectOf` kwenye miundo iliyopatikana unaelekeza kwa mzazi wa karibu (sehemu), sio hati ya juu. Uhusiano wa asili kamili hupatikana kwa kutembea juu ya DAG. +>>>>>>> 82edf2d (New md files from RunPod) ## Matumizi @@ -71,6 +108,7 @@ Kuelewa hasa wapi katika hati (ukurasa gani, sehemu gani) ukweli ulitoka. ### UC2: Kurekebisha Ubora wa Upatikanaji +<<<<<<< HEAD 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 @@ -88,6 +126,25 @@ Ushawishi mbili unapingana. Tembelea zote kurudi kwenye vyanzo vyao ili kuelewa ### 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. +======= +Ukweli unaonekana kuwa mbaya. Rudi 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 zipi zilizotokana nayo? Ghairi na uundue tena zile tu, badala ya kuchakata kila kitu. + +### UC4: Ufutilishaji wa Data / Haki ya Kusahau + +Hati ya asili lazima iondolewe (GDPR, kisheria, n.k.). Tembea kwenye DAG ili kupata na kuondoa ukweli wote uliotokana. + +### UC5: Suluhisho la Mzozo + +Ushawishi mbili unapingana. Rudi nyuma kwa vyanzo vyake ili kuelewa kwa nini na uamue ni ipi ya kuamini (chanzo cha mamlaka zaidi, cha hivi karibuni, n.k.). + +### UC6: Uzito wa Mamlaka ya Chanzo + +Vyanzo vingine ni vya mamlaka kuliko vingine. Ushawishi unaweza kupimwa au kuchujwa kulingana na mamlaka/ubora wa hati zake za asili. +>>>>>>> 82edf2d (New md files from RunPod) ### UC7: Ulinganisho wa Mfumo wa Upatikanaji @@ -97,11 +154,19 @@ Linganisha matokeo kutoka kwa mbinu/matoleo tofauti ya upatikanaji. Mfumo wa upa ### Msimamizi wa Maktaba +<<<<<<< HEAD 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:** +======= +Kifaa cha msimamizi wa maktaba tayari hutoa uhifadhi wa hati pamoja na kitambulisho cha kipekee cha hati. Mfumo wa asili unajumuishwa na miundombinu hii iliyopo. + +#### Uwezo Ulioopo (tayari umetekelezwa) + +**Uunganisho wa Hati za Mzazi na Mtoto:** +>>>>>>> 82edf2d (New md files from RunPod) `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 @@ -121,7 +186,11 @@ Kitambulisho cha kitu (UUIDs) huundwa ndani kwa uhifadhi wa blob **Muundo wa Uhifadhi:** MetaData huhifadhiwa katika Cassandra (`librarian` keyspace, `document` meza) Yaliyomo huhifadhiwa katika uhifadhi wa blob wa MinIO/S3 (`library` ndoo) +<<<<<<< HEAD Uwasilishaji mahiri wa yaliyomo: hati < 2MB zimejumuishwa, hati kubwa zaidi hutiririshwa +======= +Utoaji wa yaliyomo mahiri: hati < 2MB zimejumuishwa, hati kubwa zaidi hutiririshwa +>>>>>>> 82edf2d (New md files from RunPod) #### Faili Muhimu @@ -130,6 +199,7 @@ Uwasilishaji mahiri wa yaliyomo: hati < 2MB zimejumuishwa, hati kubwa zaidi huti `trustgraph-flow/trustgraph/tables/library.py` - Duka la meza ya Cassandra `trustgraph-base/trustgraph/schema/services/library.py` - Ufafanuzi wa mpango +<<<<<<< HEAD #### Mapungufu Yanayohitaji Kusuluhishwa Msimamizi wa maktaba una vipengele muhimu lakini kwa sasa: @@ -142,6 +212,20 @@ Msimamizi wa maktaba una vipengele muhimu lakini kwa sasa: Kila mchakato katika mstari huu unafuata mfumo unaoendana: Kupokea kitambulisho cha hati kutoka kwa chanzo +======= +#### Mapungufu Yanayohitaji Kushughulikiwa + +Msimamizi wa maktaba una vipengele muhimu lakini kwa sasa: +1. Uunganisho wa mzazi-mtoto ni safu moja tu - hakuna msaada wa uvukaji wa DAG wa ngazi nyingi +2. Hakuna hesabu ya kawaida ya aina ya uhusiano (e.g., `derivedFrom`, `extractedFrom`) +3. MetaData ya asili (njia ya uondoaji, uaminifu, nafasi ya kipande) hayajawekwa kikao +4. Hakuna API ya kuuliza ili kuvuka mnyororo kamili wa asili kutoka kwa ukweli hadi chanzo + +## Muundo wa Mtiririko wa Kila Hatua + +Kila mchakato katika mstari huu unafuata mfumo unaoendana: +Kupokea kitambulisho cha hati kutoka kwa mfumo wa juu +>>>>>>> 82edf2d (New md files from RunPod) 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 @@ -205,7 +289,11 @@ Kuna mitiririko miwili kulingana na aina ya hati: #### Mtiririko wa Nyaraka za Nakshata +<<<<<<< HEAD Nyaraka za nakshata huenda moja kwa moja kwenye sehemu ya "chunker" na hazitumii programu ya kutenganisha faili za PDF: +======= +Nyaraka za nakshata huenda moja kwa moja kwenye sehemu ya "chunker" na hazitumii programu ya kutolea maelezo kutoka kwa faili za PDF: +>>>>>>> 82edf2d (New md files from RunPod) ``` ┌─────────────────────────────────────────────────────────────────────────┐ @@ -232,14 +320,22 @@ Nyaraka za nakshata huenda moja kwa moja kwenye sehemu ya "chunker" na hazitumii └─────────────────────────────────────────────────────────────────────────┘ ``` +<<<<<<< HEAD DAG iliyotokea ni ya kiwango kimoja chini: +======= +Matokeo ya DAG (Grafu ya Kuelekea Mbele) ni ngazi moja chini: +>>>>>>> 82edf2d (New md files from RunPod) ``` PDF: Document → Pages → Chunks → Triples/Embeddings Text: Document → Chunks → Triples/Embeddings ``` +<<<<<<< HEAD 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. +======= +Ubunifu unaoendana na matumizi ya aina zote, kwa sababu mfumo wa kugawanya (chunker) hutumia data yake ya pembeni kwa njia ya jumla - hutumia kitambulisho chochote cha hati kinachopokelewa kama mzazi, bila kujali kama hiyo ni hati ya asili au ukurasa. +>>>>>>> 82edf2d (New md files from RunPod) ### Mpango wa Meta-data (PROV-O) @@ -250,21 +346,36 @@ Meta-data ya asili hutumia ontolojia ya W3C PROV-O. Hii hutoa msamiati wa kawaid | Aina ya PROV-O | Matumizi katika TrustGraph | |-------------|------------------| | `prov:Entity` | Hati, Ukurasa, Sehemu, Triple, Uingizwaji | +<<<<<<< HEAD | `prov:Activity` | Mifano ya operesheni za utoaji | +======= +| `prov:Activity` | Mifano ya shughuli za utoaji | +>>>>>>> 82edf2d (New md files from RunPod) | `prov:Agent` | Vipengele vya TG (mfumo wa utoaji wa PDF, mfumo wa kugawanya, n.k.) pamoja na matoleo | ### Mahusiano ya PROV-O +<<<<<<< HEAD | 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 | +======= +| Kifurushi | Maana | Kifaa | +|-----------|---------|---------| +| `prov:wasDerivedFrom` | Kitu kinachotokana na kitu kingine | Ukurasa ulitokana na Hati | +| `prov:wasGeneratedBy` | Kitu kilichoanzishwa na shughuli | Ukurasa ulianzishwa na Shughuli ya Utoaji wa PDF | +>>>>>>> 82edf2d (New md files from RunPod) | `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 +<<<<<<< HEAD **Hati ya Asili (inatoolewa na Librarian):** +======= +**Hati ya Asili (inatoa Librarian):** +>>>>>>> 82edf2d (New md files from RunPod) ``` doc:123 a prov:Entity . doc:123 dc:title "Research Paper" . @@ -289,7 +400,11 @@ activity:pdf-extract-456 tg:componentVersion "1.2.3" . activity:pdf-extract-456 prov:startedAtTime "2024-01-15T10:30:00Z" . ``` +<<<<<<< HEAD **Sehemu (imetolewa na Chunker):** +======= +**Sehemu (inatoolewa na Chunker):** +>>>>>>> 82edf2d (New md files from RunPod) ``` chunk:123-1-1 a prov:Entity . chunk:123-1-1 prov:wasDerivedFrom page:123-1 . @@ -328,6 +443,7 @@ activity:extract-999 tg:ontology . Uingizwaji huhifadhiwa katika hifadhi ya vekta pamoja na metadata, sio kama triple za RDF. Kila rekodi ya uingizwaji ina: +<<<<<<< HEAD | Nguvu | Maelezo | Mfano | |-------|-------------|---------| | vekta | Vektali ya uingizwaji | [0.123, -0.456, ...] | @@ -364,6 +480,44 @@ Maneno maalum chini ya nafasi ya `tg:` kwa metadata maalum ya uondoaji: #### 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. +======= +| Shamba | Maelezo | Mfano | +|-------|-------------|---------| +| vekta | Vakta 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 mfumo wa uingizwaji wa TG | `1.0.0` | + +Shamba la `entity` huunganisha uingizwaji na grafu ya maarifa (URI ya node). Shamba la `chunk_id` hutoa asili kurudi kwa sehemu ya asili, na hivyo kuruhusu ufuatiliaji hadi kwenye hati asili. + +#### Miongozo ya Upanuzi wa Nafasi ya TrustGraph + +Maneno maalum chini ya nafasi ya `tg:` kwa metadata maalum ya utoaji: + +| Dhana | Eneo | Maelezo | +|-----------|--------|-------------| +| `tg:contains` | Subgraph | Inaashiria triple iliyo ndani ya subgraph hii. | +| `tg:pageCount` | Document | Idadi jumla ya kurasa katika hati ya asili. | +| `tg:mimeType` | Document | Aina ya MIME ya hati ya asili. | +| `tg:pageNumber` | Page | Namba ya ukurasa katika hati ya asili. | +| `tg:chunkIndex` | Chunk | Indexi ya chunk ndani ya mzazi. | +| `tg:charOffset` | Chunk | Marekebisho ya herufi katika maandishi ya mzazi. | +| `tg:charLength` | Chunk | Urefu wa chunk katika herufi. | +| `tg:chunkSize` | Activity | Ukubwa wa chunk uliopangwa. | +| `tg:chunkOverlap` | Activity | Uwianifu uliopangwa kati ya chunks. | +| `tg:componentVersion` | Activity | Toleo la kipengele cha TG. | +| `tg:llmModel` | Activity | LLM iliyotumika kwa uondoaji. | +| `tg:ontology` | Activity | URI ya ontology iliyotumika kuongoza uondoaji. | +| `tg:embeddingModel` | Activity | Mfumo uliotumika kwa embeddings. | +| `tg:sourceText` | Statement | Nakala kamili kutoka ambayo triple iliondolewa. | +| `tg:sourceCharOffset` | Statement | Marekebisho ya herufi ndani ya chunk ambapo nakala ya chanzo huanza. | +| `tg:sourceCharLength` | Statement | Urefu wa nakala ya chanzo katika herufi. | + +#### Uanzishaji wa Dhana (Kwa Kundi Kila Kimoja) + +Grafu ya maarifa ni ya kawaida na huanzishwa kuwa tupu. Wakati wa kuandika data ya asili ya PROV-O kwenye mkusanyiko kwa mara ya kwanza, dhana lazima ianzishwe kwa lebo za RDF kwa madarasa na dhana zote. Hii inahakikisha onyesho linalosoma na binadamu katika maswali na UI. +>>>>>>> 82edf2d (New md files from RunPod) **Madarasa ya PROV-O:** ``` @@ -381,7 +535,11 @@ prov:wasAssociatedWith rdfs:label "was associated with" . prov:startedAtTime rdfs:label "started at" . ``` +<<<<<<< HEAD **Predikatendi za TrustGraph:** +======= +**Maneno ya TrustGraph:** +>>>>>>> 82edf2d (New md files from RunPod) ``` tg:contains rdfs:label "contains" . tg:pageCount rdfs:label "page count" . @@ -401,6 +559,7 @@ tg:sourceCharOffset rdfs:label "source character offset" . tg:sourceCharLength rdfs:label "source character length" . ``` +<<<<<<< HEAD **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) @@ -410,6 +569,17 @@ Kwa asili ya kina zaidi, itakuwa muhimu kurekodi hasa katika sehemu gani ya kipa Kuonyesha maandishi ya asili hasa katika kiolesura (UI) Kuthibitisha usahihi wa uondoaji dhidi ya asili Kuchunguza ubora wa uondoaji katika kiwango cha sentensi +======= +**Kumbuka kuhusu utekelezaji:** Msamiati huu wa kuanzia inapaswa kuwa sawa - salama 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 haswa katika sehemu gani ndani ya kipande ambapo triple ilitokana. Hii inawezesha: + +Kuonyesha maandishi ya asili haswa katika kiolesura (UI) +Kuangalia usahihi wa utoaji kulingana na asili +Kuchunguza ubora wa utoaji katika kiwango cha sentensi +>>>>>>> 82edf2d (New md files from RunPod) **Mfano na ufuatiliaji wa nafasi:** ``` @@ -436,6 +606,7 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . 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. +<<<<<<< HEAD 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. @@ -468,16 +639,55 @@ Hifadhi zote mbili zinahifadhi muundo sawa wa DAG. Msimamizi huhifadhi yaliyomo; ## Majukumu ya Utekelezaji ### Marekebisho ya Msimamizi +======= +Au, inaweza kufanywa urekebishaji wa ziada ili kulinganisha vitu vilivyotolewa na maandishi ya asili. +Kuna mtego kati ya utata wa utoleaji wa maelezo na uwazi wa asili. +Inaweza kuwa rahisi kufanikisha kwa kutumia mbinu zilizopangwa kuliko utoleaji wa maelezo wa bure unaotegemea LLM. + +Hii imewekwa kama lengo la baadaye - utaratibu wa msingi wa utoleaji wa maelezo wa kiwango cha sehemu unapaswa kutekelezwa kwanza, na kufuatilia kwa sehemu ndogo kama uboreshaji wa baadaye ikiwa inawezekana. + +### Mfumo wa Uhifadhi Mkubwa + +Mfumo wa DAG wa utoleaji wa maelezo huundwa hatua kwa hatua wakati hati zinapopitia katika mchakato: + +| Hifadhi | Kitu Kinachohifadhiwa | Lengo | +|-------|---------------|---------| +| Mkumbaji | Yaliyomo ya hati + viungo vya mzazi-mtoto | Upatikanaji wa yaliyomo, kufuta kwa mfuatano | +| Grafu ya Maarifa | Aina za mzazi-mtoto + metadata | Maswali ya utoleaji wa maelezo, uhusishaji wa ukweli | + +Hifadhi zote mbili zinahifadhi muundo sawa wa DAG. Mkumbaji huhifadhi yaliyomo; grafu huhifadhi uhusiano na inaruhusu maswali ya utaftaji. + +### Kanuni Muhimu za Ubunifu + +1. **Kitambulisho cha hati kama kitengo cha mtiririko** - Wasindikaji hutuma kitambulisho, sio yaliyomo. Yaliyomo hupatikana kutoka kwa mkumbaji wakati inahitajika. + +2. **Tolea mara moja katika chanzo** - Metadata imeandikwa kwenye grafu mara moja wakati wa mchakato unaanza, sio kurudiwa baadaye. + +3. **Muundo sawa wa wasindikaji** - Kila wasindikaji hufuata muundo sawa wa kupokea/kupata/kutoa/kuokoa/kutoa/kusonga. + +4. **Uundaji wa hatua kwa hatua wa DAG** - Kila wasindikaji huongeza kiwango chake kwenye DAG. Mnyororo kamili wa utoleaji wa maelezo huundwa hatua kwa hatua. + +5. **Uboreshaji baada ya kugawanyika** - Baada ya kugawanyika, ujumbe unaambatana na kitambulisho na yaliyomo. Sehemu ndogo (2-4KB), kwa hivyo kujumuisha yaliyomo inazuia safari zisizo za lazima za mkumbaji wakati inahifadhi utoleaji wa maelezo kupitia kitambulisho. + +## Majukumu ya Utendaji + +### Marekebisho ya Mkumbaji +>>>>>>> 82edf2d (New md files from RunPod) #### Hali ya Sasa Inaanzisha mchakato wa hati kwa kutuma kitambulisho cha hati kwa wasindikaji wa kwanza. +<<<<<<< HEAD Hakuna muunganisho na duka la vitriple - metadata huunganishwa na matokeo ya utoleaji. +======= +Hakuna muunganisho na duka la vitri - metadata huunganishwa na matokeo ya utoleaji. +>>>>>>> 82edf2d (New md files from RunPod) `add-child-document` huunda viungo vya mzazi-mtoto vya kiwango kimoja. `list-children` hurudisha watoto wa karibu tu. #### Marekebisho Yanayohitajika +<<<<<<< HEAD **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. @@ -485,6 +695,15 @@ 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** +======= +**1. Kiolesura kipya: Muunganisho wa duka la vitri** + +Mkumbaji anahitaji kutoa kingo za metadata ya hati moja kwa moja kwenye grafu ya maarifa wakati wa kuanzisha mchakato. +Ongeza mteja/mpublisher wa duka la vitri kwenye huduma ya mkumbaji. +Wakati wa kuanzisha mchakato: toa metadata ya hati ya mizizi kama kingo za grafu (mara moja). + +**2. Msamiati wa aina ya hati** +>>>>>>> 82edf2d (New md files from RunPod) Sanidi maadili ya `document_type` kwa watoto wa hati: `source` - hati iliyopakiwa asili. @@ -493,9 +712,15 @@ Sanidi maadili ya `document_type` kwa watoto wa hati: #### Muhtasari wa Marekebisho ya Kiolesura +<<<<<<< HEAD | Kiolesura | Marekebisho | |-----------|--------| | Duka la vitriple | Muunganisho mpya wa kutoka nje - toa kingo za metadata ya hati | +======= +| Kiolesura | Mabadiliko | +|-----------|--------| +| Duka la vitri | Muunganisho mpya wa kutoka nje - toa kingo za metadata ya hati | +>>>>>>> 82edf2d (New md files from RunPod) | Kuanzisha mchakato | Toa metadata kwenye grafu kabla ya kusonga kitambulisho cha hati | ### Marekebisho ya Mtoa Hati ya PDF @@ -505,6 +730,7 @@ Sanidi maadili ya `document_type` kwa watoto wa hati: Hupokea yaliyomo ya hati (au mitiririko ya hati kubwa). Hutolea maandishi kutoka kwa kurasa za PDF. Hupeleka yaliyomo ya ukurasa kwa mtoa sehemu. +<<<<<<< HEAD Hakuna mwingiliano na msimamizi au duka la vitriple. #### Marekebisho Yanayohitajika @@ -520,18 +746,43 @@ Kwa kila ukurasa: piga `add-child-document` na mzazi = kitambulisho cha hati ya 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. +======= +Hakuna mwingiliano na mkumbaji au duka la vitri. + +#### Marekebisho Yanayohitajika + +**1. Kiolesura kipya: Mteja wa mkumbaji** + +Mtoa hati ya PDF anahitaji kuhifadhi kila ukurasa kama hati ya mtoto katika mkumbaji. +Ongeza mteja wa mkumbaji 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 vitri** + +Mtoa hati ya PDF anahitaji kutoa aina za mzazi-mtoto kwenye grafu ya maarifa. +Ongeza mteja/mpublisher wa duka la vitri. +Kwa kila ukurasa: toa aina inayounganisha ukurasa wa hati na hati ya mzazi. +>>>>>>> 82edf2d (New md files from RunPod) **3. Badilisha muundo wa matokeo** Badala ya kusambaza yaliyomo ya ukurasa moja kwa moja, sambaza kitambulisho cha hati ya ukurasa. +<<<<<<< HEAD Chunker itapata yaliyomo kutoka kwa 'librarian' kwa kutumia kitambulisho. +======= +Chunker itapakua yaliyomo kutoka kwa 'librarian' kwa kutumia kitambulisho. +>>>>>>> 82edf2d (New md files from RunPod) #### Muhtasari wa Mabadiliko ya Kiolesura | Kiolesura | Mabadiliko | |-----------|--------| | Librarian | Mabadiliko mapya ya kutoka - hifadhi hati za watoto | +<<<<<<< HEAD | Hifadhi tatu | Mabadiliko mapya ya kutoka - toka miunganisho ya mzazi-mtoto | +======= +| Hifadhi tatu | Mabadiliko mapya ya kutoka - toa miunganisho ya mzazi-mtoto | +>>>>>>> 82edf2d (New md files from RunPod) | Ujumbe wa pato | Mabadiliko kutoka yaliyomo hadi kitambulisho cha hati | ### Mabadiliko ya Chunker @@ -539,14 +790,20 @@ Chunker itapata yaliyomo kutoka kwa 'librarian' kwa kutumia kitambulisho. #### Hali ya Sasa Yanapokea yaliyomo ya ukurasa/maandishi +<<<<<<< HEAD Yanagawanyika katika sehemu ndogo Yanatuma yaliyomo ya sehemu ndogo kwa wasindikaji wa baadaye +======= +Yanagawanywa katika sehemu +Yanatuma yaliyomo ya sehemu kwa wasindikaji wa baadaye +>>>>>>> 82edf2d (New md files from RunPod) Hakuna mwingiliano na 'librarian' au hifadhi tatu #### Mabadiliko Yanayohitajika **1. Badilisha utunzaji wa ingizo** +<<<<<<< HEAD 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 @@ -555,16 +812,34 @@ Pata yaliyomo ya ukurasa kwa kutumia kitambulisho cha hati 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 +======= +Pokea kitambulisho cha hati badala ya yaliyomo, upakue kutoka kwa 'librarian'. +Ongeza mteja wa 'librarian' kwenye huduma ya chunker +Pakua yaliyomo ya ukurasa kwa kutumia kitambulisho cha hati + +**2. Kiolesura kipya: Mteja wa 'Librarian' (kuandika)** + +Hifadhi kila sehemu kama hati ya mtoto katika 'librarian'. +Kwa kila sehemu: piga simu `add-child-document` na mzazi = kitambulisho cha hati ya ukurasa +>>>>>>> 82edf2d (New md files from RunPod) **3. Kiolesura kipya: Muunganisho wa hifadhi tatu** Toa miunganisho ya mzazi-mtoto kwa grafu ya maarifa. Ongeza mteja/mpublisher wa hifadhi tatu +<<<<<<< HEAD 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). +======= +Kwa kila sehemu: toa muunganisho unaounganisha hati ya sehemu na hati ya ukurasa + +**4. Badilisha muundo wa pato** + +Sambaza kitambulisho cha hati ya sehemu na yaliyomo ya sehemu (uboreshaji wa baada ya chunker). +>>>>>>> 82edf2d (New md files from RunPod) Wasindikaji wa baadaye hupokea kitambulisho kwa ajili ya asili + yaliyomo ili kufanya kazi nayo #### Muhtasari wa Mabadiliko ya Kiolesura @@ -572,7 +847,11 @@ Wasindikaji wa baadaye hupokea kitambulisho kwa ajili ya asili + yaliyomo ili ku | Kiolesura | Mabadiliko | |-----------|--------| | Ujumbe wa ingizo | Mabadiliko kutoka yaliyomo hadi kitambulisho cha hati | +<<<<<<< HEAD | Librarian | Mabadiliko mapya ya kutoka (kusoma + kuandika) - pata yaliyomo, hifadhi hati za watoto | +======= +| Librarian | Mabadiliko mapya ya kutoka (kusoma + kuandika) - pakua yaliyomo, hifadhi hati za watoto | +>>>>>>> 82edf2d (New md files from RunPod) | Hifadhi tatu | Mabadiliko mapya ya kutoka - toa miunganisho ya mzazi-mtoto | | Ujumbe wa pato | Mabadiliko kutoka yaliyomo-tu hadi kitambulisho + yaliyomo | @@ -580,15 +859,23 @@ Wasindikaji wa baadaye hupokea kitambulisho kwa ajili ya asili + yaliyomo ili ku #### Hali ya Sasa +<<<<<<< HEAD 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) +======= +Yanapokea yaliyomo ya sehemu +Yanatoa triples na embeddings +Yanatuma kwa hifadhi ya triples na hifadhi ya embeddings +`subjectOf` uhusiano unaelekeza kwenye hati ya juu (si sehemu) +>>>>>>> 82edf2d (New md files from RunPod) #### Mabadiliko Yanayohitajika **1. Badilisha utunzaji wa ingizo** +<<<<<<< HEAD Pokea kitambulisho cha hati ya sehemu ndogo pamoja na yaliyomo. Tumia kitambulisho cha sehemu ndogo kwa ulinganisho (yaliyomo tayari yamejumuishwa kwa uboreshaji) @@ -597,20 +884,41 @@ Tumia kitambulisho cha sehemu ndogo kwa ulinganisho (yaliyomo tayari yamejumuish 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 +======= +Pokea kitambulisho cha hati ya sehemu pamoja na yaliyomo. +Tumia kitambulisho cha sehemu kwa ulinganisho (yaliyomo tayari yamejumuishwa kwa uboreshaji) + +**2. Sasisha asili ya triples** + +Unganisha triples zilizotolewa na sehemu (si hati ya juu). +Tumia reification ili kuunda muunganisho unaoelekeza kwenye muunganisho +`subjectOf` uhusiano: triple → kitambulisho cha hati ya sehemu +>>>>>>> 82edf2d (New md files from RunPod) Matumizi ya kwanza ya msaada uliopo wa reification **3. Sasisha asili ya embeddings** +<<<<<<< HEAD Unganisha kitambulisho cha entiti ya embedding na sehemu ndogo. Toa muunganiko: kitambulisho cha entiti ya embedding → kitambulisho cha hati ya sehemu ndogo +======= +Unganisha kitambulisho cha entiti ya embedding na sehemu. +Toa muunganisho: kitambulisho cha entiti ya embedding → kitambulisho cha hati ya sehemu +>>>>>>> 82edf2d (New md files from RunPod) #### Muhtasari wa Mabadiliko ya Kiolesura | Kiolesura | Mabadiliko | |-----------|--------| +<<<<<<< HEAD | 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 | +======= +| Ujumbe wa ingizo | Inatarajia kitambulisho cha sehemu + yaliyomo (si yaliyomo tu) | +| Hifadhi ya triples | Tumia reification kwa asili ya triple → sehemu | +| Asili ya embeddings | Unganisha kitambulisho cha entiti → kitambulisho cha sehemu | +>>>>>>> 82edf2d (New md files from RunPod) ## Marejeleo diff --git a/docs/tech-specs/extraction-time-provenance.tr.md b/docs/tech-specs/extraction-time-provenance.tr.md index b27473eb..322d8d3a 100644 --- a/docs/tech-specs/extraction-time-provenance.tr.md +++ b/docs/tech-specs/extraction-time-provenance.tr.md @@ -2,9 +2,15 @@ ## Genel Bakış +<<<<<<< HEAD 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. +======= +Bu belge, gelecekteki özellik tanımlama ç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 (`query-time-provenance.md`'a bakın) farklıdır. +>>>>>>> 82edf2d (New md files from RunPod) ## Problem Tanımı @@ -17,15 +23,25 @@ Belgelerden kenarlar (ilişkiler/gerçekler) çıkarıldığında, çıkarılan ### Mevcut Yaklaşımla İlgili Sorunlar +<<<<<<< HEAD 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ı. +======= +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 olarak taşınır. + +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, hangi bölümden geldi, hangi çıkarma yöntemi kullanıldı. +>>>>>>> 82edf2d (New md files from RunPod) ### İ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. +<<<<<<< HEAD 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ü: +======= +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ü: +>>>>>>> 82edf2d (New md files from RunPod) ``` PDF file (source document with metadata) @@ -55,9 +71,15 @@ Belgelerden kenarlar (ilişkiler/gerçekler) çıkarıldığında, çıkarılan **Senaryo:** Bir kullanıcı bir GraphRAG sorgusu çalıştırır ve ajandan bir yanıt alır. **Süreç:** +<<<<<<< HEAD 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. +======= +1. Kullanıcı, GraphRAG ajanına bir sorgu gönderir. +2. Ajan, bir yanıt oluşturmak için bilgi grafiğinden ilgili gerçekleri alır. +3. Sorgu zamanı kaynak bilgisi spesifikasyonuna göre, ajan, yanıta hangi gerçeklerin katkıda bulunduğunu bildirir. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -65,9 +87,15 @@ Belgelerden kenarlar (ilişkiler/gerçekler) çıkarıldığında, çıkarılan 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. +<<<<<<< HEAD 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. +======= +Bir gerçekin bir belgenin neresinden (hangi sayfa, hangi bölüm) geldiğini tam olarak anlayabilir. + +**Değer:** Kullanıcılar, yapay zeka tarafından oluşturulan yanıtlara birincil kaynaklara karşı doğrulama yaparak güven oluşturabilir ve doğruluk kontrolünü sağlayabilir. +>>>>>>> 82edf2d (New md files from RunPod) ### KS2: Çıkarma Kalitesinin Hata Ayıklaması @@ -75,11 +103,19 @@ Bir gerçek yanlış görünüyor. Orijinal metni görmek için parça → sayfa ### KS3: Artımlı Yeniden Çıkarma +<<<<<<< HEAD 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. +======= +Kaynak belge güncellenir. 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üm türetilmiş gerçekleri bulmak ve kaldırmak için DAG'ı geçin. +>>>>>>> 82edf2d (New md files from RunPod) ### KS5: Çatışma Çözümü @@ -91,13 +127,21 @@ Bazı kaynaklar diğerlerinden daha yetkilidir. Gerçekler, kaynak belgelerinin ### KS7: Çıkarma Boru Hattı Karşılaştırması +<<<<<<< HEAD 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ı? +======= +Farklı çıkarma yöntemlerinin/sürümlerinin çıktılarını karşılaştırın. Aynı kaynaktan hangi çıkarıcı daha iyi gerçekler üretti? +>>>>>>> 82edf2d (New md files from RunPod) ## Entegrasyon Noktaları ### Kütüphaneci +<<<<<<< HEAD Kütüphaneci bileşeni, zaten benzersiz belge kimlikleriyle belge depolama imkanı sunmaktadır. Kaynak sistemi, bu mevcut altyapıyla entegre olmaktadır. +======= +Kütüphaneci bileşeni, zaten benzersiz belge kimlikleriyle belge depolama imkanı sunmaktadır. Kaynak sistemi, bu mevcut altyapıyla entegre edilmektedir. +>>>>>>> 82edf2d (New md files from RunPod) #### Mevcut Yetenekler (zaten uygulanan) @@ -119,8 +163,13 @@ Nesne kimlikleri (UUID'ler), blob depolama için dahili olarak oluşturulur `time` - zaman damgası, `kind` - MIME türü **Depolama Mimarisi:** +<<<<<<< HEAD Meta veriler, Cassandra'da saklanır (`librarian` anahtar alanı, `document` tablo) İçerik, MinIO/S3 blob depolamasında saklanır (`library` bucket) +======= +Meta veriler, Cassandra'da depolanır (`librarian` anahtar alanı, `document` tablo) +İçerik, MinIO/S3 blob depolamada depolanır (`library` bucket) +>>>>>>> 82edf2d (New md files from RunPod) 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 @@ -136,15 +185,26 @@ 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 +<<<<<<< HEAD 4. Bir gerçeğe geri dönen kaynaklara kadar tüm kaynak zincirini izlemek için bir sorgu API'si yoktur +======= +4. Bir gerçeğe geri dönen tam kaynak zincirini izlemek için bir sorgu API'si yoktur +>>>>>>> 82edf2d (New md files from RunPod) ## Uçtan Uca Akış Tasarımı Boru hattındaki her işlemci, tutarlı bir kalıbı izler: +<<<<<<< HEAD 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 +======= +Yukarıdan bir belge kimliği alınır +İçerik, kütüphaneciden alınır +Çocuk öğeler oluşturulur +Her çocuk için: kütüphaneciye kaydedilir, grafiğe bir kenar yollanır, kimlik aşağı akışa iletilir +>>>>>>> 82edf2d (New md files from RunPod) ### İşlem Akışları @@ -239,11 +299,19 @@ PDF: Document → Pages → Chunks → Triples/Embeddings Text: Document → Chunks → Triples/Embeddings ``` +<<<<<<< HEAD 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. +======= +Tasarım, her iki durumu da destekler çünkü parçalayıcı (chunker), girdisini genel olarak işler; aldığı belge kimliğini, bunun kaynak belge olup olmadığını veya bir sayfa olup olmadığını dikkate almadan, üst belge olarak kullanır. + +### Metaveri Şeması (PROV-O) + +Kaynak metaverileri, W3C PROV-O ontolojisini kullanır. Bu, standart bir kelime dağarcığı sağlar ve çıkarılan verilerin gelecekteki imzalama/kimlik doğrulamasını mümkün kılar. +>>>>>>> 82edf2d (New md files from RunPod) #### PROV-O Temel Kavramları @@ -275,7 +343,11 @@ doc:123 tg:pageCount 42 . doc:123 tg:mimeType "application/pdf" . ``` +<<<<<<< HEAD **Sayfa (PDF Çıkarıcı tarafından oluşturulmuştur):** +======= +**Sayfa (PDF Çıkarma Aracı tarafından oluşturulmuştur):** +>>>>>>> 82edf2d (New md files from RunPod) ``` page:123-1 a prov:Entity . page:123-1 prov:wasDerivedFrom doc:123 . @@ -306,7 +378,11 @@ activity:chunk-789 tg:chunkSize 2048 . activity:chunk-789 tg:chunkOverlap 200 . ``` +<<<<<<< HEAD **Üçlü (Knowledge Extractor tarafından üretildi):** +======= +**Üçlü (Bilgi Çıkarıcı tarafından üretildi):** +>>>>>>> 82edf2d (New md files from RunPod) ``` # The extracted triple (edge) entity:JohnSmith rel:worksAt entity:AcmeCorp . @@ -324,9 +400,15 @@ activity:extract-999 tg:llmModel "claude-3" . activity:extract-999 tg:ontology . ``` +<<<<<<< HEAD **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: +======= +**Gömme (vektör depolama alanında saklanır, üçlü depolama alanında değil):** + +Gömme verileri, RDF üçlüleri olarak değil, meta verilerle birlikte vektör depolama alanında saklanır. Her gömme kaydı şunları içerir: +>>>>>>> 82edf2d (New md files from RunPod) | Alan | Açıklama | Örnek | |-------|-------------|---------| @@ -336,6 +418,7 @@ Gömme verileri, RDF üçlüleri olarak değil, meta verilerle birlikte vektör | model | Kullanılan gömme modeli | `text-embedding-ada-002` | | component_version | TG gömme sürümü | `1.0.0` | +<<<<<<< HEAD `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 @@ -345,6 +428,17 @@ Gömme verileri, RDF üçlüleri olarak değil, meta verilerle birlikte vektör | Önek | Alan | Açıklama | |-----------|--------|-------------| | `tg:contains` | Alt Grafik | Bu çıkarma alt grafiğindeki bir üçlüye işaret eder | +======= +`entity` alanı, gömmeyi bilgi grafiğine (düğüm URI'si) bağlar. `chunk_id` alanı, orijinal belgeye kadar DAG üzerinde gezinmeyi sağlayan, kaynak parçaya ilişkin bilgileri sağlar. + +#### TrustGraph Ad Alanı Genişletmeleri + +Çıkarma ile ilgili meta veriler için `tg:` ad alanının altındaki özel önekler: + +| Önek | Alan | Açıklama | +|-----------|--------|-------------| +| `tg:contains` | Alt Grafik | Bu çıkarma alt grafiğinde bulunan bir üçlüye işaret eder | +>>>>>>> 82edf2d (New md files from RunPod) | `tg:pageCount` | Belge | Kaynak belgedeki toplam sayfa sayısı | | `tg:mimeType` | Belge | Kaynak belgenin MIME türü | | `tg:pageNumber` | Sayfa | Kaynak belgedeki sayfa numarası | @@ -363,7 +457,11 @@ Gömme verileri, RDF üçlüleri olarak değil, meta verilerle birlikte vektör #### Sözlük Başlatma (Her Koleksiyon İçin) +<<<<<<< HEAD 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. +======= +Bilgi grafiği, ontolojiye bağımlı olmayan ve başlangıçta boş durumdadı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. +>>>>>>> 82edf2d (New md files from RunPod) **PROV-O Sınıfları:** ``` @@ -401,7 +499,11 @@ tg:sourceCharOffset rdfs:label "source character offset" . tg:sourceCharLength rdfs:label "source character length" . ``` +<<<<<<< HEAD **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. +======= +**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. Koleksiyon içindeki ilk belge işleme sırasında veya ayrı bir koleksiyon başlatma adımı olarak tetiklenebilir. +>>>>>>> 82edf2d (New md files from RunPod) #### Alt Parça Kaynağı (İdeal) @@ -438,7 +540,11 @@ 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. +<<<<<<< HEAD Yapılandırılmış çıkarma yöntemleriyle serbest biçimli LLM çıkarma yöntemlerinden daha kolay uygulanabilir olabilir. +======= +Serbest biçimli LLM çıkarma yöntemlerine kıyasla yapılandırılmış çıkarma yöntemleriyle elde edilmesi daha kolay olabilir. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -446,6 +552,7 @@ Bu, iddialı bir hedef olarak işaretlenmiştir - temel parça düzeyindeki kayn Kaynak bilgisi DAG'ı, belgeler boru hattından geçerken kademeli olarak oluşturulur: +<<<<<<< HEAD | Depo | Neler Saklanır | Amaç | |-------|---------------|---------| | Kütüphaneci | Belge içeriği + ebeveyn-çocuk bağlantıları | İçerik alma, kaskad silme | @@ -454,6 +561,16 @@ Kaynak bilgisi DAG'ı, belgeler boru hattından geçerken kademeli olarak oluşt 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 +======= +| Depolama | Neler Depolanır | Amaç | +|-------|---------------|---------| +| Kütüphaneci | Belge içeriği + ebeveyn-çocuk bağlantıları | İçerik alma, zincirleme silme | +| Bilgi Grafiği | Ebeveyn-çocuk kenarları + meta veri | Kaynak bilgisi sorguları, gerçek ataması | + +Her iki depolama birimi de aynı DAG yapısını korur. Kütüphaneci içeriği tutarken, grafik ilişkileri tutar ve gezinme sorgularını sağlar. + +### Temel Tasarım İlkeleri +>>>>>>> 82edf2d (New md files from RunPod) 1. **Belge Kimliği akış birimi olarak** - İşleyiciler içeriği değil, kimlikleri iletir. İçerik gerektiğinde kütüphaneciden alınır. @@ -461,9 +578,15 @@ Her iki depo da aynı DAG yapısını korur. Kütüphaneci içeriği saklar; gra 3. **Tutarlı işlemci kalıbı** - Her işlemci aynı alım/alma/üretme/kaydetme/yayınlama/ileri gönderme kalıbını izler. +<<<<<<< HEAD 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. +======= +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üphaneci ile gereksiz geri dönüşleri önlerken, kimlik aracılığıyla kaynak bilgisini korur. +>>>>>>> 82edf2d (New md files from RunPod) ## Uygulama Görevleri @@ -472,21 +595,37 @@ Her iki depo da aynı DAG yapısını korur. Kütüphaneci içeriği saklar; gra #### Mevcut Durum Belge işleme işlemini başlatarak belge kimliğini ilk işlemciye gönderir. +<<<<<<< HEAD Üç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. +======= +Üçlü depolamaya bağlantı yok - meta veri, çıkarma çıktılarıyla birlikte paketlenir. +`add-child-document` tek düzeyli ebeveyn-çocuk bağlantıları oluşturur. +>>>>>>> 82edf2d (New md files from RunPod) `list-children` yalnızca hemen alt öğeleri döndürür. #### Gerekli Değişiklikler +<<<<<<< HEAD **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. +======= +**1. Yeni arayüz: Üçlü depolama 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ü depolama istemci/yayınlayıcısı ekleyin. +>>>>>>> 82edf2d (New md files from RunPod) İşleme başlatıldığında: kök belge meta verilerini grafik kenarları olarak (tek seferlik) yayınlayın. **2. Belge türü sözlüğü** +<<<<<<< HEAD Alt belgeler için `document_type` değerlerini standartlaştırın: +======= +Çocuk belgeler için `document_type` değerlerini standartlaştırın: +>>>>>>> 82edf2d (New md files from RunPod) `source` - orijinal olarak yüklenen belge `page` - kaynaktan (PDF, vb.) çıkarılan sayfa `chunk` - sayfadan veya kaynaktan türetilen metin parçası @@ -495,22 +634,35 @@ Alt belgeler için `document_type` değerlerini standartlaştırın: | Arayüz | Değişiklik | |-----------|--------| +<<<<<<< HEAD | Üç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 | +======= +| Üçlü depolama | 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 iletmeye devam etmeden önce | +>>>>>>> 82edf2d (New md files from RunPod) ### PDF Çıkarma Değişiklikleri #### Mevcut Durum +<<<<<<< HEAD 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 +======= +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ü depolamayla etkileşimde bulunmaz. +>>>>>>> 82edf2d (New md files from RunPod) #### Gerekli Değişiklikler **1. Yeni arayüz: Kütüphaneci istemcisi** +<<<<<<< HEAD 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 @@ -520,6 +672,17 @@ Her sayfa için: ebeveyn = kök belge kimliği ile `add-child-document`'yi çağ 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 +======= +PDF çıkarıcı, her sayfayı kütüphanecide bir çocuk belge olarak kaydetmelidir. +PDF çıkarıcı hizmetine kütüphaneci istemcisi ekleyin. +Her sayfa için: `add-child-document`'ı ebeveyn = kök belge kimliği ile çağırın. + +**2. Yeni arayüz: Üçlü depolama bağlantısı** + +PDF çıkarıcı, ebeveyn-çocuk kenarlarını bilgi grafiğine yayınlamalıdır. +Üçlü depolama istemci/yayınlayıcısı ekleyin. +Her sayfa için: sayfa belgesini ebeveyn belgeye bağlayan bir kenar yayınlayın. +>>>>>>> 82edf2d (New md files from RunPod) **3. Çıktı biçimini değiştirin** @@ -589,10 +752,17 @@ Parça içeriğini alır **1. Giriş işleme şeklini değiştirin** +<<<<<<< HEAD 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** +======= +Parça belge kimliğini içeriğin yanı sıra alın. +Köken bağlantısı için parça kimliğini kullanın (içerik zaten optimizasyon kapsamında dahil edilmiştir) + +**2. Üçlü kökenini güncelleyin** +>>>>>>> 82edf2d (New md files from RunPod) Çı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 diff --git a/docs/tech-specs/extraction-time-provenance.zh-cn.md b/docs/tech-specs/extraction-time-provenance.zh-cn.md index 6399f279..1c90bbea 100644 --- a/docs/tech-specs/extraction-time-provenance.zh-cn.md +++ b/docs/tech-specs/extraction-time-provenance.zh-cn.md @@ -10,14 +10,22 @@ ### 当前实现 +<<<<<<< HEAD 目前,数据来源的工作方式如下: +======= +当前的数据来源工作方式如下: +>>>>>>> 82edf2d (New md files from RunPod) 文档元数据以 RDF 三元组的形式存储在知识图谱中。 文档 ID 将元数据与文档关联起来,因此文档在图中显示为节点。 当从文档中提取出边(关系/事实)时,一个 `subjectOf` 关系将提取出的边链接回原始文档。 ### 当前方法的缺点 +<<<<<<< HEAD 1. **重复加载元数据:** 文档元数据会被打包并重复加载,每次从该文档中提取一批三元组时都会重复。这既浪费又冗余,相同的元数据会作为“货物”随每次提取输出一起传输。 +======= +1. **重复加载元数据:** 文档元数据被打包并重复加载,每次从该文档中提取一批三元组时都会重复。这既浪费又冗余,相同的元数据会作为“货物”随每次提取输出一起传输。 +>>>>>>> 82edf2d (New md files from RunPod) 2. **浅层数据来源:** 当前的 `subjectOf` 关系仅将事实直接链接到顶级文档。无法了解转换链,例如,该事实来自哪个页面,哪个块,使用了哪种提取方法。 @@ -25,7 +33,11 @@ 1. **一次加载元数据:** 文档元数据应该只加载一次,并附加到顶级文档节点,而不是重复包含在每个三元组批次中。 +<<<<<<< HEAD 2. **丰富的数据来源 DAG:** 捕获从原始文档到所有中间工件,再到提取出的事实的完整转换链。例如,一个 PDF 文档的转换过程: +======= +2. **丰富的数据来源 DAG:** 捕获从原始文档到所有中间工件再到提取事实的完整转换链。例如,一个 PDF 文档的转换过程: +>>>>>>> 82edf2d (New md files from RunPod) ``` PDF file (source document with metadata) @@ -40,11 +52,19 @@ → ... ``` +<<<<<<< HEAD 3. **统一存储:** 提取的知识及其来源信息(provenance)都存储在同一个知识图谱中。这使得对来源信息的查询方式与对知识的查询方式相同,即可以从任何事实出发,沿着链条追溯到其确切的来源位置。 4. **稳定的ID:** 每个中间产物(页面、段落)都具有一个稳定的ID,该ID在图中表示为一个节点。 5. **父子链接:** 从派生文档到其父文档,一直链接到顶层源文档,使用一致的关系类型。 +======= +3. **统一存储:** 提取的知识及其来源信息(provenance)都存储在同一个知识图谱中。这使得对来源信息的查询方式与对知识的查询方式相同——可以从任何事实出发,沿着链条追溯到其确切的来源位置。 + +4. **稳定的ID:** 每个中间产物(页面、段落)都有一个稳定的ID,作为图谱中的一个节点。 + +5. **父子链接:** 从派生文档到其父文档,一直链接到顶层原始文档,使用一致的关系类型。 +>>>>>>> 82edf2d (New md files from RunPod) 6. **精确的事实归属:** 提取的边上的 `subjectOf` 关系指向直接的父节点(段落),而不是顶层文档。可以通过遍历DAG来恢复完整的来源信息。 @@ -58,19 +78,29 @@ 1. 用户向GraphRAG代理提交查询。 2. 代理从知识图谱中检索相关的事实,以构建响应。 3. 根据查询时期的来源信息规范,代理报告哪些事实对响应做出了贡献。 +<<<<<<< HEAD 4. 每个事实通过来源信息DAG链接到其源段落。 5. 段落链接到页面,页面链接到源文档。 +======= +4. 每个事实通过来源信息DAG链接到其来源段落。 +5. 段落链接到页面,页面链接到原始文档。 +>>>>>>> 82edf2d (New md files from RunPod) **用户体验结果:** 界面会显示LLM响应以及来源归属信息。用户可以: 查看哪些事实支持了响应。 从事实 → 段落 → 页面 → 文档进行深入了解。 +<<<<<<< HEAD 浏览原始的源文档以验证声明。 +======= +浏览原始来源文档以验证声明。 +>>>>>>> 82edf2d (New md files from RunPod) 准确了解事实的来源(哪个页面,哪个部分)。 **价值:** 用户可以根据原始来源验证AI生成的响应,从而建立信任并实现事实核查。 ### UC2:调试提取质量 +<<<<<<< HEAD 某个事实看起来不正确。追溯到段落 → 页面 → 文档,查看原始文本。是提取出现问题,还是原始来源本身就是错误的? ### UC3:增量重提取 @@ -84,6 +114,21 @@ ### UC5:冲突解决 两个事实相互矛盾。追溯到它们的来源,以了解原因并决定应该信任哪个(更权威的来源、更新的来源等)。 +======= +某个事实看起来不正确。追溯到段落 → 页面 → 文档,查看原始文本。是提取过程出现问题,还是原始来源本身就是错误的? + +### UC3:增量重提取 + +原始文档被更新。哪些段落/事实是从它派生的?仅使这些段落/事实失效并重新生成,而不是重新处理所有内容。 + +### UC4:数据删除/被遗忘的权利 + +必须删除一个原始文档(GDPR、法律等)。遍历DAG以查找并删除所有派生的事实。 + +### UC5:冲突解决 + +两个事实相互矛盾。追溯到它们的来源,以了解原因,并决定应该信任哪个(更权威的来源、更新的来源等)。 +>>>>>>> 82edf2d (New md files from RunPod) ### UC6:来源权威性加权 @@ -91,7 +136,11 @@ ### UC7:提取管道比较 +<<<<<<< HEAD 比较来自不同提取方法/版本的输出。哪个提取器从相同的来源生成了更好的事实? +======= +比较不同提取方法/版本的输出。哪个提取器从相同的来源生成了更好的事实? +>>>>>>> 82edf2d (New md files from RunPod) ## 集成点 @@ -102,6 +151,7 @@ librarian组件已经提供了文档存储,并具有唯一的文档ID。来源 #### 现有功能(已实现) **父子文档链接:** +<<<<<<< HEAD `parent_id` 字段在 `DocumentMetadata` 中 - 将子文档链接到父文档。 `document_type` 字段 - 值:`"source"`(原始)或 `"extracted"`(派生)。 `add-child-document` API - 创建具有自动 `document_type = "extracted"` 的子文档。 @@ -137,10 +187,48 @@ librarian 具有构建块,但目前: 2. 没有标准的关系类型词汇表(例如,`derivedFrom`、`extractedFrom`)。 3. 来源信息元数据(提取方法、置信度、段落位置)尚未标准化。 4. 没有查询API来遍历从事实到源的全程来源信息链。 +======= +`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` keyspace,`document` table) +内容存储在MinIO/S3 blob存储中(`library` bucket) +智能内容交付:小于 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来遍历从事实到原始来源的完整来源信息链 +>>>>>>> 82edf2d (New md files from RunPod) ## 端到端流程设计 管道中的每个处理器都遵循一致的模式: +<<<<<<< HEAD 从上游接收文档ID。 从librarian中获取内容。 生成子产物。 @@ -149,6 +237,16 @@ librarian 具有构建块,但目前: ### 处理流程 有两个流程,具体取决于文档类型: +======= +从上游接收文档ID +从librarian中获取内容 +生成子产物 +对于每个子产物:保存到librarian,向图发出边,向下游传递ID + +### 处理流程 + +根据文档类型,有两种流程: +>>>>>>> 82edf2d (New md files from RunPod) #### PDF文档流程 @@ -363,7 +461,11 @@ activity:extract-999 tg:ontology . #### 词汇引导 (每个集合) +<<<<<<< HEAD 知识图谱是本体无关的,并且初始化为空。 当首次将 PROV-O provenance 数据写入集合时,必须使用 RDF 标签引导所有类和谓词的词汇。 这可确保在查询和 UI 中提供人类可读的显示。 +======= +知识图谱是本体无关的,并且初始化为空。当首次将 PROV-O provenance 数据写入集合时,必须使用 RDF 标签引导所有类和谓词的词汇。这可确保在查询和 UI 中提供人类可读的显示。 +>>>>>>> 82edf2d (New md files from RunPod) **PROV-O 类:** ``` @@ -372,7 +474,11 @@ prov:Activity rdfs:label "Activity" . prov:Agent rdfs:label "Agent" . ``` +<<<<<<< HEAD **PROV-O谓词:** +======= +**PROV-O 谓词:** +>>>>>>> 82edf2d (New md files from RunPod) ``` prov:wasDerivedFrom rdfs:label "was derived from" . prov:wasGeneratedBy rdfs:label "was generated by" . @@ -401,11 +507,19 @@ tg:sourceCharOffset rdfs:label "source character offset" . tg:sourceCharLength rdfs:label "source character length" . ``` +<<<<<<< HEAD **实施说明:** 这个词汇库初始化应该具有幂等性,即可以多次运行而不会创建重复项。 它可以触发在集合中的第一个文档处理过程中,或者作为单独的集合初始化步骤。 #### 子块来源信息(期望) 为了获得更细粒度的来源信息,记录三元组是从块中的哪个位置提取出来的将非常有用。 这可以实现: +======= +**实施说明:** 此词汇引导过程应具有幂等性,即可以多次运行而不会创建重复项。 可以在集合中的首次文档处理过程中触发,也可以作为单独的集合初始化步骤。 + +#### 子块来源信息(期望) + +为了获得更精细的来源信息,记录三元组是从块中的哪个位置提取出来的将非常有用。 这可以实现: +>>>>>>> 82edf2d (New md files from RunPod) 在用户界面中突出显示确切的原始文本 验证提取的准确性与原始文本 @@ -432,6 +546,7 @@ subgraph:001 tg:sourceRange "1547-1593" . subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . ``` +<<<<<<< HEAD **实现注意事项:** 基于 LLM 的提取可能无法自然地提供字符位置。 @@ -441,6 +556,17 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . 使用结构化提取方法可能更容易实现,而不是使用自由形式的 LLM 提取。 这被标记为期望目标 - 首先应实现基本的块级溯源,如果可行,子块跟踪可以作为未来的增强功能。 +======= +**实现注意事项:** + +基于 LLM 的提取可能无法自然地提供字符位置 +可以提示 LLM 同时返回提取的三元组以及原始句子/短语 +或者,可以进行后处理,将提取的实体模糊匹配回原始文本 +提取复杂度和溯源粒度之间的权衡 +使用结构化提取方法可能更容易实现,而不是使用自由形式的 LLM 提取 + +这被标记为期望目标 - 首先应该实现基本的块级溯源,如果可行,子块跟踪可以作为未来的增强功能。 +>>>>>>> 82edf2d (New md files from RunPod) ### 双重存储模型 @@ -451,12 +577,17 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . | Librarian | 文档内容 + 父子链接 | 内容检索、级联删除 | | Knowledge Graph | 父子边 + 元数据 | 溯源查询、事实归属 | +<<<<<<< HEAD 两个存储都维护相同的 DAG 结构。 Librarian 存储内容;Graph 存储关系,并支持遍历查询。 +======= +两个存储都维护相同的 DAG 结构。 Librarian 存储内容;Knowledge Graph 存储关系,并支持遍历查询。 +>>>>>>> 82edf2d (New md files from RunPod) ### 关键设计原则 1. **文档 ID 作为流动的单位** - 处理程序传递 ID,而不是内容。 需要时从 Librarian 检索内容。 +<<<<<<< HEAD 2. **在源头一次发出** - 元数据在处理开始时写入到 Graph 中,而不是在下游重复。 3. **一致的处理程序模式** - 每个处理程序都遵循相同的接收/检索/生成/保存/发出/转发模式。 @@ -464,6 +595,15 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . 4. **渐进的 DAG 构建** - 每个处理程序添加其级别到 DAG 中。 完整的溯源链是逐步构建的。 5. **分块后优化** - 在分块之后,消息同时携带 ID 和内容。 块很小(2-4KB),因此包含内容可以避免不必要的 Librarian 往返,同时通过 ID 保持溯源。 +======= +2. **在源头一次发出** - 元数据在处理开始时写入 Knowledge Graph 一次,而不是在下游重复。 + +3. **一致的处理程序模式** - 每个处理程序都遵循相同的接收/检索/生成/保存/发出/转发模式。 + +4. **渐进式 DAG 构建** - 每个处理程序添加其级别到 DAG。 完整的溯源链是逐步构建的。 + +5. **分块后优化** - 在分块之后,消息同时携带 ID 和内容。 块很小(2-4KB),因此包含内容可以避免不必要的 Librarian 交互,同时通过 ID 保持溯源。 +>>>>>>> 82edf2d (New md files from RunPod) ## 实现任务 @@ -471,47 +611,79 @@ subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" . #### 当前状态 +<<<<<<< HEAD 通过将文档 ID 发送到第一个处理程序来启动文档处理。 没有连接到三元存储 - 元数据与提取输出一起打包。 `add-child-document` 创建一级父子链接。 `list-children` 仅返回直接子节点。 +======= +通过将文档 ID 发送到第一个处理程序来启动文档处理 +没有连接到三元存储 - 元数据与提取输出一起打包 +`add-child-document` 创建一级父子链接 +`list-children` 仅返回直接子节点 +>>>>>>> 82edf2d (New md files from RunPod) #### 需要的更改 **1. 新接口:三元存储连接** +<<<<<<< HEAD Librarian 需要直接将文档元数据边发射到知识图谱,以在启动处理时进行操作。 向 Librarian 服务添加三元存储客户端/发布器。 在处理启动时:以图谱边的方式(一次)发射根文档元数据。 +======= +Librarian 需要直接将文档元数据边发射到 Knowledge Graph,以在启动处理时。 +向 Librarian 服务添加三元存储客户端/发布器 +在处理启动时:以图边形式(一次)发射根文档元数据 +>>>>>>> 82edf2d (New md files from RunPod) **2. 文档类型词汇表** 标准化子文档的 `document_type` 值: +<<<<<<< HEAD `source` - 原始上传的文档。 `page` - 从源头提取的页面(PDF 等)。 `chunk` - 从页面或源头派生的文本块。 +======= +`source` - 原始上传的文档 +`page` - 从源文件(PDF 等)提取的页面 +`chunk` - 从页面或源文件派生的文本块 +>>>>>>> 82edf2d (New md files from RunPod) #### 接口更改摘要 | 接口 | 更改 | |-----------|--------| +<<<<<<< HEAD | 三元存储 | 新的出站连接 - 发射文档元数据边 | | 处理启动 | 在转发文档 ID 之前,向图谱发射元数据 | +======= +| 三元存储 | 新的外部连接 - 发射文档元数据边 | +| 处理启动 | 在转发文档 ID 之前,向图发射元数据 | +>>>>>>> 82edf2d (New md files from RunPod) ### PDF 提取器更改 #### 当前状态 +<<<<<<< HEAD 接收文档内容(或流式传输大型文档)。 从 PDF 页面提取文本。 将页面内容转发到分块器。 没有与 Librarian 或三元存储交互。 +======= +接收文档内容(或流式传输大型文档) +从 PDF 页面提取文本 +将页面内容转发到分块器 +没有与 Librarian 或三元存储交互 +>>>>>>> 82edf2d (New md files from RunPod) #### 需要的更改 **1. 新接口:Librarian 客户端** PDF 提取器需要将每个页面作为子文档保存到 Librarian 中。 +<<<<<<< HEAD 向 PDF 提取器服务添加 Librarian 客户端。 对于每个页面:使用父文档 ID 调用 `add-child-document`。 @@ -520,6 +692,16 @@ PDF 提取器需要将每个页面作为子文档保存到 Librarian 中。 PDF 提取器需要将父子边发射到知识图谱。 添加三元存储客户端/发布器。 对于每个页面:发射一个链接页面文档到父文档的边。 +======= +向 PDF 提取器服务添加 Librarian 客户端 +对于每个页面:使用父文档 ID 调用 `add-child-document` + +**2. 新接口:三元存储连接** + +PDF 提取器需要将父子边发射到 Knowledge Graph。 +添加三元存储客户端/发布器 +对于每个页面:发射将页面文档链接到父文档的边 +>>>>>>> 82edf2d (New md files from RunPod) **3. 更改输出格式** @@ -551,7 +733,11 @@ Chunker 将使用 ID 从 librarian 获取内容 向 chunker 服务添加 librarian 客户端 使用文档 ID 获取页面内容 +<<<<<<< HEAD **2. 新接口:Librarian 客户端(写入)** +======= +**2. 新接口:Librarian 客户端 (写入)** +>>>>>>> 82edf2d (New md files from RunPod) 将每个块保存为 librarian 中的子文档。 对于每个块:使用 parent = 页面文档 ID 调用 `add-child-document` @@ -572,7 +758,11 @@ Chunker 将使用 ID 从 librarian 获取内容 | 接口 | 变更 | |-----------|--------| | 输入消息 | 从内容更改为文档 ID | +<<<<<<< HEAD | Librarian | 新的输出(读取 + 写入)- 获取内容,保存子文档 | +======= +| Librarian | 新的输出 (读取 + 写入) - 获取内容,保存子文档 | +>>>>>>> 82edf2d (New md files from RunPod) | Triple store | 新的输出 - 发射父子边 | | 输出消息 | 从仅包含内容更改为 ID + 内容 | @@ -583,18 +773,30 @@ Chunker 将使用 ID 从 librarian 获取内容 接收块内容 提取三元组和嵌入 发送到 triple store 和 embedding store +<<<<<<< HEAD `subjectOf` 关系指向顶级文档(不是块) +======= +`subjectOf` 关系指向顶级文档 (而不是块) +>>>>>>> 82edf2d (New md files from RunPod) #### 必需的变更 **1. 更改输入处理** 接收块文档 ID 以及内容。 +<<<<<<< HEAD 使用块 ID 用于溯源链接(内容已包含在优化中) **2. 更新三元组溯源** 将提取的三元组链接到块(而不是顶级文档)。 +======= +使用块 ID 用于溯源链接 (内容已包含在优化中) + +**2. 更新三元组溯源** + +将提取的三元组链接到块 (而不是顶级文档)。 +>>>>>>> 82edf2d (New md files from RunPod) 使用重构来创建指向边的边 `subjectOf` 关系:三元组 → 块文档 ID 首次使用现有的重构支持 @@ -608,7 +810,11 @@ Chunker 将使用 ID 从 librarian 获取内容 | 接口 | 变更 | |-----------|--------| +<<<<<<< HEAD | 输入消息 | 期望块 ID + 内容(不是仅包含内容) | +======= +| 输入消息 | 期望块 ID + 内容 (而不是仅包含内容) | +>>>>>>> 82edf2d (New md files from RunPod) | Triple store | 使用重构进行三元组 → 块溯源 | | 嵌入溯源 | 将实体 ID 链接到块 ID | @@ -616,4 +822,8 @@ Chunker 将使用 ID 从 librarian 获取内容 查询时溯源:`docs/tech-specs/query-time-provenance.md` PROV-O 标准用于溯源建模 +<<<<<<< HEAD 知识图谱中现有的源元数据(需要审计) +======= +知识图谱中现有的源元数据 (需要审计) +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/flow-class-definition.ar.md b/docs/tech-specs/flow-class-definition.ar.md index df048c86..2fb44171 100644 --- a/docs/tech-specs/flow-class-definition.ar.md +++ b/docs/tech-specs/flow-class-definition.ar.md @@ -1,4 +1,8 @@ +<<<<<<< HEAD # مواصفات تعريف مخطط التدفق +======= +# تعريف مواصفات مخطط التدفق +>>>>>>> 82edf2d (New md files from RunPod) ## نظرة عامة @@ -113,12 +117,20 @@ #### {id} يتم استبدالها بمعرّف مثيل التدفق الفريد. +<<<<<<< HEAD تقوم بإنشاء موارد معزولة لكل تدفق. +======= +تنشئ موارد معزولة لكل تدفق. +>>>>>>> 82edf2d (New md files from RunPod) مثال: `flow-123`، `customer-A-flow` #### {class} يتم استبدالها باسم مخطط التدفق. +<<<<<<< HEAD تقوم بإنشاء موارد مشتركة عبر التدفقات من نفس الفئة. +======= +تنشئ موارد مشتركة عبر التدفقات من نفس الفئة. +>>>>>>> 82edf2d (New md files from RunPod) مثال: `standard-rag`، `enterprise-rag` ### متغيرات المعلمات @@ -201,9 +213,15 @@ } ``` +<<<<<<< HEAD ## أنماط قائمة الانتظار (بالمسر) تستخدم مخططات التدفق Apache Pulsar للرسائل. تتبع أسماء قوائم الانتظار تنسيق بالمسر: +======= +## أنماط قائمة الانتظار (بالمار) + +تستخدم مخططات التدفق Apache Pulsar للرسائل. تتبع أسماء قوائم الانتظار تنسيق بالمار: +>>>>>>> 82edf2d (New md files from RunPod) ``` ://// ``` @@ -239,7 +257,11 @@ 3. **الخدمات المشتركة**: معالجات مركزية يمكن لجميع التدفقات استخدامها 4. **كتابة التخزين**: تحفظ البيانات المعالجة في المخازن المناسبة +<<<<<<< HEAD تعمل جميع المعالجات (سواء `{id}` و `{class}`) معًا كرسوم بيانية لتدفق بيانات متماسك، وليس كأنظمة منفصلة. +======= +تعمل جميع المعالجات (سواء `{id}` و `{class}`) معًا كرسوم بيانية لتدفق البيانات المتكاملة، وليس كأنظمة منفصلة. +>>>>>>> 82edf2d (New md files from RunPod) ## مثال على إنشاء التدفق @@ -255,7 +277,11 @@ `temp`: `0.5` `chunk`: `512` +<<<<<<< HEAD التوسعات القالبية: +======= +توسعات القالب: +>>>>>>> 82edf2d (New md files from RunPod) `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"` diff --git a/docs/tech-specs/flow-class-definition.es.md b/docs/tech-specs/flow-class-definition.es.md index 5c77a230..1b91d127 100644 --- a/docs/tech-specs/flow-class-definition.es.md +++ b/docs/tech-specs/flow-class-definition.es.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD # Especificación de la Definición del Esquema de Flujo ## Resumen @@ -10,6 +11,20 @@ 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. +======= +# Especificación de la Definición de la Hoja de Flujo + +## Resumen + +Una hoja 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 hoja de flujo consta de cinco secciones principales: + +### 1. Sección de Clase +Define procesadores de servicios compartidos que se instancian una vez por hoja de flujo. Estos procesadores manejan las solicitudes de todas las instancias de flujo de esta clase. +>>>>>>> 82edf2d (New md files from RunPod) ```json "class": { @@ -235,7 +250,11 @@ Ejemplo: `non-persistent://tg/request/embeddings:{class}` 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 +<<<<<<< HEAD 2. **Servicios de Consulta**: Procesadores integrados que consultan las mismas bases de datos y servicios +======= +2. **Servicios de Consulta**: Procesadores integrados que consultan las mismas fuentes de datos y servicios +>>>>>>> 82edf2d (New md files from RunPod) 3. **Servicios Compartidos**: Procesadores centralizados que todos los flujos pueden utilizar 4. **Escritores de Almacenamiento**: Persisten los datos procesados en los almacenes apropiados diff --git a/docs/tech-specs/flow-class-definition.he.md b/docs/tech-specs/flow-class-definition.he.md index 2ba61e83..fe90a2a7 100644 --- a/docs/tech-specs/flow-class-definition.he.md +++ b/docs/tech-specs/flow-class-definition.he.md @@ -1,4 +1,8 @@ +<<<<<<< HEAD # הגדרת מפרט תוכנית זרימה +======= +# מפרט הגדרת תוכנית זרימה +>>>>>>> 82edf2d (New md files from RunPod) ## סקירה כללית @@ -9,7 +13,11 @@ הגדרת תוכנית זרימה מורכבת מחמש קטעים עיקריים: ### 1. קטע מחלקה +<<<<<<< HEAD מגדיר מעבדי שירות משותפים המופעלים פעם אחת לכל תוכנית זרימה. מעבדים אלה מטפלים בבקשות מכל מופעי הזרימה של מחלקה זו. +======= +מגדיר מעבדים משותפים המופעלים פעם אחת לכל תוכנית זרימה. מעבדים אלה מטפלים בבקשות מכל מופעי הזרימה של מחלקה זו. +>>>>>>> 82edf2d (New md files from RunPod) ```json "class": { @@ -32,7 +40,11 @@ דוגמאות: `embeddings:{class}`, `text-completion:{class}`, `graph-rag:{class}` ### 2. סעיף זרימה +<<<<<<< HEAD מגדיר מעבדים ספציפיים לזרימה, אשר מופעלים עבור כל מופע זרימה בודד. לכל זרימה יש סט נפרד משלה של מעבדים אלה. +======= +מגדיר מעבדים ספציפיים לזרימה אשר מופעלים עבור כל מופע זרימה בודד. לכל זרימה יש סט נפרד משלה של מעבדים אלה. +>>>>>>> 82edf2d (New md files from RunPod) ```json "flow": { @@ -59,7 +71,11 @@ ממשקים יכולים לקבל שתי צורות: +<<<<<<< HEAD **תבנית "שלח ושכח"** (תור יחיד): +======= +**תבנית "שלח והשכח"** (תור יחיד): +>>>>>>> 82edf2d (New md files from RunPod) ```json "interfaces": { "document-load": "persistent://tg/flow/document-load:{id}", @@ -78,9 +94,15 @@ ``` **סוגי ממשקים:** +<<<<<<< HEAD **נקודות כניסה:** נקודות שבהן מערכות חיצוניות מזריקות נתונים (`document-load`, `agent`) **ממשקי שירות:** תבניות בקשה/תגובה עבור שירותים (`embeddings`, `text-completion`) **ממשקי נתונים:** נקודות חיבור לזרימת נתונים מסוג "שלח וסגור" (`triples-store`, `entity-contexts-load`) +======= +**נקודות כניסה:** נקודות בהן מערכות חיצוניות מזריקות נתונים (`document-load`, `agent`) +**ממשקי שירות:** תבניות בקשה/תגובה עבור שירותים (`embeddings`, `text-completion`) +**ממשקי נתונים:** נקודות חיבור לזרימת נתונים מסוג "שלח ושים" (`triples-store`, `entity-contexts-load`) +>>>>>>> 82edf2d (New md files from RunPod) ### 4. סעיף פרמטרים ממפה שמות פרמטרים ספציפיים לזרימה להגדרות פרמטרים המאוחסנות באופן מרכזי: @@ -129,7 +151,11 @@ משמש בהגדרות של מעבדים כדי להתאים אישית את ההתנהגות דוגמאות: `{model}`, `{temp}`, `{chunk}` מוחלף בערכים המסופקים בעת הפעלת ה-flow +<<<<<<< HEAD מאומתים מול הגדרות פרמטרים המאוחסנות באופן מרכזי +======= +מאומתים מול הגדרות פרמטרים המאוחסנות במרכז +>>>>>>> 82edf2d (New md files from RunPod) ## הגדרות מעבד @@ -213,19 +239,32 @@ **tenant**: `tg` עבור הגדרות תבניות זרימה המסופקות על ידי TrustGraph **namespace**: מציין את דפוס העברת ההודעות `flow`: שירותים מסוג "שלח וגע" (fire-and-forget) +<<<<<<< HEAD `request`: החלק של הבקשה בשירותי בקשה/תגובה (request/response) `response`: החלק של התגובה בשירותי בקשה/תגובה (request/response) +======= + `request`: החלק של הבקשה בשירותי "בקשה/תגובה" (request/response) + `response`: החלק של התגובה בשירותי "בקשה/תגובה" (request/response) +>>>>>>> 82edf2d (New md files from RunPod) **topic**: שם התור/נושא הספציפי עם משתני תבנית ### תורים קבועים (Persistent Queues) דפוס: `persistent://tg/flow/:{id}` משמש עבור שירותים מסוג "שלח וגע" וזרימת נתונים עמידה +<<<<<<< HEAD הנתונים נשמרים באחסון של Pulsar בין הפעלות מחדש +======= +הנתונים נשמרים באחסון של Pulsar גם לאחר אתחולים מחדש +>>>>>>> 82edf2d (New md files from RunPod) דוגמה: `persistent://tg/flow/chunk-load:{id}` ### תורים לא קבועים (Non-Persistent Queues) דפוס: `non-persistent://tg/request/:{class}` או `non-persistent://tg/response/:{class}` +<<<<<<< HEAD משמש עבור דפוסי העברת הודעות מסוג בקשה/תגובה +======= +משמש עבור דפוסי העברת הודעות מסוג "בקשה/תגובה" +>>>>>>> 82edf2d (New md files from RunPod) זמני, אינו נשמר בדיסק על ידי Pulsar השהיה נמוכה יותר, מתאים לתקשורת בסגנון RPC דוגמה: `non-persistent://tg/request/embeddings:{class}` @@ -263,7 +302,11 @@ `"chunk_size": "{chunk}"` → `"chunk_size": "512"` זה יוצר: +<<<<<<< HEAD צינור עיבוד מסמכים נפרד עבור `customer-A-flow` +======= +צינור עיבוד מסמכים מבודד עבור `customer-A-flow` +>>>>>>> 82edf2d (New md files from RunPod) שירות הטמעה משותף עבור כל זרימות `standard-rag` זרימת נתונים שלמה מאיסוף מסמכים דרך שאילתות מעבדים מוגדרים עם ערכי הפרמטרים שסופקו diff --git a/docs/tech-specs/flow-class-definition.hi.md b/docs/tech-specs/flow-class-definition.hi.md index efd9db77..1d1fdb83 100644 --- a/docs/tech-specs/flow-class-definition.hi.md +++ b/docs/tech-specs/flow-class-definition.hi.md @@ -9,7 +9,11 @@ एक फ्लो ब्लूप्रिंट परिभाषा में पाँच मुख्य अनुभाग होते हैं: ### 1. क्लास अनुभाग +<<<<<<< HEAD यह साझा सेवा प्रोसेसर को परिभाषित करता है जिन्हें प्रत्येक फ्लो ब्लूप्रिंट के लिए एक बार इंस्टेंट किया जाता है। ये प्रोसेसर इस क्लास के सभी फ्लो उदाहरणों से अनुरोधों को संभालते हैं। +======= +साझा सेवा प्रोसेसर को परिभाषित करता है जिन्हें प्रत्येक फ्लो ब्लूप्रिंट के लिए एक बार इंस्टेंट किया जाता है। ये प्रोसेसर इस क्लास के सभी फ्लो उदाहरणों से अनुरोधों को संभालते हैं। +>>>>>>> 82edf2d (New md files from RunPod) ```json "class": { @@ -27,7 +31,11 @@ **विशेषताएं:** समान वर्ग के सभी फ्लो उदाहरणों में साझा किया जाता है। आमतौर पर महंगी या स्टेटलेस सेवाएं (एलएलएम, एम्बेडिंग मॉडल)। +<<<<<<< HEAD कतार नामकरण के लिए `{class}` टेम्पलेट वेरिएबल का उपयोग करें। +======= +क्यू नामकरण के लिए `{class}` टेम्पलेट वेरिएबल का उपयोग करें। +>>>>>>> 82edf2d (New md files from RunPod) सेटिंग्स निश्चित मान हो सकती हैं या `{parameter-name}` सिंटैक्स के साथ पैरामीटराइज़ की जा सकती हैं। उदाहरण: `embeddings:{class}`, `text-completion:{class}`, `graph-rag:{class}` @@ -55,7 +63,11 @@ उदाहरण: `chunker:{id}`, `pdf-decoder:{id}`, `kg-extract-relationships:{id}` ### 3. इंटरफेस अनुभाग +<<<<<<< HEAD यह प्रवाह के लिए प्रवेश बिंदुओं और इंटरैक्शन अनुबंधों को परिभाषित करता है। ये बाहरी प्रणालियों और आंतरिक घटक संचार के लिए एपीआई सतह बनाते हैं। +======= +यह प्रवाह के लिए प्रवेश बिंदु और इंटरैक्शन अनुबंधों को परिभाषित करता है। ये बाहरी प्रणालियों और आंतरिक घटक संचार के लिए एपीआई सतह बनाते हैं। +>>>>>>> 82edf2d (New md files from RunPod) इंटरफेस दो रूप ले सकते हैं: @@ -146,7 +158,11 @@ ``` ### पैरामीटराइज़्ड सेटिंग्स +<<<<<<< HEAD वे मान जो प्रवाह शुरू करते समय प्रदान किए गए पैरामीटर का उपयोग करते हैं: +======= +वे मान जो फ्लो शुरू करते समय प्रदान किए गए पैरामीटर का उपयोग करते हैं: +>>>>>>> 82edf2d (New md files from RunPod) ```json "settings": { "model": "{model}", @@ -210,7 +226,11 @@ ### घटक: **स्थायित्व**: `persistent` या `non-persistent` (पल्सर स्थायित्व मोड) +<<<<<<< HEAD **किरायेदार**: ट्रस्टग्राफ द्वारा प्रदान किए गए प्रवाह ब्लूप्रिंट परिभाषाओं के लिए `tg` +======= +**किरायेदार**: ट्रस्टग्राफ द्वारा प्रदान किए गए फ़्लो ब्लूप्रिंट परिभाषाओं के लिए `tg` +>>>>>>> 82edf2d (New md files from RunPod) **नामस्थान**: यह संदेश पैटर्न को इंगित करता है `flow`: फायर-एंड-फॉरगेट सेवाएं `request`: अनुरोध/प्रतिक्रिया सेवाओं का अनुरोध भाग @@ -232,11 +252,16 @@ ## डेटाफ्लो आर्किटेक्चर +<<<<<<< HEAD प्रवाह ब्लूप्रिंट एक एकीकृत डेटाफ्लो बनाता है जहां: +======= +फ़्लो ब्लूप्रिंट एक एकीकृत डेटाफ्लो बनाता है जहां: +>>>>>>> 82edf2d (New md files from RunPod) 1. **दस्तावेज़ प्रसंस्करण पाइपलाइन**: अंतर्ग्रहण से लेकर परिवर्तन और भंडारण तक का प्रवाह 2. **क्वेरी सेवाएं**: एकीकृत प्रोसेसर जो समान डेटा स्टोर और सेवाओं को क्वेरी करते हैं 3. **साझा सेवाएं**: केंद्रीय प्रोसेसर जिनका उपयोग सभी प्रवाह कर सकते हैं +<<<<<<< HEAD 4. **भंडारण लेखक**: संसाधित डेटा को उपयुक्त स्टोर में सहेजें सभी प्रोसेसर (दोनों `{id}` और `{class}`) एक सुसंगत डेटाफ्लो ग्राफ के रूप में एक साथ काम करते हैं, अलग-अलग सिस्टम के रूप में नहीं। @@ -247,6 +272,18 @@ प्रवाह उदाहरण आईडी: `customer-A-flow` प्रवाह ब्लूप्रिंट: `standard-rag` प्रवाह पैरामीटर मैपिंग: +======= +4. **भंडारण लेखक**: संसाधित डेटा को उपयुक्त स्टोर में संग्रहीत करते हैं + +सभी प्रोसेसर (दोनों `{id}` और `{class}`) एक सुसंगत डेटाफ्लो ग्राफ के रूप में एक साथ काम करते हैं, अलग-अलग सिस्टम के रूप में नहीं। + +## उदाहरण फ़्लो इंस्टेंशिएशन + +दिया गया: +फ़्लो इंस्टेंस आईडी: `customer-A-flow` +फ़्लो ब्लूप्रिंट: `standard-rag` +फ़्लो पैरामीटर मैपिंग: +>>>>>>> 82edf2d (New md files from RunPod) `"model": "llm-model"` `"temp": "temperature"` `"chunk": "chunk-size"` @@ -271,7 +308,13 @@ ## लाभ 1. **संसाधन दक्षता**: महंगी सेवाओं को प्रवाह में साझा किया जाता है +<<<<<<< HEAD 2. **प्रवाह अलगाव**: प्रत्येक प्रवाह का अपना डेटा प्रसंस्करण पाइपलाइन होता है 3. **मापनीयता**: एक ही टेम्पलेट से कई प्रवाहों को कार्यान्वित किया जा सकता है 4. **मॉड्यूलरिटी**: साझा और प्रवाह-विशिष्ट घटकों के बीच स्पष्ट अलगाव +======= +2. **फ़्लो अलगाव**: प्रत्येक फ़्लो का अपना डेटा प्रसंस्करण पाइपलाइन होता है +3. **मापनीयता**: एक ही टेम्पलेट से कई फ़्लो को इंस्टेंशिएट किया जा सकता है +4. **मॉड्यूलरिटी**: साझा और फ़्लो-विशिष्ट घटकों के बीच स्पष्ट अलगाव +>>>>>>> 82edf2d (New md files from RunPod) 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 index 6efb4c38..cca8fd61 100644 --- a/docs/tech-specs/flow-class-definition.pt.md +++ b/docs/tech-specs/flow-class-definition.pt.md @@ -26,7 +26,11 @@ Define processadores de serviço compartilhados que são instanciados uma vez po **Características:** Compartilhadas entre todas as instâncias de fluxo da mesma classe. +<<<<<<< HEAD Normalmente, serviços caros ou sem estado (LLMs, modelos de embedding). +======= +Normalmente, serviços com alto custo ou sem estado (LLMs, modelos de embedding). +>>>>>>> 82edf2d (New md files from RunPod) 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}`. @@ -50,12 +54,21 @@ Define processadores específicos do fluxo que são instanciados para cada inst **Características:** Instância única por fluxo Gerenciar dados e estado específicos do fluxo +<<<<<<< HEAD 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. +======= +Usar variável de modelo `{id}` para nomeação de fila +As configurações podem ser valores fixos ou parametrizadas 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 de componentes internos. +>>>>>>> 82edf2d (New md files from RunPod) As interfaces podem assumir duas formas: @@ -112,7 +125,11 @@ Informações adicionais sobre o blueprint do fluxo: ### Variáveis do Sistema #### {id} +<<<<<<< HEAD Substituído pelo identificador de instância de fluxo único. +======= +Substituído pelo identificador único da instância do fluxo. +>>>>>>> 82edf2d (New md files from RunPod) Cria recursos isolados para cada fluxo. Exemplo: `flow-123`, `customer-A-flow` @@ -210,7 +227,11 @@ Os modelos de fluxo utilizam o Apache Pulsar para mensagens. Os nomes das filas ### Componentes: **persistência**: `persistent` ou `non-persistent` (modo de persistência do Pulsar) +<<<<<<< HEAD **inquilino**: `tg` para definições de blueprint de fluxo fornecidas pelo TrustGraph +======= +**inquilino**: `tg` para definições de blueprint de fluxo fornecidas pela TrustGraph +>>>>>>> 82edf2d (New md files from RunPod) **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 @@ -234,10 +255,17 @@ Exemplo: `non-persistent://tg/request/embeddings:{class}` O blueprint do fluxo cria um fluxo de dados unificado onde: +<<<<<<< HEAD 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 +======= +1. **Pipeline de Processamento de Documentos**: Fluxo da ingestão ao armazenamento, passando pela transformação +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 nos armazenamentos apropriados +>>>>>>> 82edf2d (New md files from RunPod) Todos os processadores (tanto `{id}` quanto `{class}`) trabalham juntos como um grafo de fluxo de dados coeso, e não como sistemas separados. @@ -265,7 +293,11 @@ Expansões de modelo: Isso cria: Pipeline de processamento de documentos isolado para `customer-A-flow` Serviço de incorporação compartilhado para todos os fluxos `standard-rag` +<<<<<<< HEAD Fluxo de dados completo da ingestão de documentos à consulta +======= +Fluxo de dados completo da ingestão do documento à consulta +>>>>>>> 82edf2d (New md files from RunPod) Processadores configurados com os valores de parâmetro fornecidos ## Benefícios diff --git a/docs/tech-specs/flow-class-definition.ru.md b/docs/tech-specs/flow-class-definition.ru.md index 815cf556..b27c033a 100644 --- a/docs/tech-specs/flow-class-definition.ru.md +++ b/docs/tech-specs/flow-class-definition.ru.md @@ -25,10 +25,17 @@ ``` **Характеристики:** +<<<<<<< HEAD Общие для всех экземпляров потока одного класса. Обычно это дорогие или безсостояниевые сервисы (LLM, модели эмбеддингов). Используйте переменную шаблона `{class}` для именования очереди. Настройки могут быть фиксированными значениями или параметризованы с использованием синтаксиса `{parameter-name}`. +======= +Распространяются на все экземпляры потока одного и того же класса. +Обычно это дорогие или не имеющие состояния сервисы (LLM, модели эмбеддингов). +Используйте переменную шаблона `{class}` для именования очереди. +Параметры могут быть фиксированными значениями или параметризованы с использованием синтаксиса `{parameter-name}`. +>>>>>>> 82edf2d (New md files from RunPod) Примеры: `embeddings:{class}`, `text-completion:{class}`, `graph-rag:{class}`. ### 2. Раздел потока @@ -96,7 +103,11 @@ **Характеристики:** Ключи являются именами параметров, используемыми в настройках процессора (например, `{model}`) Значения ссылаются на определения параметров, хранящиеся в schema/config +<<<<<<< HEAD Обеспечивает повторное использование общих определений параметров в различных потоках. +======= +Позволяет повторно использовать общие определения параметров в различных потоках. +>>>>>>> 82edf2d (New md files from RunPod) Уменьшает дублирование схем параметров. ### 5. Метаданные @@ -213,19 +224,32 @@ **арендатор**: `tg` для определений шаблонов потоков, предоставляемых TrustGraph **пространство имен**: Указывает шаблон обмена сообщениями `flow`: Сервисы "отправь и забудь" +<<<<<<< HEAD `request`: Запрос в сервисах "запрос/ответ" `response`: Ответ в сервисах "запрос/ответ" +======= + `request`: Запрос в сервисах "запрос-ответ" + `response`: Ответ в сервисах "запрос-ответ" +>>>>>>> 82edf2d (New md files from RunPod) **тема**: Конкретное имя очереди/темы с переменными шаблона ### Постоянные очереди Шаблон: `persistent://tg/flow/:{id}` Используется для сервисов "отправь и забудь" и потоков данных с гарантированной доставкой +<<<<<<< HEAD Данные сохраняются в хранилище Pulsar после перезагрузок +======= +Данные сохраняются в хранилище Pulsar при перезапусках +>>>>>>> 82edf2d (New md files from RunPod) Пример: `persistent://tg/flow/chunk-load:{id}` ### Непостоянные очереди Шаблон: `non-persistent://tg/request/:{class}` или `non-persistent://tg/response/:{class}` +<<<<<<< HEAD Используется для шаблонов обмена сообщениями "запрос/ответ" +======= +Используется для шаблонов обмена сообщениями "запрос-ответ" +>>>>>>> 82edf2d (New md files from RunPod) Непостоянные, не сохраняются на диск Pulsar Меньшая задержка, подходит для коммуникации в стиле RPC Пример: `non-persistent://tg/request/embeddings:{class}` @@ -241,7 +265,11 @@ Все процессоры (как `{id}`, так и `{class}`) работают вместе как единый граф потока данных, а не как отдельные системы. +<<<<<<< HEAD ## Пример инстанцирования потока +======= +## Пример инстанциирования потока +>>>>>>> 82edf2d (New md files from RunPod) Дано: Идентификатор экземпляра потока: `customer-A-flow` diff --git a/docs/tech-specs/flow-class-definition.sw.md b/docs/tech-specs/flow-class-definition.sw.md index 66d63ab2..68247db0 100644 --- a/docs/tech-specs/flow-class-definition.sw.md +++ b/docs/tech-specs/flow-class-definition.sw.md @@ -2,14 +2,22 @@ ## Muhtasari +<<<<<<< HEAD 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. +======= +Mfumo wa mtiririko unafafanua mfumo kamili wa 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. +>>>>>>> 82edf2d (New md files from RunPod) ## Muundo Ufafanuzi wa mfumo wa mtiririko una sehemu tano kuu: ### 1. Sehemu ya Darasa +<<<<<<< HEAD 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. +======= +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 wa darasa hili. +>>>>>>> 82edf2d (New md files from RunPod) ```json "class": { @@ -27,7 +35,11 @@ Inafafanua vichakata vya huduma ambavyo huanzishwa mara moja kwa kila mfumo wa m **Sifa:** Zinashirikiwa katika visasisho vyote vya aina moja. Hutoa huduma za kawaida au zisizo na hali (LLMs, modeli za uingizaji). +<<<<<<< HEAD Tumia jina la kigezo cha `{class}` kwa ajili ya kujina kwa folyo. +======= +Tumia jina la kigezo `{class}` kwa ajili ya kujina kwa folyo. +>>>>>>> 82edf2d (New md files from RunPod) Mipangilio inaweza kuwa maadili thabiti au kupangwa kwa kutumia sintaksia ya `{parameter-name}`. Mifano: `embeddings:{class}`, `text-completion:{class}`, `graph-rag:{class}` @@ -54,10 +66,17 @@ 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}`. +<<<<<<< HEAD ### 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: +======= +### Sura ya 3. Sehemu ya Vifaa vya Kuunganisha +Inaelezea pointi za kuingilia na mikataba ya kuingiliana kwa mtiririko. Hizi huunda safu ya API kwa mifumo ya nje na mawasiliano ya vipengele vya ndani. + +Vifaa vya kuunganisha vinaweza kuwa na aina mbili: +>>>>>>> 82edf2d (New md files from RunPod) **Mfumo wa "Tuma na Usahau"** (folyo moja): ```json @@ -67,7 +86,11 @@ Vifaa vinaweza kuwa na aina mbili: } ``` +<<<<<<< HEAD **Muundo wa Ombi/Jibu** (kitu chenye sehemu za ombi/jibu): +======= +**Muundo wa Ombi/Jibu** (objekti yenye sehemu za ombi/jibu): +>>>>>>> 82edf2d (New md files from RunPod) ```json "interfaces": { "embeddings": { @@ -77,6 +100,7 @@ Vifaa vinaweza kuwa na aina mbili: } ``` +<<<<<<< HEAD **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`) @@ -84,6 +108,15 @@ Vifaa vinaweza kuwa na aina mbili: ### 4. Sehemu ya Vigezo Huunganisha majina ya vigezo maalum ya mtiririko na ufafanuzi wa vigezo unaohifadhiwa katika eneo moja: +======= +**Aina za Vifaa vya Kuunganisha:** +**Vifaa vya Kuanzia:** Maeneo ambapo mifumo ya nje huingiza data (`document-load`, `agent`) +**Vifaa vya Huduma:** Mfumo wa ombi/jibu kwa huduma (`embeddings`, `text-completion`) +**Vifaa vya Data:** Vifaa vya kuunganisha 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 la kati: +>>>>>>> 82edf2d (New md files from RunPod) ```json "parameters": { @@ -94,13 +127,21 @@ Huunganisha majina ya vigezo maalum ya mtiririko na ufafanuzi wa vigezo unaohifa ``` **Sifa:** +<<<<<<< HEAD Nenosiri ni majina ya vigezo yanayotumika katika mipangilio ya kichakata (k.m., `{model}`) +======= +Funguo ni majina ya vigezo yanayotumika katika mipangilio ya kichakata (k.m., `{model}`) +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD Taarifa za ziada kuhusu mpango wa mtiririko: +======= +Habari ya ziada kuhusu mpango wa mtiririko: +>>>>>>> 82edf2d (New md files from RunPod) ```json "description": "Human-readable description", @@ -112,6 +153,7 @@ Taarifa za ziada kuhusu mpango wa mtiririko: ### Vigezo vya Mfumo #### {id} +<<<<<<< HEAD Huibwa na kitambulisho kipekee cha kila mfumo. Huunda rasilimali zilizotengwa kwa kila mfumo. Mifano: `flow-123`, `customer-A-flow` @@ -120,10 +162,21 @@ Mifano: `flow-123`, `customer-A-flow` Huibwa na jina la mpango wa mfumo. Huunda rasilimali zilizoshirikiwa katika mifumo ya aina moja. Mifano: `standard-rag`, `enterprise-rag` +======= +Huibadilishwa na kitambulisho kipekee cha kila mtiririko. +Huunda rasilimali zilizojitenga kwa kila mtiririko. +Mfano: `flow-123`, `customer-A-flow` + +#### {class} +Huibadilishwa na jina la mpango wa mtiririko. +Huunda rasilimali zilizoshirikiwa katika mitiririko ya aina moja. +Mfano: `standard-rag`, `enterprise-rag` +>>>>>>> 82edf2d (New md files from RunPod) ### Vigezo vya Parameta #### {parameter-name} +<<<<<<< HEAD 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. @@ -136,6 +189,20 @@ Yanathibitishwa kulingana na ufafanuzi wa parameta uliohifadhiwa katika mfumo. Mpangilio hutoa maadili ya usanidi kwa vichakuzi wakati wa uundaji. Inaweza kuwa: ### Mpangilio Thabiti +======= +Parameta maalum zilizobainishwa wakati wa kuanzisha mtiririko. +Majina ya parametri yanalingana na funguo katika sehemu ya `parameters` ya mtiririko. +Hutumiwa katika mipangilio ya kichakataji ili kuboresha tabia. +Mifano: `{model}`, `{temp}`, `{chunk}` +Huibadilishwa na maadili yaliyotolewa wakati wa kuanzisha mtiririko. +Yanathibitishwa kulingana na ufafanuzi wa parametri uliohifadhiwa katika mfumo. + +## Mipangilio ya Kichakataji + +Mipangilio hutoa maadili ya usanidi kwa vichakataji wakati wa uundaji. Inaweza kuwa: + +### Mipangilio Thabiti +>>>>>>> 82edf2d (New md files from RunPod) Maadili ya moja kwa moja ambayo hayubadiliki: ```json "settings": { @@ -145,7 +212,11 @@ Maadili ya moja kwa moja ambayo hayubadiliki: } ``` +<<<<<<< HEAD ### Mipangilio Iliyobadilishwa +======= +### Parameta za Mpangilio +>>>>>>> 82edf2d (New md files from RunPod) Maelezo ambayo hutumia vigezo vilivyotolewa wakati wa kuanzisha mtiririko: ```json "settings": { @@ -182,7 +253,11 @@ Majina ya vigezo katika mipangilio yanalingana na funguo katika sehemu ya `param } ``` +<<<<<<< HEAD **Kifurushi cha Mpangilio wa Kurekebisha na Unaoweza Kubadilishwa:** +======= +**Sehemu za Kujumuisha Zenye Mipangilio Thabiti na Inayoweza Kubadilishwa:** +>>>>>>> 82edf2d (New md files from RunPod) ```json // In parameters section: "parameters": { @@ -203,21 +278,32 @@ Majina ya vigezo katika mipangilio yanalingana na funguo katika sehemu ya `param ## Mifumo ya Kinyororo (Pulsar) +<<<<<<< HEAD Mfumo wa mtiririko hutumia Apache Pulsar kwa ujumbe. Majina ya nyororo yanafuata muundo wa Pulsar: +======= +Mfumo wa mtiririko hutumia Apache Pulsar kwa ajili ya ujumbe. Majina ya nyororo yanafuata muundo wa Pulsar: +>>>>>>> 82edf2d (New md files from RunPod) ``` ://// ``` ### Vipengele: +<<<<<<< HEAD **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 +======= +**uhifadhi**: `persistent` au `non-persistent` (Njia ya uhifadhi ya Pulsar) +**mwendeshaji**: `tg` kwa maelekezo ya muundo wa mtiririko yanayotolewa na TrustGraph +**nafasi**: Inaonyesha mtindo wa ujumbe +>>>>>>> 82edf2d (New md files from RunPod) `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 +<<<<<<< HEAD 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 @@ -228,18 +314,40 @@ Muundo: `non-persistent://tg/request/:{class}` au `non-persistent://tg/re Inatumika kwa muundo wa ujumbe wa ombi/jibu Inapotea, haihifadhiwa kwenye diski na Pulsar Latensi ndogo, inafaa kwa mawasiliano ya aina ya RPC +======= +Mtindo: `persistent://tg/flow/:{id}` +Inatumika kwa huduma za "tumia na usahau" na mtiririko wa data endelevu +Data inahifadhiwa katika hifadhi ya Pulsar katika kuanzishwa upya +Mfano: `persistent://tg/flow/chunk-load:{id}` + +### Folyozilizohifadhiwa +Mtindo: `non-persistent://tg/request/:{class}` au `non-persistent://tg/response/:{class}` +Inatumika kwa mitindo ya ujumbe ya ombi/jibu +Inapotea, haihifadhiwi kwenye diski na Pulsar +Latensi ya chini, inayofaa kwa mawasiliano ya aina ya RPC +>>>>>>> 82edf2d (New md files from RunPod) Mfano: `non-persistent://tg/request/embeddings:{class}` ## Usanifu wa Mtiririko wa Data +<<<<<<< HEAD Muundo wa mtiririko huunda mtiririko wa data unaounganishwa ambapo: 1. **Mchakato wa Kusindika Nyaraka**: Mtiririko kutoka kwa kupokea hadi kubadilisha hadi kuhifadhi +======= +Muundo wa mtiririko huunda mtiririko wa data uliounganishwa ambapo: + +1. **Mchakato wa Kusindika Nyaraka**: Mtiririko kutoka kwa kupokea kupitia mabadiliko hadi kuhifadhi +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD Wasindikaji wote (wote `{id}` na `{class}`) hufanya kazi pamoja kama grafu moja ya mtiririko wa data, sio mifumo tofauti. +======= +Wasindikaji wote (wote `{id}` na `{class}`) hufanya kazi pamoja kama grafu ya mtiririko wa data iliyounganishwa, sio mifumo tofauti. +>>>>>>> 82edf2d (New md files from RunPod) ## Uanzishaji wa Mfano wa Mtiririko @@ -264,9 +372,15 @@ Upanuzi wa kiolezo: Hii huunda: Mchakato wa kusindika nyaraka uliotengwa kwa `customer-A-flow` +<<<<<<< HEAD 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 +======= +Huduma ya pamoja ya uingishaji kwa mtiririko wote wa `standard-rag` +Mtiririko kamili kutoka kwa kupokea nyaraka hadi uchunguzi +Wasindikaji uliopangwa na maadili ya vigezo vilivyotolewa +>>>>>>> 82edf2d (New md files from RunPod) ## Faida diff --git a/docs/tech-specs/flow-class-definition.tr.md b/docs/tech-specs/flow-class-definition.tr.md index c13222ae..cd90fd0f 100644 --- a/docs/tech-specs/flow-class-definition.tr.md +++ b/docs/tech-specs/flow-class-definition.tr.md @@ -2,7 +2,11 @@ ## Genel Bakış +<<<<<<< HEAD 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. +======= +Bir akış şeması, TrustGraph sisteminde eksiksiz bir veri akışı kalıbı şablonunu tanımlar. Örneklenildiğinde, veri alımı, işleme, depolama ve sorgulamayı birleşik bir sistem olarak ele alan birbirine bağlı işlemci ağları oluşturur. +>>>>>>> 82edf2d (New md files from RunPod) ## Yapı @@ -50,7 +54,11 @@ Her bir bireysel akış örneği için örneklenen, akışa özgü işlemcileri **Özellikler:** Her akış için benzersiz bir örnek Akışa özgü verileri ve durumu yönetir +<<<<<<< HEAD Kuyruğu adlandırmak için `{id}` şablon değişkenini kullanın +======= +Kuyruğa adlandırma için `{id}` şablon değişkenini kullanın +>>>>>>> 82edf2d (New md files from RunPod) Ayarlar, sabit değerler olabilir veya `{parameter-name}` sözdizimi ile parametrelendirilebilir Örnekler: `chunker:{id}`, `pdf-decoder:{id}`, `kg-extract-relationships:{id}` @@ -79,7 +87,11 @@ Arayüzler iki formda olabilir: **Arayüz Türleri:** **Giriş Noktaları:** Dış sistemlerin veri enjekte ettiği yerler (`document-load`, `agent`) +<<<<<<< HEAD **Servis Arayüzleri:** Servisler için istek/yanıt kalıpları (`embeddings`, `text-completion`) +======= +**Hizmet Arayüzleri:** Hizmetler için istek/yanıt kalıpları (`embeddings`, `text-completion`) +>>>>>>> 82edf2d (New md files from RunPod) **Veri Arayüzleri:** Ateşle-ve-unut veri akışı bağlantı noktaları (`triples-store`, `entity-contexts-load`) ### 4. Parametreler Bölümü @@ -211,28 +223,45 @@ Akış şemaları, mesajlaşma için Apache Pulsar'ı kullanır. Kuyruk adları, ### 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` +<<<<<<< HEAD **isim alanı**: Mesajlaşma desenini belirtir +======= +**isim alanı**: Mesajlaşma kalıbını gösterir +>>>>>>> 82edf2d (New md files from RunPod) `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 +<<<<<<< HEAD Desen: `persistent://tg/flow/:{id}` +======= +Kalıp: `persistent://tg/flow/:{id}` +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD Desen: `non-persistent://tg/request/:{class}` veya `non-persistent://tg/response/:{class}` İstek/yanıt mesajlaşma desenleri için kullanılır +======= +Kalıp: `non-persistent://tg/request/:{class}` veya `non-persistent://tg/response/:{class}` +İstek/yanıt mesajlaşma kalıpları için kullanılır +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD Akış tanımı, aşağıdaki gibi birleşik bir veri akışı oluşturur: +======= +Akış tanımı, aşağıdaki unsurları içeren birleşik bir veri akışı oluşturur: +>>>>>>> 82edf2d (New md files from RunPod) 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 @@ -264,14 +293,26 @@ Kullanıcı tarafından sağlanan parametreler: Bu, aşağıdaki öğeleri oluşturur: `customer-A-flow` için izole edilmiş belge işleme hattı +<<<<<<< HEAD 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 +======= +tüm `standard-rag` akışları için paylaşımlı gömme hizmeti +Belge alımından sorgulamaya kadar olan eksiksiz veri akışı +İşlemcilerin sağlanan parametre değerleriyle yapılandırılması +>>>>>>> 82edf2d (New md files from RunPod) ## 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 +<<<<<<< HEAD 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 +5. **Bütünleşik Mimari**: Sorgu ve işleme, aynı veri akışının bir parçasıdır +======= +3. **Ölçeklenebilirlik**: Aynı şablondan çok sayıda akış oluşturulabilir +4. **Modülerlik**: Paylaşılan ve akışa özgü bileşenler arasında net bir ayrım +5. **Birleşik Mimari**: Sorgu ve işleme, aynı veri akışının bir parçasıdır +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/flow-class-definition.zh-cn.md b/docs/tech-specs/flow-class-definition.zh-cn.md index dea29c18..687f2551 100644 --- a/docs/tech-specs/flow-class-definition.zh-cn.md +++ b/docs/tech-specs/flow-class-definition.zh-cn.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD # 流程蓝图定义规范 ## 概述 @@ -10,6 +11,20 @@ ### 1. 类部分 定义共享服务处理器,这些处理器每个流程蓝图实例化一次。这些处理器处理来自此类的所有流程实例的请求。 +======= +# 流工作蓝图定义规范 + +## 概述 + +一个流工作蓝图定义了 TrustGraph 系统中完整的数据流模式模板。当实例化时,它会创建一个相互连接的处理单元网络,该网络处理数据摄取、处理、存储和查询,作为一个统一的系统。 + +## 结构 + +一个流工作蓝图定义由五个主要部分组成: + +### 1. 类部分 +定义共享服务处理器,这些处理器每个流工作蓝图实例化一次。这些处理器处理来自此类的所有流实例的请求。 +>>>>>>> 82edf2d (New md files from RunPod) ```json "class": { @@ -24,7 +39,11 @@ } ``` +<<<<<<< HEAD **特性:** +======= +**特点:** +>>>>>>> 82edf2d (New md files from RunPod) 在同一类别的所有流程实例中共享。 通常是昂贵或无状态的服务(例如:大型语言模型、嵌入模型)。 使用 `{class}` 模板变量进行队列命名。 @@ -57,9 +76,15 @@ ### 3. 接口部分 定义流程的入口点和交互协议。 这些构成了外部系统和内部组件通信的 API 表面。 +<<<<<<< HEAD 接口可以有两种形式: **即发即弃模式**(单个队列): +======= +接口可以采用两种形式: + +**发布-订阅模式**(单个队列): +>>>>>>> 82edf2d (New md files from RunPod) ```json "interfaces": { "document-load": "persistent://tg/flow/document-load:{id}", @@ -234,10 +259,17 @@ 流程蓝图创建统一的数据流,其中: +<<<<<<< HEAD 1. **文档处理管道**: 从摄取到转换再到存储的流程 2. **查询服务**: 集成的处理器,查询相同的存储和服务 3. **共享服务**: 所有流程都可以使用的集中式处理器 4. **存储写入器**: 将处理后的数据持久化到适当的存储中 +======= +1. **文档处理管道**: 从摄取到转换再到存储 +2. **查询服务**: 集成的处理器,查询相同的存储和服务 +3. **共享服务**: 所有流程都可以使用的集中处理器 +4. **存储写入器**: 将处理后的数据持久化到适当的存储 +>>>>>>> 82edf2d (New md files from RunPod) 所有处理器(包括 `{id}` 和 `{class}`)协同工作,形成一个连贯的数据流图,而不是作为独立的系统。 diff --git a/docs/tech-specs/flow-configurable-parameters.ar.md b/docs/tech-specs/flow-configurable-parameters.ar.md index 98da3e71..ba4e2ac7 100644 --- a/docs/tech-specs/flow-configurable-parameters.ar.md +++ b/docs/tech-specs/flow-configurable-parameters.ar.md @@ -36,10 +36,17 @@ الإعلان عن المعلمات في تعريفات "خطط سير العمل". التحقق من صحة المعلمات عند بدء تشغيل سير العمل. استبدال المعلمات في معلمات المعالج. +<<<<<<< HEAD الكشف عنها من خلال واجهات برمجة التطبيقات وواجهات المستخدم. من خلال الاستفادة من معلمات معلمات المعالج، يمكن لـ TrustGraph: تقليل تكرار "خطط سير العمل" باستخدام المعلمات للتغيرات. +======= +الكشف عن المعلمات من خلال واجهات برمجة التطبيقات وواجهات المستخدم. + +من خلال الاستفادة من معلمات معلمات المعالج، يمكن لـ TrustGraph: +تقليل تكرار "خطط سير العمل" باستخدام المعلمات للتنوعات. +>>>>>>> 82edf2d (New md files from RunPod) تمكين المستخدمين من ضبط سلوك المعالج دون تعديل التعريفات. دعم التكوينات الخاصة بالبيئة من خلال قيم المعلمات. الحفاظ على الأمان من النوع من خلال التحقق من صحة مخططات المعلمات. @@ -148,7 +155,11 @@ #### مخطط سير العمل مع مراجع المعلمات +<<<<<<< HEAD تحدد مخططات سير العمل بيانات وصفية للمعلمات مع مراجع للأنواع والأوصاف والترتيب: +======= +تحدد مخططات سير العمل بيانات تعريف المعلمات مع مراجع الأنواع والأوصاف والترتيب: +>>>>>>> 82edf2d (New md files from RunPod) ```json { @@ -217,9 +228,15 @@ } ``` +<<<<<<< HEAD القسم `parameters` يربط أسماء المعلمات الخاصة بالتدفق (المفاتيح) بكائنات بيانات تعريف المعلمات التي تحتوي على: `type`: مرجع إلى تعريف المعلمة المحدد مركزيًا (مثل "llm-model") `description`: وصف يمكن قراءته بواسطة الإنسان للعرض في واجهة المستخدم +======= +القسم `parameters` يربط أسماء المعلمات الخاصة بالتدفق (المفاتيح) بكائنات بيانات وصفية للمعلمات والتي تحتوي على: +`type`: مرجع إلى تعريف المعلمة المحدد مركزيًا (مثل "llm-model") +`description`: وصف قابل للقراءة بواسطة الإنسان للعرض في واجهة المستخدم +>>>>>>> 82edf2d (New md files from RunPod) `order`: ترتيب العرض لنماذج المعلمات (تظهر الأرقام الأقل أولاً) `advanced` (اختياري): علامة منطقية تشير إلى ما إذا كانت هذه معلمة متقدمة (افتراضي: خطأ). عند تعيينها على "صحيح"، قد تخفي واجهة المستخدم هذه المعلمة افتراضيًا أو تضعها في قسم "متقدم" `controlled-by` (اختياري): اسم معلمة أخرى تتحكم في قيمة هذه المعلمة عند التواجد في الوضع البسيط. عند تحديدها، ترث هذه المعلمة قيمتها من المعلمة المتحكمة ما لم يتم تجاوزها بشكل صريح @@ -227,7 +244,11 @@ تسمح هذه الطريقة بما يلي: تعريفات أنواع معلمات قابلة لإعادة الاستخدام عبر قوالب تدفق متعددة إدارة مركزية لأنواع المعلمات والتحقق من صحتها +<<<<<<< HEAD أوصاف وترتيب المعلمات الخاصة بالتدفق +======= +أوصاف وترتيب معلمات خاصة بالتدفق +>>>>>>> 82edf2d (New md files from RunPod) تجربة واجهة مستخدم محسنة مع نماذج معلمات وصفية التحقق من صحة المعلمات بشكل متسق عبر التدفقات إضافة سهلة لأنواع معلمات قياسية جديدة @@ -253,9 +274,15 @@ ملاحظة: في هذا المثال، `llm-rag-model` غير مقدمة بشكل صريح ولكنها سترث القيمة "claude-3" من `llm-model` بسبب علاقتها مع `controlled-by`. وبالمثل، يمكن أن ترث `chunk-overlap` قيمة محسوبة بناءً على `chunk-size`. سيقوم النظام بما يلي: +<<<<<<< HEAD 1. استخراج بيانات تعريف المعلمات من تعريف مخطط التدفق 2. مطابقة أسماء معلمات التدفق مع تعريفات أنواعها (على سبيل المثال، `llm-model` → نوع `llm-model`) 3. حل علاقات "يتم التحكم بها" (على سبيل المثال، ترث `llm-rag-model` من `llm-model`) +======= +1. استخراج بيانات وصفية للمعلمات من تعريف مخطط التدفق +2. ربط أسماء معلمات التدفق بتعريفات أنواعها (مثل: `llm-model` → نوع `llm-model`) +3. حل علاقات "التحكم بواسطة" (مثل: `llm-rag-model` ترث من `llm-model`) +>>>>>>> 82edf2d (New md files from RunPod) 4. التحقق من صحة القيم المقدمة من المستخدم والقيم الموروثة مقابل تعريفات أنواع المعلمات 5. استبدال القيم التي تم حلها في معلمات المعالج أثناء إنشاء التدفق @@ -265,25 +292,41 @@ عندما يتم بدء تدفق، يقوم النظام بتنفيذ الخطوات التالية لحل المعلمات: +<<<<<<< HEAD 1. **تحميل مخطط التدفق**: تحميل تعريف مخطط التدفق واستخراج بيانات تعريف المعلمات 2. **استخراج البيانات الوصفية**: استخراج `type`، `description`، `order`، `advanced`، و `controlled-by` لكل معلمة معرفة في قسم `parameters` الخاص بمخطط التدفق 3. **البحث عن تعريف النوع**: لكل معلمة في مخطط التدفق: استرجاع تعريف نوع المعلمة من متجر المخطط/التكوين باستخدام حقل `type` +======= +1. **تحميل مخطط التدفق**: تحميل تعريف مخطط التدفق واستخراج بيانات وصفية للمعلمات +2. **استخراج البيانات الوصفية**: استخراج `type`، `description`، `order`، `advanced`، و `controlled-by` لكل معلمة معرفة في قسم `parameters` الخاص بمخطط التدفق +3. **البحث عن تعريف النوع**: لكل معلمة في مخطط التدفق: + استرجاع تعريف نوع المعلمة من متجر المخططات/التكوين باستخدام حقل `type` +>>>>>>> 82edf2d (New md files from RunPod) يتم تخزين تعريفات الأنواع مع النوع "parameter-type" في نظام التكوين يحتوي كل تعريف نوع على مخطط المعلمة والقيمة الافتراضية وقواعد التحقق من الصحة 4. **حل القيمة الافتراضية**: لكل معلمة معرفة في مخطط التدفق: التحقق مما إذا كان المستخدم قد قدم قيمة لهذه المعلمة إذا لم يتم تقديم قيمة من قبل المستخدم، استخدم القيمة `default` من تعريف نوع المعلمة +<<<<<<< HEAD إنشاء خريطة معلمات كاملة تحتوي على كل من القيم المقدمة من قبل المستخدم والقيم الافتراضية 5. **حل إرث المعلمات** (علاقات "يتم التحكم بها"): +======= + إنشاء خريطة كاملة للمعلمات تحتوي على كل من القيم المقدمة من قبل المستخدم والقيم الافتراضية +5. **حل إرث المعلمات** (علاقات "التحكم بواسطة"): +>>>>>>> 82edf2d (New md files from RunPod) للمعلمات التي تحتوي على حقل `controlled-by`، تحقق مما إذا تم توفير قيمة بشكل صريح إذا لم يتم توفير قيمة صريحة، فقم بوراثة القيمة من المعلمة المسيطرة إذا كانت المعلمة المسيطرة أيضًا لا تحتوي على قيمة، فاستخدم القيمة الافتراضية من تعريف النوع التحقق من عدم وجود تبعيات دائرية في علاقات `controlled-by` 6. **التحقق من الصحة**: التحقق من صحة مجموعة المعلمات الكاملة (القيم المقدمة من قبل المستخدم والقيم الافتراضية والقيم الموروثة) مقابل تعريفات الأنواع 7. **التخزين**: تخزين مجموعة المعلمات التي تم حلها بالكامل مع مثيل التدفق لأغراض التدقيق +<<<<<<< HEAD 8. **الاستبدال القالب**: استبدال عناصر نائب المعلمات في معلمات المعالج بالقيم التي تم حلها +======= +8. **استبدال القوالب**: استبدال عناصر نطق المعلمات في معلمات المعالج بالقيم التي تم حلها +>>>>>>> 82edf2d (New md files from RunPod) 9. **إنشاء المعالجات**: إنشاء معالجات بمعلمات مستبدلة **ملاحظات تنفيذ مهمة:** @@ -292,7 +335,11 @@ يحدث حل المعلمات في وقت بدء التدفق، وليس في وقت إنشاء المعالج يجب أن يؤدي عدم وجود معلمات مطلوبة بدون قيم افتراضية إلى فشل بدء التدفق مع رسالة خطأ واضحة +<<<<<<< HEAD #### إرث المعلمات مع "يتم التحكم بها" +======= +#### إرث المعلمات مع "التحكم بواسطة" +>>>>>>> 82edf2d (New md files from RunPod) يتيح الحقل `controlled-by` وراثة قيمة المعلمة، وهو مفيد بشكل خاص لتبسيط واجهات المستخدم مع الحفاظ على المرونة: @@ -370,34 +417,57 @@ ``` يجب أن تقوم هذه الدالة بما يلي: +<<<<<<< HEAD استخراج بيانات تعريف المعلمات من قسم `parameters` في مخطط سير العمل. لكل معلمة، استرداد تعريف النوع الخاص بها من مستودع التكوين. +======= + استخراج بيانات تعريف المعلمات من قسم `parameters` في مخطط التدفق. + لكل معلمة، استرجاع تعريف النوع الخاص بها من مستودع التكوين. +>>>>>>> 82edf2d (New md files from RunPod) تطبيق القيم الافتراضية لأي معلمات لم يتم توفيرها من قبل المستخدم. التعامل مع علاقات الوراثة `controlled-by`. إرجاع المجموعة الكاملة للمعلمات. 2. **الطريقة المعدلة `handle_start_flow`** +<<<<<<< HEAD استدعاء `resolve_parameters` بعد تحميل مخطط سير العمل. استخدام المجموعة الكاملة للمعلمات التي تم حلها للاستبدال في القوالب. تخزين المجموعة الكاملة للمعلمات (وليس فقط المعلمات التي قدمها المستخدم) مع سير العمل. التحقق من أن جميع المعلمات المطلوبة لها قيم. 3. **استرداد أنواع المعلمات** +======= + استدعاء `resolve_parameters` بعد تحميل مخطط التدفق. + استخدام المجموعة الكاملة للمعلمات التي تم حلها للاستبدال في القوالب. + تخزين المجموعة الكاملة للمعلمات (وليس فقط المعلمات التي قدمها المستخدم) مع التدفق. + التحقق من أن جميع المعلمات المطلوبة لها قيم. + +3. **استرجاع أنواع المعلمات** +>>>>>>> 82edf2d (New md files from RunPod) يتم تخزين تعريفات أنواع المعلمات في التكوين بنوع "parameter-type". يحتوي كل تعريف نوع على مخطط وقيمة افتراضية وقواعد تحقق. تخزين أنواع المعلمات المستخدمة بشكل متكرر في ذاكرة التخزين المؤقت لتقليل عمليات البحث في التكوين. #### تكامل نظام التكوين +<<<<<<< HEAD 3. **تخزين كائنات سير العمل** عندما تتم إضافة سير عمل إلى نظام التكوين بواسطة مكون سير العمل في مدير التكوين، يجب أن تتضمن كائن سير العمل قيم المعلمات التي تم حلها. يحتاج مدير التكوين إلى تخزين كل من المعلمات التي قدمها المستخدم في الأصل والقيم التي تم حلها (مع تطبيق القيم الافتراضية). يجب أن تتضمن كائنات سير العمل في نظام التكوين: `parameters`: القيم النهائية للمعلمات التي تم حلها والتي تم استخدامها لسير العمل. +======= +3. **تخزين كائنات التدفق** + عندما تتم إضافة تدفق إلى نظام التكوين بواسطة مكون التدفق في مدير التكوين، يجب أن تتضمن كائن التدفق قيم المعلمات التي تم حلها. + يحتاج مدير التكوين إلى تخزين كل من المعلمات التي قدمها المستخدم في الأصل والقيم التي تم حلها (مع تطبيق القيم الافتراضية). + يجب أن تتضمن كائنات التدفق في نظام التكوين: + `parameters`: القيم النهائية للمعلمات التي تم حلها والتي تم استخدامها للتدفق. +>>>>>>> 82edf2d (New md files from RunPod) #### تكامل واجهة سطر الأوامر 4. **أوامر واجهة سطر الأوامر الخاصة بالمكتبة** +<<<<<<< HEAD تحتاج أوامر واجهة سطر الأوامر التي تبدأ سير العمل إلى دعم المعلمات: قبول قيم المعلمات عبر علامات سطر الأوامر أو ملفات التكوين. التحقق من صحة المعلمات مقابل تعريفات مخطط سير العمل قبل الإرسال. @@ -406,16 +476,34 @@ تحتاج أوامر واجهة سطر الأوامر التي تعرض سير العمل إلى عرض معلومات المعلمات: عرض قيم المعلمات المستخدمة عند بدء سير العمل. عرض المعلمات المتاحة لمخطط سير عمل. +======= + تحتاج أوامر واجهة سطر الأوامر التي تبدأ التدفقات إلى دعم المعلمات: + قبول قيم المعلمات عبر علامات سطر الأوامر أو ملفات التكوين. + التحقق من صحة المعلمات مقابل تعريفات مخطط التدفق قبل الإرسال. + دعم إدخال ملفات المعلمات (JSON/YAML) لمجموعات المعلمات المعقدة. + + تحتاج أوامر واجهة سطر الأوامر التي تعرض التدفقات إلى عرض معلومات المعلمات: + عرض قيم المعلمات المستخدمة عند بدء التدفق. + عرض المعلمات المتاحة لمخطط تدفق. +>>>>>>> 82edf2d (New md files from RunPod) عرض مخططات التحقق من صحة المعلمات والقيم الافتراضية. #### تكامل الفئة الأساسية للمعالج 5. **دعم ParameterSpec** +<<<<<<< HEAD تحتاج الفئات الأساسية للمعالج إلى دعم استبدال المعلمات من خلال آلية ParametersSpec الحالية. يجب تحسين فئة ParametersSpec (الموجودة في نفس الوحدة النمطية مثل ConsumerSpec و ProducerSpec) إذا لزم الأمر لدعم استبدال القوالب للمعلمات. يجب أن تكون المعالجات قادرة على استدعاء ParametersSpec لتكوين معامها باستخدام قيم المعلمات التي تم حلها في وقت بدء سير العمل. يجب أن تقوم تنفيذ ParametersSpec بما يلي: قبول تكوينات المعلمات التي تحتوي على عناصر نائبة للمعلمات (مثل `{model}`، `{temperature}`). +======= + يجب أن تدعم الفئات الأساسية للمعالج استبدال المعلمات من خلال آلية ParametersSpec الحالية. + يجب تحسين فئة ParametersSpec (الموجودة في نفس الوحدة كما ConsumerSpec و ProducerSpec) إذا لزم الأمر لدعم استبدال القوالب للمعلمات. + يجب أن تكون المعالجات قادرة على استدعاء ParametersSpec لتكوين معامها باستخدام قيم المعلمات التي تم حلها في وقت بدء التدفق. + يجب أن تقوم تنفيذ ParametersSpec بما يلي: + قبول تكوينات المعلمات التي تحتوي على عناصر نائب للمعلمات (مثل `{model}`، `{temperature}`). +>>>>>>> 82edf2d (New md files from RunPod) دعم استبدال المعلمات في وقت التشغيل عند إنشاء المعالج. التحقق من أن القيم المستبدلة تتطابق مع الأنواع والقيود المتوقعة. توفير معالجة الأخطاء للإشارات المفقودة أو غير الصالحة للمعلمات. @@ -423,7 +511,11 @@ #### قواعد الاستبدال تستخدم المعلمات التنسيق `{parameter-name}` في معلمات المعالج. +<<<<<<< HEAD تتطابق أسماء المعلمات في المعلمات مع المفاتيح في قسم `parameters` في سير العمل. +======= +تتطابق أسماء المعلمات في المعلمات مع المفاتيح في قسم `parameters` في التدفق. +>>>>>>> 82edf2d (New md files from RunPod) يحدث الاستبدال جنبًا إلى جنب مع استبدال `{id}` و `{class}`. تؤدي الإشارات غير الصالحة للمعلمات إلى أخطاء في وقت بدء التشغيل. يحدث التحقق من النوع بناءً على تعريف المعلمة المخزن مركزيًا. @@ -449,21 +541,35 @@ Substituted in processor: "0.7" (string) اختبارات الوحدة للتحقق من صحة مخططات المعلمات. اختبارات التكامل لاستبدال المعلمات في معلمات المعالج. +<<<<<<< HEAD اختبارات شاملة لإطلاق العمليات التدفقية بقيم معلمات مختلفة. اختبارات واجهة المستخدم لإنشاء النموذج والتحقق من صحة المعلمات. اختبارات الأداء للعمليات التدفقية التي تحتوي على العديد من المعلمات. +======= +اختبارات شاملة لإطلاق العمليات مع قيم معلمات مختلفة. +اختبارات واجهة المستخدم لإنشاء النموذج والتحقق من صحة المعلمات. +اختبارات الأداء للعمليات التي تحتوي على العديد من المعلمات. +>>>>>>> 82edf2d (New md files from RunPod) حالات حافة: معلمات مفقودة، وأنواع غير صالحة، وإشارات غير معرفة للمعلمات. ## خطة الترحيل +<<<<<<< HEAD 1. يجب أن يستمر النظام في دعم مخططات العمليات التدفقية التي لا تحتوي على معلمات. معلنة. 2. يجب أن يستمر النظام في دعم العمليات التدفقية التي لا يتم فيها تحديد أي معلمات: هذا يعمل للعمليات التدفقية التي لا تحتوي على معلمات، وللعمليات التدفقية التي تحتوي على معلمات +======= +1. يجب أن يستمر النظام في دعم نماذج العمليات بدون معلمات + مُعرّفة. +2. يجب أن يستمر النظام في دعم العمليات بدون تحديد معلمات: + هذا يعمل للعمليات التي لا تحتوي على معلمات، وللعمليات التي تحتوي على معلمات +>>>>>>> 82edf2d (New md files from RunPod) (لديها قيم افتراضية). ## أسئلة مفتوحة +<<<<<<< HEAD س: هل يجب أن تدعم المعلمات كائنات متداخلة معقدة أم يجب الالتزام بأنواع بسيطة؟ ج: سيتم ترميز قيم المعلمات كسلاسل نصية، لذلك من المحتمل أن نلتزم بالسلاسل النصية. @@ -478,8 +584,28 @@ Substituted in processor: "0.7" (string) س: هل يجب أن ندعم المعلمات المحسوبة (المشتقة من معلمات أخرى)؟ ج: مجرد استبدال السلاسل النصية لإزالة عمليات الحقن والحالات الحافة الغريبة. +======= +س: هل يجب أن تدعم المعلمات كائنات متداخلة معقدة أم تقتصر على الأنواع البسيطة؟ +ج: سيتم ترميز قيم المعلمات كسلاسل نصية، ومن المحتمل أن نلتزم بالسلاسل النصية. + + +س: هل يجب السماح بوضع إشارات المعلمات في أسماء قوائم الانتظار أم فقط في + المعلمات؟ +ج: فقط في المعلمات لإزالة الحقن والحالات الحافة الغريبة. + +س: كيف نتعامل مع التعارضات بين أسماء المعلمات ومتغيرات النظام مثل + `id` و `class`؟ +ج: من غير المسموح بتحديد المعرف (id) والفئة (class) عند إطلاق عملية. + +س: هل يجب أن ندعم المعلمات المحسوبة (المشتقة من معلمات أخرى)؟ +ج: مجرد استبدال السلاسل النصية لإزالة الحقن والحالات الحافة الغريبة. +>>>>>>> 82edf2d (New md files from RunPod) ## المراجع مواصفات مخطط JSON: https://json-schema.org/ +<<<<<<< HEAD مواصفات تعريف مخطط العمليات التدفقية: docs/tech-specs/flow-class-definition.md +======= +مواصفات تعريف نموذج العملية: docs/tech-specs/flow-class-definition.md +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/flow-configurable-parameters.es.md b/docs/tech-specs/flow-configurable-parameters.es.md index f48bdd47..b02e84d8 100644 --- a/docs/tech-specs/flow-configurable-parameters.es.md +++ b/docs/tech-specs/flow-configurable-parameters.es.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD # Especificación Técnica de Parámetros Configurables para Flow Blueprint ## Resumen @@ -10,11 +11,26 @@ 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. +======= +# Especificación Técnica de Parámetros Configurables para el Blueprint de Flujo + +## Resumen + +Esta especificación describe la implementación de parámetros configurables para blueprints de flujo 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 blueprint del flujo. + +Los parámetros funcionan mediante la sustitución de variables de plantilla en los parámetros del procesador, de manera similar a como 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 de 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 fragmento y los límites de concurrencia. +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD **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. @@ -27,19 +43,41 @@ La integración admite cuatro casos de uso principales: ## 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. +======= +**Configuración Dinámica del Procesador**: Permitir la configuración en tiempo de ejecución de los parámetros del procesador mediante 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 razonables, 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 la 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 blueprints de flujo. +**Compatibilidad con Versiones Anteriores**: Mantener la compatibilidad con los blueprints de flujo existentes que no utilizan parámetros. + +## Antecedentes + +Los blueprints de flujo 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. +>>>>>>> 82edf2d (New md files from RunPod) 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: +<<<<<<< HEAD Declaran en las definiciones de flow blueprint. +======= +Declaran en las definiciones de blueprints de flujo. +>>>>>>> 82edf2d (New md files from RunPod) 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: +<<<<<<< HEAD Reducir la duplicación de flow blueprints mediante el uso de parámetros para las variaciones. +======= +Reducir la duplicación de blueprints de flujo mediante el uso de parámetros para las variaciones. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -51,7 +89,11 @@ Mantener la seguridad de tipos a través de la validación del esquema de parám El sistema de parámetros configurables requiere los siguientes componentes técnicos: 1. **Definición del Esquema de Parámetros** +<<<<<<< HEAD Definiciones de parámetros basadas en JSON Schema dentro de los metadatos del flow blueprint. +======= + Definiciones de parámetros basadas en esquemas JSON dentro de los metadatos del blueprint de flujo. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -80,10 +122,17 @@ El sistema de parámetros configurables requiere los siguientes componentes téc Módulo: trustgraph-flow/trustgraph/flow/launcher.py 5. **Formularios de Parámetros de la Interfaz de Usuario** +<<<<<<< HEAD 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. +======= + Generación dinámica de formularios a partir de metadatos de 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 definiciones de tipos de parámetros. +>>>>>>> 82edf2d (New md files from RunPod) Preajustes y plantillas de parámetros. Módulo: trustgraph-ui/components/flow-parameters/ @@ -217,6 +266,7 @@ Los diagramas de flujo definen los metadatos de los parámetros con referencias } ``` +<<<<<<< HEAD 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 @@ -237,6 +287,28 @@ 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: +======= +La sección `parameters` asigna 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): Marcador booleano 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 coherente 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 del flujo + +La API de inicio del flujo acepta parámetros utilizando los nombres de parámetros del flujo: +>>>>>>> 82edf2d (New md files from RunPod) ```json { @@ -252,8 +324,13 @@ La API de inicio de flujo acepta parámetros utilizando los nombres de parámetr 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`. +<<<<<<< HEAD El sistema realizará lo siguiente: 1. Extraer metadatos de parámetros de la definición de la plantilla de flujo. +======= +El sistema realizará las siguientes acciones: +1. Extraer metadatos de parámetros de la definición de la plantilla del flujo. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -268,7 +345,11 @@ Cuando se inicia un flujo, el sistema realiza los siguientes pasos de resolució 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: +<<<<<<< HEAD Recuperar la definición de tipo del parámetro del almacén de esquema/configuración utilizando el campo `type`. +======= + Recuperar la definición de tipo del parámetro del almacén de esquemas/configuración utilizando el campo `type`. +>>>>>>> 82edf2d (New md files from RunPod) 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**: @@ -292,7 +373,11 @@ El conjunto completo de parámetros (incluidos los valores predeterminados aplic 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. +<<<<<<< HEAD #### Herencia de parámetros con control +======= +#### Herencia de parámetros con "controlled-by" +>>>>>>> 82edf2d (New md files from RunPod) 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: @@ -313,7 +398,11 @@ En el modo básico/simple: Los parámetros con `controlled-by` pueden estar ocul 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. +<<<<<<< HEAD #### Integración de Pulsar +======= +#### Integración con Pulsar +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -371,7 +460,11 @@ El servicio de configuración de flujo (`trustgraph-flow/trustgraph/config/servi Esta función debe: Extraer los metadatos de los parámetros de la sección `parameters` del plano de flujo. +<<<<<<< HEAD Para cada parámetro, obtener la definición de tipo de la tienda de configuración. +======= + Para cada parámetro, obtener la definición de tipo del almacén de configuración. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -384,50 +477,86 @@ El servicio de configuración de flujo (`trustgraph-flow/trustgraph/config/servi 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". +<<<<<<< HEAD Cada definición de tipo contiene un esquema, un valor predeterminado y reglas de validación. +======= + Cada definición de tipo contiene el esquema, el valor predeterminado y las reglas de validación. +>>>>>>> 82edf2d (New md files from RunPod) 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** +<<<<<<< HEAD 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. +======= + 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ámetro 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ámetro resueltos finales utilizados para el flujo. +>>>>>>> 82edf2d (New md files from RunPod) #### 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: +<<<<<<< HEAD Aceptar valores de parámetros a través de indicadores de línea de comandos o archivos de configuración. +======= + Aceptar valores de parámetro a través de indicadores de línea de comandos o archivos de configuración. +>>>>>>> 82edf2d (New md files from RunPod) 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: +<<<<<<< HEAD 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. +======= + Mostrar los valores de parámetro utilizados cuando se inició el flujo. + Mostrar los parámetros disponibles para un plano de flujo. + Mostrar los esquemas de validación y los valores predeterminados de los parámetros. +>>>>>>> 82edf2d (New md files from RunPod) #### 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. +<<<<<<< HEAD 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. +======= + Los procesadores deben poder invocar ParametersSpec para configurar sus parámetros con los valores de parámetro resueltos en el momento del inicio 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 las restricciones esperadas. + Proporcionar el manejo de errores para las referencias de parámetros faltantes o no válidas. +>>>>>>> 82edf2d (New md files from RunPod) #### 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}`. +<<<<<<< HEAD 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. +======= +Las referencias de parámetros no válidas dan como resultado errores en el momento del inicio. +La validación de tipos se basa en la definición de parámetro almacenada de forma centralizada. +**IMPORTANTE**: Todos los valores de los parámetros se almacenan y transmiten como cadenas. +>>>>>>> 82edf2d (New md files from RunPod) 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())`. @@ -452,6 +581,7 @@ Pruebas de integración para la sustitución de parámetros en los parámetros d 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. +<<<<<<< HEAD Casos extremos: parámetros faltantes, tipos no válidos, referencias de parámetros no definidos. ## Plan de Migración @@ -459,12 +589,25 @@ Casos extremos: parámetros faltantes, tipos no válidos, referencias de paráme 1. El sistema debe seguir soportando planos de flujo sin parámetros declarados. 2. El sistema debe seguir soportando flujos sin parámetros especificados: +======= +Casos extremos: parámetros faltantes, tipos inválidos, referencias de parámetros no definidos. + +## Plan de Migración + +1. El sistema debe continuar admitiendo planos de flujo sin parámetros + declarados. +2. El sistema debe continuar admitiendo flujos sin parámetros especificados: +>>>>>>> 82edf2d (New md files from RunPod) Esto funciona para flujos sin parámetros y para flujos con parámetros (que tienen valores predeterminados). ## Preguntas Abiertas +<<<<<<< HEAD P: ¿Deben los parámetros soportar objetos anidados complejos o limitarse a tipos simples? +======= +P: ¿Deben los parámetros admitir objetos anidados complejos o limitarse a tipos simples? +>>>>>>> 82edf2d (New md files from RunPod) R: Los valores de los parámetros se codificarán como cadenas, por lo que probablemente queremos limitarnos a cadenas. @@ -476,10 +619,18 @@ P: ¿Cómo manejar los conflictos entre los nombres de los parámetros y las var `id` y `class`? R: No es válido especificar "id" y "class" al iniciar un flujo. +<<<<<<< HEAD P: ¿Debemos soportar parámetros calculados (derivados de otros parámetros)? +======= +P: ¿Debemos admitir parámetros calculados (derivados de otros parámetros)? +>>>>>>> 82edf2d (New md files from RunPod) 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/ +<<<<<<< HEAD Especificación de la Definición del Plano de Flujo: docs/tech-specs/flow-class-definition.md +======= +Especificación de la definición del plano de flujo: docs/tech-specs/flow-class-definition.md +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/flow-configurable-parameters.he.md b/docs/tech-specs/flow-configurable-parameters.he.md index c324efa9..63d20d62 100644 --- a/docs/tech-specs/flow-configurable-parameters.he.md +++ b/docs/tech-specs/flow-configurable-parameters.he.md @@ -2,7 +2,11 @@ ## סקירה כללית +<<<<<<< HEAD מפרט זה מתאר את יישום הפרמטרים הניתנים להגדרה עבור תבניות זרימה ב-TrustGraph. פרמטרים מאפשרים למשתמשים להתאים אישית את פרמטרי המעבד בזמן הפעלת הזרימה על ידי מתן ערכים המחליפים את מקומות הפרמטרים בהגדרת תבנית הזרימה. +======= +מפרט זה מתאר את יישום הפרמטרים הניתנים להגדרה עבור תבניות זרימה ב-TrustGraph. פרמטרים מאפשרים למשתמשים להתאים אישית את פרמטרי המעבד בזמן הפעלת הזרימה על ידי מתן ערכים שמחליפים את מקומות הפרמטרים בהגדרת תבנית הזרימה. +>>>>>>> 82edf2d (New md files from RunPod) פרמטרים פועלים באמצעות החלפת משתנים בתבניות בפרמטרי המעבד, בדומה לאופן שבו משתנים `{id}` ו-`{class}` פועלים, אך עם ערכים שמסופקים על ידי המשתמש. @@ -10,7 +14,11 @@ 1. **בחירת מודל**: לאפשר למשתמשים לבחור מודלים שונים של LLM (לדוגמה, `gemma3:8b`, `gpt-4`, `claude-3`) עבור מעבדים. 2. **תצורת משאבים**: התאמת פרמטרי מעבד כגון גודל חבילות, גודל אצווה ומגבלות מקביליות. +<<<<<<< HEAD 3. **כוונון התנהגות**: שינוי התנהגות המעבד באמצעות פרמטרים כגון טמפרטורה, מקסימום טוקנים או ספי תאחזור. +======= +3. **כוונון התנהגות**: שינוי התנהגות המעבד באמצעות פרמטרים כגון טמפרטורה, מקסימום טוקנים או ספי הצעת מחיר. +>>>>>>> 82edf2d (New md files from RunPod) 4. **פרמטרים ספציפיים לסביבה**: הגדרת נקודות קצה, מפתחות API או כתובות URL ספציפיות לאזור עבור כל פריסה. ## מטרות @@ -21,16 +29,28 @@ **החלפת תבניות**: להחליף בצורה חלקה את מקומות הפרמטרים בפרמטרי המעבד. **אינטגרציה עם ממשק משתמש**: לאפשר הזנת פרמטרים באמצעות ממשקי API וממשקי משתמש. **בטיחות סוגים**: להבטיח שטיפוסי הפרמטרים תואמים לטיפוסי פרמטרי המעבד הצפויים. +<<<<<<< HEAD **תיעוד**: סכימות פרמטרים המתועדות באופן עצמי בתוך הגדרות תבניות הזרימה. +======= +**תיעוד**: סכימות פרמטרים המתועדות באופן עצמי בתוך הגדרות תבניות זרימה. +>>>>>>> 82edf2d (New md files from RunPod) **תאימות לאחור**: לשמור על תאימות לתבניות זרימה קיימות שאינן משתמשות בפרמטרים. ## רקע +<<<<<<< HEAD תבניות זרימה ב-TrustGraph תומכות כעת בפרמטרי מעבד שניתן להכיל ערכים קבועים או מקומות שמירת פרמטרים. זה יוצר הזדמנות להתאמה אישית בזמן ריצה. פרמטרי מעבד קיימים תומכים ב: ערכים קבועים: `"model": "gemma3:12b"` מקומות שמירת פרמטרים: `"model": "gemma3:{model-size}"` +======= +תבניות זרימה ב-TrustGraph תומכות כעת בפרמטרי מעבד שניתן להכיל ערכים קבועים או מקומות פרמטרים. זה יוצר הזדמנות להתאמה אישית בזמן ריצה. + +פרמטרי מעבד קיימים תומכים ב: +ערכים קבועים: `"model": "gemma3:12b"` +מקומות פרמטרים: `"model": "gemma3:{model-size}"` +>>>>>>> 82edf2d (New md files from RunPod) מפרט זה מגדיר כיצד פרמטרים: מוצהרים בהגדרות תבניות זרימה @@ -38,7 +58,11 @@ מוכנסים לפרמטרי מעבד נחשפים באמצעות ממשקי API וממשקי משתמש +<<<<<<< HEAD על ידי שימוש בפרמטרי מעבד מוגדרים, TrustGraph יכולה: +======= +על ידי שימוש בפרמטרי מעבד מותאמים אישית, TrustGraph יכולה: +>>>>>>> 82edf2d (New md files from RunPod) להפחית שכפול של תבניות זרימה על ידי שימוש בפרמטרים עבור וריאציות לאפשר למשתמשים לכוונן את התנהגות המעבד מבלי לשנות הגדרות לתמוך בתצורות ספציפיות לסביבה באמצעות ערכי פרמטרים @@ -51,9 +75,15 @@ מערכת הפרמטרים הניתנים להגדרה דורשת את הרכיבים הטכניים הבאים: 1. **הגדרת סכימת פרמטרים** +<<<<<<< HEAD הגדרות פרמטרים מבוססות סכימת JSON בתוך מטא-נתונים של תבניות זרימה הגדרות סוגים כולל מחרוזות, מספרים, בוליאנים, enum ואובייקטים כללי אימות כולל ערכים מינימליים/מקסימליים, תבניות ושדות חובה +======= + הגדרות פרמטרים המבוססות על סכימת JSON בתוך מטא-נתונים של תבניות זרימה + הגדרות סוגים כולל מחרוזות, מספרים, בוליאנים, enum ואובייקטים + כללי אימות כולל ערכים מינימליים/מקסימליים, תבניות ושדות נדרשים +>>>>>>> 82edf2d (New md files from RunPod) מודול: trustgraph-flow/trustgraph/flow/definition.py @@ -84,7 +114,11 @@ תצוגה מסודרת של פרמטרים באמצעות שדה `order` תגיות תיאוריות של פרמטרים באמצעות שדה `description` אימות קלט מול הגדרות סוג פרמטרים +<<<<<<< HEAD ערכות מקדימות ותבניות פרמטרים +======= + ערכות חכמות ותבניות פרמטרים +>>>>>>> 82edf2d (New md files from RunPod) מודול: trustgraph-ui/components/flow-parameters/ @@ -93,7 +127,11 @@ #### הגדרות פרמטרים (מאוחסנות בסכימה/תצורה) הגדרות פרמטרים מאוחסנות באופן מרכזי במערכת הסכימות והתצורה עם סוג "parameter-type": +<<<<<<< HEAD פלט חוזה (יש לעקוב בדיוק אחר הפורמט הבא). +======= +פלט חוזה (יש לעקוב אחר הפורמט המדויק). +>>>>>>> 82edf2d (New md files from RunPod) ```json { "llm-model": { @@ -250,14 +288,22 @@ } ``` +<<<<<<< HEAD הערה: בדוגמה זו, `llm-rag-model` אינו מסופק באופן מפורש, אך הוא יירש את הערך "claude-3" מ-`llm-model` בשל הקשר `controlled-by` שלו. באופן דומה, `chunk-overlap` יכול לרשת ערך מחושב המבוסס על `chunk-size`. +======= +הערה: בדוגמה זו, `llm-rag-model` אינו מסופק באופן מפורש, אך הוא יירש את הערך "claude-3" מ-`llm-model` עקב הקשר `controlled-by` שלו. באופן דומה, `chunk-overlap` יכול לרשת ערך מחושב המבוסס על `chunk-size`. +>>>>>>> 82edf2d (New md files from RunPod) המערכת תבצע את הפעולות הבאות: 1. חילוץ מטא-נתונים של פרמטרים מהגדרת תבנית זרימה 2. מיפוי שמות פרמטרים של זרימה להגדרות הסוג שלהם (לדוגמה, `llm-model` → סוג `llm-model`) 3. פתרון קשרים "שולט ב" (controlled-by) (לדוגמה, `llm-rag-model` יורש מ-`llm-model`) 4. אימות ערכים שסופקו על ידי המשתמש וערכים שירשו בהתאם להגדרות הסוג של הפרמטרים +<<<<<<< HEAD 5. החלפת ערכים שפתורים לתוך פרמטרים של מעבדים במהלך יצירת זרימה +======= +5. החלפת ערכים פתורים לפרמטרים של מעבדים במהלך יצירת זרימה +>>>>>>> 82edf2d (New md files from RunPod) ### פרטי יישום @@ -268,13 +314,19 @@ 1. **טעינת תבנית זרימה**: טעינת הגדרת תבנית זרימה וחילוץ מטא-נתונים של פרמטרים 2. **חילוץ מטא-נתונים**: חילוץ `type`, `description`, `order`, `advanced` ו-`controlled-by` עבור כל פרמטר המוגדר בתבנית הזרימה בסעיף `parameters` 3. **חיפוש הגדרת סוג**: עבור כל פרמטר בתבנית הזרימה: +<<<<<<< HEAD אחזור הגדרת הסוג של הפרמטר ממחסן הסכימה/התצורה באמצעות השדה `type` הגדרות הסוג מאוחסנות עם הסוג "parameter-type" במערכת התצורה +======= + אחזור הגדרת הסוג של הפרמטר ממחסן הסכימה/הגדרות באמצעות השדה `type` + הגדרות הסוג מאוחסנות עם הסוג "parameter-type" במערכת ההגדרות +>>>>>>> 82edf2d (New md files from RunPod) כל הגדרת סוג מכילה את הסכימה של הפרמטר, ערך ברירת מחדל וכללי אימות 4. **פתרון ערך ברירת מחדל**: עבור כל פרמטר המוגדר בתבנית הזרימה: בדיקה האם המשתמש סיפק ערך עבור פרמטר זה אם לא סופק ערך על ידי המשתמש, השתמש בערך `default` מהגדרת סוג הפרמטר +<<<<<<< HEAD יצירת מפת פרמטרים שלמה המכילה הן ערכים שסופקו על ידי המשתמש והן ערכי ברירת מחדל 5. **פתרון ירושה של פרמטרים** (קשרים "שולט ב"): עבור פרמטרים עם שדה `controlled-by`, בדוק האם סופק ערך באופן מפורש @@ -284,13 +336,28 @@ 6. **אימות**: אימות קבוצת הפרמטרים השלמה (ערכים שסופקו על ידי המשתמש, ברירות מחדל וערכים שירשו) בהתאם להגדרות הסוג 7. **אחסון**: אחסון קבוצת הפרמטרים השלמה שפתורה עם מופע הזרימה לצורך ביקורת 8. **החלפת תבניות**: החלפת מקומות שמורות של פרמטרים בפרמטרים של מעבדים עם ערכים שפתורים +======= + יצירת מפת פרמטרים שלמה המכילה גם ערכים שסופקו על ידי המשתמש וגם ערכי ברירת מחדל +5. **פתרון ירושה של פרמטרים** (קשרים "שולט ב"): + עבור פרמטרים עם שדה `controlled-by`, בדוק האם סופק ערך באופן מפורש + אם לא סופק ערך מפורש, ירוש את הערך מהפרמטר השולט + אם גם לפרמטר השולט אין ערך, השתמש בברירת המחדל מהגדרת הסוג + ודא שאין תלות מעגלית בקשרי `controlled-by` +6. **אימות**: אימות קבוצת הפרמטרים השלמה (ערכים שסופקו על ידי המשתמש, ברירות מחדל וערכים שירשו) בהתאם להגדרות הסוג +7. **אחסון**: אחסון קבוצת הפרמטרים הפתורים השלמה עם מופע הזרימה לצורך ביקורת +8. **החלפת תבניות**: החלפת מקומות שמורות של פרמטרים בפרמטרים של מעבדים עם ערכים פתורים +>>>>>>> 82edf2d (New md files from RunPod) 9. **יצירת מעבדים**: יצירת מעבדים עם פרמטרים שהוחלפו **הערות חשובות ליישום:** שירות הזרימה חייב למזג פרמטרים שסופקו על ידי המשתמש עם ברירות מחדל מהגדרות סוג הפרמטרים קבוצת הפרמטרים השלמה (כולל ברירות המחדל המיושמות) חייבת להיות מאוחסנת עם הזרימה לצורך מעקב פתרון פרמטרים מתרחש בזמן התחלת הזרימה, ולא בזמן יצירת המעבד +<<<<<<< HEAD פרמטרים חסרים שנדרשים ללא ברירות מחדל חייבים לגרום לכישלון התחלת הזרימה עם הודעת שגיאה ברורה +======= +פרמטרים חסרים הדורשים ברירות מחדל חייבים לגרום לכישלון התחלת הזרימה עם הודעת שגיאה ברורה +>>>>>>> 82edf2d (New md files from RunPod) #### ירושת פרמטרים עם "שולט ב" @@ -311,7 +378,11 @@ **התנהגות ממשק משתמש**: במצב בסיסי/פשוט: פרמטרים עם `controlled-by` עשויים להיות מוסתרים או מוצגים כקריאה בלבד עם ערך שירש במצב מתקדם: מוצגים כל הפרמטרים וניתן להגדיר אותם באופן אינדיבידואלי +<<<<<<< HEAD כאשר פרמטר שולט משתנה, פרמטרים תלויים מתעדכנים אוטומטית אלא אם כן הם נדחפים באופן מפורש +======= +כאשר פרמטר שולט משתנה, פרמטרים תלויים מתעדכנים אוטומטית אלא אם כן הם דורסים באופן מפורש +>>>>>>> 82edf2d (New md files from RunPod) #### אינטגרציה עם Pulsar @@ -370,9 +441,15 @@ ``` פונקציה זו צריכה: +<<<<<<< HEAD לחלץ מטא-נתונים של פרמטרים מתוך סעיף `parameters` של תוכנית העבודה (blueprint). עבור כל פרמטר, לשלוף את הגדרת הסוג שלו ממאגר התצורה. להחיל ערכי ברירת מחדל עבור כל פרמטרים שאינם מסופקים על ידי המשתמש. +======= + לחלץ מטא-נתונים של פרמטרים מסעיף `parameters` של תוכנית העבודה (blueprint). + עבור כל פרמטר, לשלוף את הגדרת הסוג שלו ממאגר התצורה. + להחיל ערכי ברירת מחדל עבור כל פרמטרים שלא סופקו על ידי המשתמש. +>>>>>>> 82edf2d (New md files from RunPod) לטפל ביחסי ירושה `controlled-by`. להחזיר את קבוצת הפרמטרים השלמה. @@ -429,7 +506,11 @@ אימות סוג מתרחש בהתבסס על הגדרת הפרמטר המאוחסנת במרכז. **חשוב**: כל ערכי הפרמטרים מאוחסנים ומועברים כרצף תווים. מספרים מומרים לרצף תווים (לדוגמה, `0.7` הופך ל-`"0.7"`). +<<<<<<< HEAD ערכים בוליאניים מומרים לרצף תווים קטן (לדוגמה, `true` הופך ל-`"true"`). +======= + בוליאנים מומרים לרצף תווים קטן (לדוגמה, `true` הופך ל-`"true"`). +>>>>>>> 82edf2d (New md files from RunPod) זה נדרש על ידי הסכימה של Pulsar, אשר מגדירה `parameters = Map(String())`. דוגמה לפענוח: @@ -457,14 +538,22 @@ Substituted in processor: "0.7" (string) ## תוכנית מעבר 1. המערכת צריכה להמשיך לתמוך בתבניות זרימה ללא פרמטרים +<<<<<<< HEAD מוצהרים. +======= + מוגדרים. +>>>>>>> 82edf2d (New md files from RunPod) 2. המערכת צריכה להמשיך לתמוך בזרימות ללא פרמטרים מוגדרים: זה עובד עבור זרימות ללא פרמטרים, וזרימות עם פרמטרים (שיש להם ערכי ברירת מחדל). ## שאלות פתוחות +<<<<<<< HEAD ש: האם הפרמטרים צריכים לתמוך באובייקטים מקוננים מורכבים או להישאר בסוגים פשוטים? +======= +ש: האם פרמטרים צריכים לתמוך באובייקטים מקוננים מורכבים או להישאר בסוגים פשוטים? +>>>>>>> 82edf2d (New md files from RunPod) ת: ערכי הפרמטרים יועברו כרצף תווים, סביר להניח שנרצה להישאר ברצפים תווים. @@ -473,11 +562,19 @@ Substituted in processor: "0.7" (string) ת: רק בפרמטרים כדי למנוע הזרקות ותופעות לוואי. ש: כיצד לטפל בקונפליקטים בין שמות פרמטרים למשתנים של המערכת כמו +<<<<<<< HEAD `id` ו- `class`? ת: לא חוקי לציין id ו-class בעת הפעלת זרימה. ש: האם אנו תומכים בפרמטרים מחושבים (נגזרים מפרמטרים אחרים)? ת: רק החלפת רצפי תווים כדי למנוע הזרקות ותופעות לוואי. +======= + `id` ו-`class`? +ת: לא חוקי לציין id ו-class בעת הפעלת זרימה. + +ש: האם אנו תומכים בפרמטרים מחושבים (נגזרים מפרמטרים אחרים)? +ת: רק החלפת רצפים תווים כדי למנוע הזרקות ותופעות לוואי. +>>>>>>> 82edf2d (New md files from RunPod) ## הפניות diff --git a/docs/tech-specs/flow-configurable-parameters.hi.md b/docs/tech-specs/flow-configurable-parameters.hi.md index 300687d7..d748a142 100644 --- a/docs/tech-specs/flow-configurable-parameters.hi.md +++ b/docs/tech-specs/flow-configurable-parameters.hi.md @@ -11,18 +11,30 @@ 1. **मॉडल चयन**: उपयोगकर्ताओं को प्रोसेसर के लिए विभिन्न एलएलएम मॉडल (जैसे, `gemma3:8b`, `gpt-4`, `claude-3`) चुनने की अनुमति देना 2. **संसाधन कॉन्फ़िगरेशन**: प्रोसेसर पैरामीटर जैसे कि चंक आकार, बैच आकार और समवर्ती सीमा को समायोजित करना 3. **व्यवहार ट्यूनिंग**: तापमान, अधिकतम-टोकन या पुनर्प्राप्ति थ्रेसहोल्ड जैसे पैरामीटर के माध्यम से प्रोसेसर व्यवहार को संशोधित करना +<<<<<<< HEAD 4. **पर्यावरण-विशिष्ट पैरामीटर**: प्रत्येक परिनियोजन के लिए समापन बिंदु, एपीआई कुंजियाँ या क्षेत्र-विशिष्ट यूआरएल को कॉन्फ़िगर करना +======= +4. **पर्यावरण-विशिष्ट पैरामीटर**: प्रत्येक तैनाती के लिए समापन बिंदु, एपीआई कुंजियाँ या क्षेत्र-विशिष्ट यूआरएल को कॉन्फ़िगर करना +>>>>>>> 82edf2d (New md files from RunPod) ## लक्ष्य **डायनामिक प्रोसेसर कॉन्फ़िगरेशन**: पैरामीटर प्रतिस्थापन के माध्यम से प्रोसेसर पैरामीटर के रनटाइम कॉन्फ़िगरेशन को सक्षम करना **पैरामीटर सत्यापन**: फ्लो लॉन्च समय पर पैरामीटर के लिए टाइप चेकिंग और सत्यापन प्रदान करना +<<<<<<< HEAD **डिफ़ॉल्ट मान**: समझदार डिफ़ॉल्ट का समर्थन करना जबकि उन्नत उपयोगकर्ताओं के लिए ओवरराइड की अनुमति देना +======= +**डिफ़ॉल्ट मान**: समझदार डिफ़ॉल्ट मानों का समर्थन करना जबकि उन्नत उपयोगकर्ताओं के लिए ओवरराइड की अनुमति देना +>>>>>>> 82edf2d (New md files from RunPod) **टेम्पलेट प्रतिस्थापन**: प्रोसेसर पैरामीटर में पैरामीटर प्लेसहोल्डर को निर्बाध रूप से बदलना **यूआई एकीकरण**: एपीआई और यूआई इंटरफेस दोनों के माध्यम से पैरामीटर इनपुट को सक्षम करना **टाइप सुरक्षा**: यह सुनिश्चित करना कि पैरामीटर प्रकार अपेक्षित प्रोसेसर पैरामीटर प्रकारों से मेल खाते हैं **प्रलेखन**: फ्लो ब्लूप्रिंट परिभाषाओं के भीतर स्व-प्रलेखित पैरामीटर स्कीमा +<<<<<<< HEAD **पिछड़ा संगतता**: मौजूदा फ्लो ब्लूप्रिंट के साथ संगतता बनाए रखना जो पैरामीटर का उपयोग नहीं करते हैं +======= +**पिछला संगतता**: मौजूदा फ्लो ब्लूप्रिंट के साथ संगतता बनाए रखना जो पैरामीटर का उपयोग नहीं करते हैं +>>>>>>> 82edf2d (New md files from RunPod) ## पृष्ठभूमि @@ -52,7 +64,11 @@ 1. **पैरामीटर स्कीमा परिभाषा** फ्लो ब्लूप्रिंट मेटाडेटा के भीतर JSON स्कीमा-आधारित पैरामीटर परिभाषाएँ +<<<<<<< HEAD स्ट्रिंग, नंबर, बूलियन, एनम और ऑब्जेक्ट प्रकार सहित प्रकार परिभाषाएँ +======= + स्ट्रिंग, संख्या, बूलियन, एनम और ऑब्जेक्ट प्रकार सहित प्रकार परिभाषाएँ +>>>>>>> 82edf2d (New md files from RunPod) न्यूनतम/अधिकतम मान, पैटर्न और आवश्यक फ़ील्ड सहित सत्यापन नियम मॉड्यूल: trustgraph-flow/trustgraph/flow/definition.py @@ -67,7 +83,11 @@ 3. **पैरामीटर स्टोर एकीकरण** स्कीमा/कॉन्फ़िग स्टोर से पैरामीटर परिभाषाओं की पुनर्प्राप्ति +<<<<<<< HEAD अक्सर उपयोग की जाने वाली पैरामीटर परिभाषाओं का कैशिंग +======= + बार-बार उपयोग की जाने वाली पैरामीटर परिभाषाओं का कैशिंग +>>>>>>> 82edf2d (New md files from RunPod) केंद्रीय रूप से संग्रहीत स्कीमा के विरुद्ध सत्यापन मॉड्यूल: trustgraph-flow/trustgraph/flow/parameter_store.py @@ -222,10 +242,17 @@ `description`: यूआई प्रदर्शन के लिए मानव-पठनीय विवरण `order`: पैरामीटर फ़ॉर्म के लिए प्रदर्शन क्रम (छोटे नंबर पहले दिखाई देते हैं) `advanced` (वैकल्पिक): एक बूलियन ध्वज जो इंगित करता है कि क्या यह एक उन्नत पैरामीटर है (डिफ़ॉल्ट: false)। जब इसे true पर सेट किया जाता है, तो यूआई डिफ़ॉल्ट रूप से इस पैरामीटर को छिपा सकता है या इसे "उन्नत" अनुभाग में रख सकता है +<<<<<<< HEAD `controlled-by` (वैकल्पिक): एक अन्य पैरामीटर का नाम जो सरल मोड में इस पैरामीटर के मान को नियंत्रित करता है। जब निर्दिष्ट किया जाता है, तो यह पैरामीटर अपने मान को नियंत्रित पैरामीटर से प्राप्त करता है जब तक कि स्पष्ट रूप से ओवरराइड न किया जाए यह दृष्टिकोण अनुमति देता है: कई प्रवाह ब्लूप्रिंट में पुन: प्रयोज्य पैरामीटर प्रकार परिभाषाएँ +======= +`controlled-by` (वैकल्पिक): एक अन्य पैरामीटर का नाम जो सरल मोड में इस पैरामीटर के मान को नियंत्रित करता है। जब निर्दिष्ट किया जाता है, तो यह पैरामीटर अपने मान को नियंत्रित पैरामीटर से विरासत में लेता है जब तक कि स्पष्ट रूप से ओवरराइड न किया जाए + +यह दृष्टिकोण अनुमति देता है: +कई फ़्लो ब्लूप्रिंट में पुन: प्रयोज्य पैरामीटर प्रकार परिभाषाएँ +>>>>>>> 82edf2d (New md files from RunPod) केंद्रीकृत पैरामीटर प्रकार प्रबंधन और सत्यापन प्रवाह-विशिष्ट पैरामीटर विवरण और क्रम वर्णनात्मक पैरामीटर फ़ॉर्म के साथ बेहतर यूआई अनुभव @@ -234,9 +261,15 @@ बुनियादी/उन्नत मोड अलगाव के साथ सरलीकृत यूआई संबंधित सेटिंग्स के लिए पैरामीटर मान विरासत +<<<<<<< HEAD #### प्रवाह लॉन्च अनुरोध प्रवाह लॉन्च एपीआई प्रवाह के पैरामीटर नामों का उपयोग करके पैरामीटर स्वीकार करता है: +======= +#### फ़्लो लॉन्च अनुरोध + +फ़्लो लॉन्च एपीआई प्रवाह के पैरामीटर नामों का उपयोग करके पैरामीटर स्वीकार करता है: +>>>>>>> 82edf2d (New md files from RunPod) ```json { @@ -250,12 +283,20 @@ } ``` +<<<<<<< HEAD ध्यान दें: इस उदाहरण में, `llm-rag-model` स्पष्ट रूप से प्रदान नहीं किया गया है, लेकिन यह `llm-model` से "claude-3" मान को अपने `controlled-by` संबंध के कारण प्राप्त करेगा। इसी तरह, `chunk-overlap` `chunk-size` के आधार पर गणना किए गए मान को प्राप्त कर सकता है। +======= +ध्यान दें: इस उदाहरण में, `llm-rag-model` स्पष्ट रूप से प्रदान नहीं किया गया है, लेकिन यह `llm-model` से "claude-3" मान को अपने `controlled-by` संबंध के कारण प्राप्त करेगा। इसी तरह, `chunk-overlap` `chunk-size` के आधार पर एक गणना किए गए मान को प्राप्त कर सकता है। +>>>>>>> 82edf2d (New md files from RunPod) सिस्टम निम्नलिखित कार्य करेगा: 1. फ्लो ब्लूप्रिंट परिभाषा से पैरामीटर मेटाडेटा निकालें 2. फ्लो पैरामीटर नामों को उनके प्रकार परिभाषाओं (जैसे, `llm-model` → `llm-model` प्रकार) में मैप करें +<<<<<<< HEAD 3. नियंत्रित-द्वारा संबंधों को हल करें (जैसे, `llm-rag-model` `llm-model` से प्राप्त होता है) +======= +3. नियंत्रित-द्वारा (controlled-by) संबंधों को हल करें (जैसे, `llm-rag-model` `llm-model` से प्राप्त होता है) +>>>>>>> 82edf2d (New md files from RunPod) 4. पैरामीटर प्रकार परिभाषाओं के विरुद्ध उपयोगकर्ता द्वारा प्रदान किए गए और प्राप्त मूल्यों को मान्य करें 5. फ्लो इंस्टेंशिएशन के दौरान हल किए गए मूल्यों को प्रोसेसर पैरामीटर में प्रतिस्थापित करें @@ -268,14 +309,22 @@ 1. **फ्लो ब्लूप्रिंट लोडिंग**: फ्लो ब्लूप्रिंट परिभाषा लोड करें और पैरामीटर मेटाडेटा निकालें 2. **मेटाडेटा निष्कर्षण**: फ्लो ब्लूप्रिंट के `parameters` अनुभाग में परिभाषित प्रत्येक पैरामीटर के लिए `type`, `description`, `order`, `advanced`, और `controlled-by` निकालें 3. **टाइप परिभाषा लुकअप**: फ्लो ब्लूप्रिंट में प्रत्येक पैरामीटर के लिए: +<<<<<<< HEAD स्कीमा/कॉन्फ़िग स्टोर से `type` फ़ील्ड का उपयोग करके पैरामीटर प्रकार परिभाषा प्राप्त करें +======= + `type` फ़ील्ड का उपयोग करके स्कीमा/कॉन्फ़िग स्टोर से पैरामीटर प्रकार परिभाषा प्राप्त करें +>>>>>>> 82edf2d (New md files from RunPod) प्रकार परिभाषाएँ कॉन्फ़िग सिस्टम में "parameter-type" प्रकार के साथ संग्रहीत की जाती हैं प्रत्येक प्रकार की परिभाषा में पैरामीटर का स्कीमा, डिफ़ॉल्ट मान और सत्यापन नियम होते हैं 4. **डिफ़ॉल्ट मान रिज़ॉल्यूशन**: फ्लो ब्लूप्रिंट में परिभाषित प्रत्येक पैरामीटर के लिए: जांचें कि क्या उपयोगकर्ता ने इस पैरामीटर के लिए कोई मान प्रदान किया है यदि कोई उपयोगकर्ता मान प्रदान नहीं किया गया है, तो पैरामीटर प्रकार परिभाषा से `default` मान का उपयोग करें +<<<<<<< HEAD उपयोगकर्ता द्वारा प्रदान किए गए और डिफ़ॉल्ट मानों दोनों को शामिल करते हुए एक पूर्ण पैरामीटर मानचित्र बनाएं +======= + उपयोगकर्ता द्वारा प्रदान किए गए और डिफ़ॉल्ट मानों दोनों को शामिल करते हुए एक पूर्ण पैरामीटर मैप बनाएं +>>>>>>> 82edf2d (New md files from RunPod) 5. **पैरामीटर इनहेरिटेंस रिज़ॉल्यूशन** (नियंत्रित-द्वारा संबंध): `controlled-by` फ़ील्ड वाले पैरामीटर के लिए, जांचें कि क्या कोई मान स्पष्ट रूप से प्रदान किया गया था यदि कोई स्पष्ट मान प्रदान नहीं किया गया है, तो नियंत्रित पैरामीटर से मान प्राप्त करें @@ -287,9 +336,15 @@ 9. **प्रोसेसर इंस्टेंशिएशन**: प्रतिस्थापित पैरामीटर के साथ प्रोसेसर बनाएं **महत्वपूर्ण कार्यान्वयन नोट्स:** +<<<<<<< HEAD फ्लो सर्विस को पैरामीटर प्रकार परिभाषाओं से डिफ़ॉल्ट के साथ उपयोगकर्ता द्वारा प्रदान किए गए पैरामीटर को मर्ज करना होगा पूर्ण पैरामीटर सेट (लागू डिफ़ॉल्ट सहित) को पता लगाने के लिए फ्लो के साथ संग्रहीत किया जाना चाहिए पैरामीटर रिज़ॉल्यूशन फ्लो शुरू होने के समय होता है, प्रोसेसर इंस्टेंशिएशन के समय नहीं +======= +फ्लो सेवा को उपयोगकर्ता द्वारा प्रदान किए गए पैरामीटर को पैरामीटर प्रकार परिभाषाओं से डिफ़ॉल्ट के साथ मर्ज करना होगा +पूर्ण पैरामीटर सेट (लागू डिफ़ॉल्ट सहित) को ट्रेसबिलिटी के लिए फ्लो के साथ संग्रहीत किया जाना चाहिए +पैरामीटर रिज़ॉल्यूशन फ्लो शुरू होने के समय होता है, न कि प्रोसेसर इंस्टेंशिएशन के समय +>>>>>>> 82edf2d (New md files from RunPod) डिफ़ॉल्ट के बिना आवश्यक पैरामीटर गायब होने से फ्लो शुरू होने में विफलता होनी चाहिए, साथ ही एक स्पष्ट त्रुटि संदेश भी #### नियंत्रित-द्वारा के साथ पैरामीटर इनहेरिटेंस @@ -316,7 +371,11 @@ #### पल्सर एकीकरण 1. **स्टार्ट-फ्लो ऑपरेशन** +<<<<<<< HEAD पल्सर स्टार्ट-फ्लो ऑपरेशन को एक `parameters` फ़ील्ड स्वीकार करना होगा जिसमें पैरामीटर मानों का एक मानचित्र होता है +======= + पल्सर स्टार्ट-फ्लो ऑपरेशन को एक `parameters` फ़ील्ड स्वीकार करना होगा जिसमें पैरामीटर मानों का एक मैप हो +>>>>>>> 82edf2d (New md files from RunPod) स्टार्ट-फ्लो अनुरोध के लिए पल्सर स्कीमा को वैकल्पिक `parameters` फ़ील्ड को शामिल करने के लिए अपडेट किया जाना चाहिए उदाहरण अनुरोध: ```json @@ -374,12 +433,21 @@ प्रत्येक पैरामीटर के लिए, कॉन्फ़िगरेशन स्टोर से इसके प्रकार की परिभाषा प्राप्त करें उन सभी पैरामीटर के लिए डिफ़ॉल्ट मान लागू करें जो उपयोगकर्ता द्वारा प्रदान नहीं किए गए हैं `controlled-by` विरासत संबंधों को संभालें +<<<<<<< HEAD संपूर्ण पैरामीटर सेट लौटाएं 2. **संशोधित `handle_start_flow` विधि** फ़्लो ब्लूप्रिंट लोड करने के बाद `resolve_parameters` को कॉल करें टेम्पलेट प्रतिस्थापन के लिए पूरे हल किए गए पैरामीटर सेट का उपयोग करें पूरे पैरामीटर सेट को (केवल उपयोगकर्ता द्वारा प्रदान किए गए नहीं) फ़्लो के साथ संग्रहीत करें +======= + पूर्ण पैरामीटर सेट लौटाएं + +2. **संशोधित `handle_start_flow` विधि** + फ़्लो ब्लूप्रिंट लोड करने के बाद `resolve_parameters` को कॉल करें + टेम्पलेट प्रतिस्थापन के लिए पूर्ण हल किए गए पैरामीटर सेट का उपयोग करें + पूर्ण पैरामीटर सेट (केवल उपयोगकर्ता द्वारा प्रदान किए गए नहीं) को फ़्लो के साथ संग्रहीत करें +>>>>>>> 82edf2d (New md files from RunPod) सत्यापित करें कि सभी आवश्यक पैरामीटर में मान हैं 3. **पैरामीटर प्रकार प्राप्त करना** @@ -391,8 +459,13 @@ 3. **फ़्लो ऑब्जेक्ट स्टोरेज** जब कोई फ़्लो घटक कॉन्फ़िगर प्रबंधक में कॉन्फ़िगर सिस्टम में जोड़ा जाता है, तो फ़्लो ऑब्जेक्ट में हल किए गए पैरामीटर मान शामिल होने चाहिए +<<<<<<< HEAD कॉन्फ़िगर प्रबंधक को मूल उपयोगकर्ता-प्रदान किए गए पैरामीटर और हल किए गए मान दोनों (डिफ़ॉल्ट लागू किए गए) को संग्रहीत करने की आवश्यकता होती है कॉन्फ़िगर सिस्टम में फ़्लो ऑब्जेक्ट में शामिल होना चाहिए: +======= + कॉन्फ़िगर प्रबंधक को मूल उपयोगकर्ता-प्रदान किए गए पैरामीटर और हल किए गए मान (डिफ़ॉल्ट लागू होने के साथ) दोनों को संग्रहीत करने की आवश्यकता है + कॉन्फ़िगर सिस्टम में फ़्लो ऑब्जेक्ट में निम्नलिखित शामिल होने चाहिए: +>>>>>>> 82edf2d (New md files from RunPod) `parameters`: फ़्लो के लिए उपयोग किए गए अंतिम हल किए गए पैरामीटर मान #### CLI एकीकरण @@ -413,7 +486,11 @@ 5. **पैरामीटरस्पेक समर्थन** प्रोसेसर बेस क्लास को मौजूदा पैरामीटर्सस्पेक तंत्र के माध्यम से पैरामीटर प्रतिस्थापन का समर्थन करने की आवश्यकता है पैरामीटर्सस्पेक क्लास (उपभोक्तास्पेक और प्रोड्यूसरस्पेक के समान मॉड्यूल में स्थित) को पैरामीटर टेम्पलेट प्रतिस्थापन का समर्थन करने के लिए आवश्यक होने पर बढ़ाया जाना चाहिए +<<<<<<< HEAD प्रोसेसर को अपने पैरामीटर को कॉन्फ़िगर करने के लिए पैरामीटर्सस्पेक को कॉल करने में सक्षम होना चाहिए, जिसमें फ़्लो लॉन्च समय पर हल किए गए पैरामीटर मान शामिल हैं +======= + प्रोसेसर को अपने पैरामीटर को कॉन्फ़िगर करने के लिए पैरामीटर्सस्पेक को लागू करने में सक्षम होना चाहिए, जिसमें फ़्लो लॉन्च समय पर हल किए गए पैरामीटर मान शामिल हैं +>>>>>>> 82edf2d (New md files from RunPod) पैरामीटर्सस्पेक कार्यान्वयन को: पैरामीटर कॉन्फ़िगरेशन स्वीकार करें जिसमें पैरामीटर प्लेसहोल्डर शामिल हैं (जैसे, `{model}`, `{temperature}`) प्रोसेसर के इंस्टेंट होने पर रनटाइम पैरामीटर प्रतिस्थापन का समर्थन करें @@ -422,7 +499,11 @@ #### प्रतिस्थापन नियम +<<<<<<< HEAD प्रोसेसर पैरामीटर में पैरामीटर `{parameter-name}` प्रारूप का उपयोग करते हैं +======= +पैरामीटर प्रोसेसर पैरामीटर में `{parameter-name}` प्रारूप का उपयोग करते हैं +>>>>>>> 82edf2d (New md files from RunPod) पैरामीटर में पैरामीटर नाम फ़्लो के `parameters` अनुभाग में कुंजियों से मेल खाते हैं प्रतिस्थापन `{id}` और `{class}` प्रतिस्थापन के साथ-साथ होता है अमान्य पैरामीटर संदर्भ लॉन्च-टाइम त्रुटियों का परिणाम देते हैं @@ -430,7 +511,11 @@ **महत्वपूर्ण**: सभी पैरामीटर मान स्ट्रिंग के रूप में संग्रहीत और प्रसारित किए जाते हैं संख्याओं को स्ट्रिंग में परिवर्तित किया जाता है (जैसे, `0.7` `"0.7"` बन जाता है) बूलियन को लोअरकेस स्ट्रिंग में परिवर्तित किया जाता है (जैसे, `true` `"true"` बन जाता है) +<<<<<<< HEAD यह पल्सर स्कीमा की आवश्यकता है जो `parameters = Map(String())` को परिभाषित करती है +======= + यह पल्सर स्कीमा द्वारा आवश्यक है जो `parameters = Map(String())` को परिभाषित करता है +>>>>>>> 82edf2d (New md files from RunPod) उदाहरण समाधान: ``` @@ -459,11 +544,16 @@ Substituted in processor: "0.7" (string) 1. सिस्टम को बिना पैरामीटर वाले फ्लो ब्लूप्रिंट का समर्थन करना जारी रखना चाहिए। घोषित। 2. सिस्टम को बिना पैरामीटर वाले फ्लो का समर्थन करना जारी रखना चाहिए: +<<<<<<< HEAD यह बिना पैरामीटर वाले फ्लो और पैरामीटर वाले फ्लो दोनों के लिए काम करता है (उनके पास डिफ़ॉल्ट होते हैं)। +======= + यह बिना पैरामीटर वाले फ्लो और पैरामीटर वाले फ्लो दोनों के लिए काम करता है (उनके पास डिफ़ॉल्ट मान होते हैं)। +>>>>>>> 82edf2d (New md files from RunPod) ## खुले प्रश्न +<<<<<<< HEAD प्रश्न: क्या पैरामीटर जटिल, नेस्टेड ऑब्जेक्ट्स का समर्थन करेंगे, या केवल साधारण प्रकारों तक सीमित रहेंगे? उत्तर: पैरामीटर मान स्ट्रिंग के रूप में एन्कोड किए जाएंगे, इसलिए शायद हमें केवल स्ट्रिंग तक ही सीमित रहना चाहिए। @@ -477,6 +567,21 @@ Substituted in processor: "0.7" (string) अ: यह सही नहीं है कि फ्लो शुरू करते समय आईडी और क्लास दोनों निर्दिष्ट किए जाएं। प्रश्न: क्या हमें गणना किए गए पैरामीटर (अन्य पैरामीटर से प्राप्त) का समर्थन करना चाहिए? +======= +प्रश्न: क्या पैरामीटर जटिल, नेस्टेड ऑब्जेक्ट्स का समर्थन करेंगे, या केवल सरल प्रकारों तक सीमित रहेंगे? +उत्तर: पैरामीटर मान स्ट्रिंग के रूप में एन्कोड किए जाएंगे, इसलिए हम शायद केवल स्ट्रिंग तक ही सीमित रहना चाहेंगे। + + +प्रश्न: क्या पैरामीटर प्लेसहोल्डर को कतार के नामों में अनुमति दी जानी चाहिए, या केवल पैरामीटर में? + उत्तर: केवल पैरामीटर में, ताकि अजीब इंजेक्शन और असामान्य स्थितियों से बचा जा सके। + + +प्रश्न: पैरामीटर नामों और सिस्टम वेरिएबल्स के बीच टकराव को कैसे संभालें, जैसे कि + `id` और `class`? +अ: यह सही नहीं है कि फ्लो शुरू करते समय आईडी और क्लास दोनों को निर्दिष्ट किया जाए। + +प्रश्न: क्या हमें गणना किए गए मापदंडों (अन्य मापदंडों से प्राप्त) का समर्थन करना चाहिए? +>>>>>>> 82edf2d (New md files from RunPod) उत्तर: केवल स्ट्रिंग प्रतिस्थापन का उपयोग करके अजीब इंजेक्शन और विशेष मामलों को हटाना। ## संदर्भ diff --git a/docs/tech-specs/flow-configurable-parameters.pt.md b/docs/tech-specs/flow-configurable-parameters.pt.md index ab2ea41a..81dc326b 100644 --- a/docs/tech-specs/flow-configurable-parameters.pt.md +++ b/docs/tech-specs/flow-configurable-parameters.pt.md @@ -79,10 +79,17 @@ O sistema de parâmetros configuráveis requer os seguintes componentes técnico Módulo: trustgraph-flow/trustgraph/flow/launcher.py +<<<<<<< HEAD 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`. +======= +5. **Formulários de Parâmetros 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 descritivos de parâmetros usando o campo `description`. +>>>>>>> 82edf2d (New md files from RunPod) Validação de entrada contra as definições de tipo de parâmetro. Predefinições e modelos de parâmetros. @@ -253,11 +260,19 @@ A API de inicialização do fluxo aceita parâmetros usando os nomes de parâmet 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á: +<<<<<<< HEAD 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 +======= +1. Extrair metadados de parâmetros da definição 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 relações de dependência (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. +>>>>>>> 82edf2d (New md files from RunPod) ### Detalhes da Implementação @@ -265,6 +280,7 @@ O sistema irá: Quando um fluxo é iniciado, o sistema executa as seguintes etapas de resolução de parâmetros: +<<<<<<< HEAD 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: @@ -312,12 +328,66 @@ No modo avançado, os usuários podem substituir `llm-rag-model` com um valor di 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 +======= +1. **Carregamento da Definição do Fluxo**: Carregar a definição 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` da definição do fluxo. +3. **Consulta da Definição de Tipo**: Para cada parâmetro na definição 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 na definição 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 de dependência): + 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 Marcadores**: Substituir os marcadores de parâmetros nos parâmetros do processador pelos 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 dependência + +O campo `controlled-by` permite a herança de valores de parâmetros, o que é particularmente útil para simplificar interfaces de 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 o valor `"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 Interface do Usuário**: +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. +>>>>>>> 82edf2d (New md files from RunPod) #### Integração com Pulsar 1. **Operação Start-Flow** +<<<<<<< HEAD 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` +======= + 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`. +>>>>>>> 82edf2d (New md files from RunPod) Exemplo de solicitação: ```json { @@ -378,7 +448,11 @@ O serviço de configuração de fluxo (`trustgraph-flow/trustgraph/config/servic 2. **Método `handle_start_flow` Modificado** Chamar `resolve_parameters` após carregar o blueprint do fluxo +<<<<<<< HEAD Usar o conjunto completo de parâmetros resolvidos para substituição de modelo +======= + Usar o conjunto completo de parâmetros resolvidos para a substituição de modelo +>>>>>>> 82edf2d (New md files from RunPod) 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 @@ -393,14 +467,22 @@ O serviço de configuração de fluxo (`trustgraph-flow/trustgraph/config/servic 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: +<<<<<<< HEAD `parameters`: Os valores finais de parâmetros resolvidos usados para o fluxo +======= + `parameters`: Os valores de parâmetros resolvidos finais usados para o fluxo +>>>>>>> 82edf2d (New md files from RunPod) #### 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 +<<<<<<< HEAD Validar parâmetros em relação às definições do blueprint do fluxo antes da submissão +======= + Validar os parâmetros em relação às definições do blueprint do fluxo antes da submissão +>>>>>>> 82edf2d (New md files from RunPod) 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: @@ -411,7 +493,11 @@ O serviço de configuração de fluxo (`trustgraph-flow/trustgraph/config/servic #### Integração com a Classe Base do Processador 5. **Suporte a ParameterSpec** +<<<<<<< HEAD As classes base do processador precisam suportar a substituição de parâmetros por meio do mecanismo existente ParametersSpec +======= + As classes base do processador precisam suportar a substituição de parâmetros por meio do mecanismo ParametersSpec existente +>>>>>>> 82edf2d (New md files from RunPod) 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: @@ -447,12 +533,21 @@ Substituted in processor: "0.7" (string) ## Estratégia de Testes +<<<<<<< HEAD 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 +======= +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 de borda: parâmetros ausentes, tipos inválidos, referências de parâmetros indefinidos. +>>>>>>> 82edf2d (New md files from RunPod) ## Plano de Migração @@ -470,14 +565,22 @@ R: Os valores dos parâmetros serão codificados como strings, provavelmente que P: Os espaços reservados de parâmetros devem ser permitidos em nomes de filas ou apenas em parâmetros? +<<<<<<< HEAD R: Apenas em parâmetros para evitar injeções estranhas e casos extremos. +======= +R: Apenas em parâmetros para remover injeções estranhas e casos de borda. +>>>>>>> 82edf2d (New md files from RunPod) 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)? +<<<<<<< HEAD R: Apenas substituição de strings para evitar injeções estranhas e casos extremos. +======= +R: Apenas substituição de strings para remover injeções estranhas e casos de borda. +>>>>>>> 82edf2d (New md files from RunPod) ## Referências diff --git a/docs/tech-specs/flow-configurable-parameters.ru.md b/docs/tech-specs/flow-configurable-parameters.ru.md index 0c9dabae..787c56c5 100644 --- a/docs/tech-specs/flow-configurable-parameters.ru.md +++ b/docs/tech-specs/flow-configurable-parameters.ru.md @@ -57,11 +57,19 @@ Модуль: trustgraph-flow/trustgraph/flow/definition.py +<<<<<<< HEAD 2. **Механизм разрешения параметров** Проверка параметров на соответствие схеме во время выполнения. Применение значений по умолчанию для не указанных параметров. Внедрение параметров в контекст выполнения потока. Преобразование типов и приведение типов при необходимости. +======= +2. **Движок разрешения параметров** + Проверка параметров на соответствие схеме во время выполнения. + Применение значений по умолчанию для не указанных параметров. + Внедрение параметров в контекст выполнения потока. + Приведение типов и преобразование при необходимости. +>>>>>>> 82edf2d (New md files from RunPod) Модуль: trustgraph-flow/trustgraph/flow/parameter_resolver.py @@ -74,14 +82,22 @@ 4. **Расширения для запуска потоков** Расширения API для приема значений параметров при запуске потока. +<<<<<<< HEAD Разрешение отображения (имена потоков на имена определений). +======= + Разрешение сопоставления параметров (имена потоков к именам определений). +>>>>>>> 82edf2d (New md files from RunPod) Обработка ошибок для недействительных комбинаций параметров. Модуль: trustgraph-flow/trustgraph/flow/launcher.py 5. **Формы параметров пользовательского интерфейса** Динамическая генерация форм из метаданных параметров потока. +<<<<<<< HEAD Отображение параметров в упорядоченном виде с использованием поля `order`. +======= + Отображение параметров в отсортированном порядке с использованием поля `order`. +>>>>>>> 82edf2d (New md files from RunPod) Описательные метки параметров с использованием поля `description`. Проверка ввода в соответствии с определениями типов параметров. Предустановки и шаблоны параметров. @@ -218,8 +234,13 @@ ``` Раздел `parameters` сопоставляет имена параметров, специфичные для потока (ключи), с объектами метаданных параметров, содержащими: +<<<<<<< HEAD `type`: Ссылка на централизованно определенное определение параметра (например, "llm-model") `description`: Описание, понятное человеку, для отображения в пользовательском интерфейсе +======= +`type`: Ссылка на центрально определенное определение параметра (например, "llm-model") +`description`: Описание, понятное для человека, для отображения в пользовательском интерфейсе +>>>>>>> 82edf2d (New md files from RunPod) `order`: Порядок отображения параметров в формах (меньшие числа отображаются первыми) `advanced` (необязательно): Булевский флаг, указывающий, является ли этот параметр расширенным (по умолчанию: false). Если установлено значение true, пользовательский интерфейс может скрывать этот параметр по умолчанию или помещать его в раздел "Расширенные" `controlled-by` (необязательно): Имя другого параметра, который управляет значением этого параметра в простом режиме. Если указано, этот параметр наследует свое значение от управляющего параметра, если явно не переопределен @@ -250,12 +271,21 @@ API запуска потока принимает параметры, испо } ``` +<<<<<<< HEAD Примечание: В этом примере, `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`) +======= +Примечание: В этом примере `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`) +>>>>>>> 82edf2d (New md files from RunPod) 4. Проверять предоставленные пользователем и унаследованные значения на соответствие определениям типов параметров 5. Подставлять разрешенные значения в параметры процессоров во время создания экземпляра потока @@ -265,6 +295,7 @@ API запуска потока принимает параметры, испо При запуске потока система выполняет следующие шаги разрешения параметров: +<<<<<<< HEAD 1. **Загрузка схемы потока**: Загрузить определение схемы потока и извлечь метаданные параметров 2. **Извлечение метаданных**: Извлечь `type`, `description`, `order`, `advanced` и `controlled-by` для каждого параметра, определенного в разделе `parameters` схемы потока 3. **Поиск определения типа**: Для каждого параметра в схеме потока: @@ -285,6 +316,28 @@ API запуска потока принимает параметры, испо 7. **Хранение**: Сохранить полный разрешенный набор параметров с экземпляром потока для обеспечения возможности аудита 8. **Подстановка шаблонов**: Заменить заполнители параметров в параметрах процессоров разрешенными значениями 9. **Создание экземпляров процессоров**: Создать процессоры с подставленными параметрами +======= +1. **Загрузка шаблона потока**: Загрузить определение шаблона потока и извлечь метаданные параметров +2. **Извлечение метаданных**: Извлечь `type`, `description`, `order`, `advanced` и `controlled-by` для каждого параметра, определенного в разделе `parameters` шаблона потока +3. **Поиск определения типа**: Для каждого параметра в шаблоне потока: + Получить определение типа параметра из хранилища схемы/конфигурации, используя поле `type` + Определения типов хранятся с типом "parameter-type" в системе конфигурации + Каждое определение типа содержит схему параметра, значение по умолчанию и правила проверки +4. **Разрешение значения по умолчанию**: + Для каждого параметра, определенного в шаблоне потока: + Проверить, предоставлено ли пользователем значение для этого параметра + Если значение не предоставлено пользователем, использовать значение `default` из определения типа параметра + Создать полную карту параметров, содержащую как предоставленные пользователем, так и значения по умолчанию +5. **Разрешение наследования параметров** (зависимости): + Для параметров с полем `controlled-by`, проверить, было ли предоставлено явное значение + Если явное значение не предоставлено, унаследовать значение от управляющего параметра + Если управляющий параметр также не имеет значения, использовать значение по умолчанию из определения типа + Убедиться в отсутствии циклических зависимостей в отношениях `controlled-by` +6. **Проверка**: Проверить полный набор параметров (предоставленные пользователем, значения по умолчанию и унаследованные) на соответствие определениям типов +7. **Хранение**: Сохранить полный набор разрешенных параметров с экземпляром потока для обеспечения возможности аудита +8. **Подстановка шаблонов**: Заменить заполнители параметров в параметрах процессоров разрешенными значениями +9. **Создание процессоров**: Создать процессоры с подставленными параметрами +>>>>>>> 82edf2d (New md files from RunPod) **Важные замечания по реализации**: Сервис потока ДОЛЖЕН объединять параметры, предоставленные пользователем, со значениями по умолчанию из определений типов параметров @@ -292,11 +345,16 @@ API запуска потока принимает параметры, испо Разрешение параметров происходит при запуске потока, а не при создании экземпляра процессора Отсутствующие обязательные параметры без значений по умолчанию ДОЛЖНЫ приводить к сбою запуска потока с четким сообщением об ошибке +<<<<<<< HEAD #### Наследование параметров с помощью "контролируется" +======= +#### Наследование параметров с помощью controlled-by +>>>>>>> 82edf2d (New md files from RunPod) Поле `controlled-by` обеспечивает наследование значений параметров, что особенно полезно для упрощения пользовательских интерфейсов, сохраняя при этом гибкость: **Пример сценария**: +<<<<<<< HEAD Параметр `llm-model` контролирует основную модель LLM Параметр `llm-rag-model` имеет значение `"controlled-by": "llm-model"` В простом режиме установка `llm-model` в "gpt-4" автоматически устанавливает `llm-rag-model` в "gpt-4" @@ -312,12 +370,34 @@ API запуска потока принимает параметры, испо В базовом/простом режиме: Параметры с `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` могут быть скрыты или показаны как доступные только для чтения со унаследованным значением +В расширенном режиме: Все параметры отображаются и могут быть настроены индивидуально +При изменении управляющего параметра зависимые параметры автоматически обновляются, если они не перезаписаны +>>>>>>> 82edf2d (New md files from RunPod) #### Интеграция с Pulsar 1. **Операция Start-Flow** +<<<<<<< HEAD Операция start-flow в Pulsar должна принимать поле `parameters`, содержащее карту значений параметров Схема запроса start-flow в Pulsar должна быть обновлена для включения необязательного поля `parameters` +======= + Операция Pulsar start-flow должна принимать поле `parameters`, содержащее карту значений параметров + Схема Pulsar для запроса start-flow должна быть обновлена для включения необязательного поля `parameters` +>>>>>>> 82edf2d (New md files from RunPod) Пример запроса: ```json { @@ -372,7 +452,11 @@ API запуска потока принимает параметры, испо Эта функция должна: Извлекать метаданные параметров из раздела `parameters` схемы потока. Для каждого параметра получать определение его типа из хранилища конфигурации. +<<<<<<< HEAD Применять значения по умолчанию для любых параметров, которые не предоставлены пользователем. +======= + Применять значения по умолчанию для любых параметров, не предоставленных пользователем. +>>>>>>> 82edf2d (New md files from RunPod) Обрабатывать отношения наследования `controlled-by`. Возвращать полный набор параметров. @@ -393,7 +477,11 @@ API запуска потока принимает параметры, испо Когда поток добавляется в систему конфигурации компонентом потока в менеджере конфигурации, объект потока должен включать разрешенные значения параметров. Менеджер конфигурации должен хранить как исходные параметры, предоставленные пользователем, так и разрешенные значения (с применением значений по умолчанию). Объекты потока в системе конфигурации должны включать: +<<<<<<< HEAD `parameters`: Конечные разрешенные значения параметров, используемые для потока. +======= + `parameters`: Окончательные разрешенные значения параметров, используемые для потока. +>>>>>>> 82edf2d (New md files from RunPod) #### Интеграция с CLI @@ -417,7 +505,11 @@ API запуска потока принимает параметры, испо Реализация ParametersSpec должна: Принимать конфигурации параметров, содержащие заполнители параметров (например, `{model}`, `{temperature}`). Поддерживать подстановку параметров во время выполнения при создании экземпляра процессора. +<<<<<<< HEAD Проверять, соответствуют ли подставленные значения ожидаемым типам и ограничениям. +======= + Проверять, что подставленные значения соответствуют ожидаемым типам и ограничениям. +>>>>>>> 82edf2d (New md files from RunPod) Предоставлять обработку ошибок для отсутствующих или недействительных ссылок на параметры. #### Правила подстановки @@ -452,12 +544,17 @@ Substituted in processor: "0.7" (string) Комплексные тесты для запуска потоков с разными значениями параметров UI-тесты для генерации и проверки форм параметров Тесты производительности для потоков со многими параметрами +<<<<<<< HEAD Пограничные случаи: отсутствующие параметры, неверные типы, неопределенные ссылки на параметры +======= +Краевые случаи: отсутствующие параметры, неверные типы, неопределенные ссылки на параметры +>>>>>>> 82edf2d (New md files from RunPod) ## План миграции 1. Система должна продолжать поддерживать шаблоны потоков без объявленных параметров. 2. Система должна продолжать поддерживать потоки без указанных параметров: +<<<<<<< HEAD Это работает для потоков без параметров и для потоков с параметрами (у которых есть значения по умолчанию). (имеют значения по умолчанию). @@ -471,15 +568,38 @@ UI-тесты для генерации и проверки форм парам В: Должны ли быть разрешены заполнители параметров в именах очередей или только в параметрах? О: Только в параметрах, чтобы избежать странных инъекций и пограничных случаев. +======= +Это работает для потоков без параметров и для потоков с параметрами + (у них есть значения по умолчанию). + +## Открытые вопросы + + +В: Должны ли параметры поддерживать сложные вложенные объекты или ограничиваться простыми типами? +О: Значения параметров будут закодированы в виде строки, поэтому, вероятно, нам стоит + придерживаться строк. + +В: Должны ли быть разрешены заполнители параметров в именах очередей или только в + параметрах? +О: Только в параметрах, чтобы избежать странных внедрений и пограничных случаев. +>>>>>>> 82edf2d (New md files from RunPod) В: Как обрабатывать конфликты между именами параметров и системными переменными, такими как `id` и `class`? О: Недопустимо указывать id и class при запуске потока. В: Должны ли мы поддерживать вычисляемые параметры (выводимые из других параметров)? +<<<<<<< HEAD О: Только простая подстановка строк, чтобы избежать странных инъекций и пограничных случаев. +======= +О: Только простая замена строк, чтобы избежать странных внедрений и пограничных случаев. +>>>>>>> 82edf2d (New md files from RunPod) ## Ссылки Спецификация JSON Schema: https://json-schema.org/ +<<<<<<< HEAD Спецификация определения шаблона потока: docs/tech-specs/flow-class-definition.md +======= +Спецификация определения схемы потока: docs/tech-specs/flow-class-definition.md +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/flow-configurable-parameters.sw.md b/docs/tech-specs/flow-configurable-parameters.sw.md index e75e9842..39251822 100644 --- a/docs/tech-specs/flow-configurable-parameters.sw.md +++ b/docs/tech-specs/flow-configurable-parameters.sw.md @@ -4,7 +4,11 @@ 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. +<<<<<<< HEAD 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. +======= +Vigezo hufanya kazi kupitia ubadilishaji wa vigezo vya kishabaha katika vigezo vya kichakato, sawa na jinsi vigezo `{id}` na `{class}` hufanya kazi, lakini kwa maadili ambayo hutolewa na mtumiaji. +>>>>>>> 82edf2d (New md files from RunPod) Uunganishaji huu unaunga mkono matumizi manne makuu: @@ -19,14 +23,22 @@ Uunganishaji huu unaunga mkono matumizi manne makuu: **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. +<<<<<<< HEAD **Uunganishaji wa UI**: Kuruhusu uingizaji wa vigezo kupitia interfaces za API na UI. +======= +**Uunganisho wa UI**: Kuruhusu uingizaji wa vigezo kupitia interfaces za API na UI. +>>>>>>> 82edf2d (New md files from RunPod) **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 +<<<<<<< HEAD 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. +======= +Mifumo ya uwekaji njia katika TrustGraph sasa inasaidia vigezo vya kichakato ambavyo yanaweza kuwa na maadili thabiti au nafasi za vigezo. Hii huunda fursa ya urekebishaji wakati wa utendaji. +>>>>>>> 82edf2d (New md files from RunPod) Vigezo vya kichakato vya sasa vinaunga mkono: Maadili thabiti: `"model": "gemma3:12b"` @@ -44,6 +56,7 @@ 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 +<<<<<<< HEAD ## Ubunifu wa Kiufundi ### Muundo @@ -52,20 +65,41 @@ Mfumo wa vigezo vinavyoweza kubadilishwa unahitaji vipengele vifuatavyo vya kiuf 1. **Ufafanuzi wa Shabaha ya Vigezo** Ufafanuzi wa vigezo unaotegemea shabaha ya JSON ndani ya metadata ya mfumo wa uwekaji njia. +======= +## Muundo wa Kiufundi + +### Usanifu + +Mfumo wa vigezo unaoweza kubadilishwa unahitaji vipengele vifuatavyo vya kiufundi: + +1. **Ufafanuzi wa Shabaha ya Vigezo** + Ufafanuzi wa vigezo unaotegemea kwenye JSON Schema ndani ya metadata ya mfumo wa uwekaji njia. +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD 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. +======= +2. **Injini ya Urekebishaji 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 utekelezaji wa mfumo wa uwekaji njia. +>>>>>>> 82edf2d (New md files from RunPod) Marekebisho na ubadilishaji wa aina kama inavyohitajika. Moduli: trustgraph-flow/trustgraph/flow/parameter_resolver.py +<<<<<<< HEAD 3. **Uunganishaji wa Hifadhi ya Vigezo** +======= +3. **Uunganisho wa Hifadhi ya Vigezo** +>>>>>>> 82edf2d (New md files from RunPod) Kupata ufafanuzi wa vigezo kutoka kwa duka la shabaha/usanidi. Kuhifadhi ufafanuzi wa vigezo unaotumika mara kwa mara. Uthibitisho dhidi ya shabaha zilizohifadhiwa katikati. @@ -74,26 +108,44 @@ Mfumo wa vigezo vinavyoweza kubadilishwa unahitaji vipengele vifuatavyo vya kiuf 4. **Viendelezi vya Kuanzisha Mfumo wa Uwekaji Njia** Viendelezi vya API kukubali maadili ya vigezo wakati wa kuanzisha mfumo wa uwekaji njia. +<<<<<<< HEAD Ufumbuzi wa ramani ya vigezo (majina ya mifumo ya uwekaji njia hadi majina ya ufafanuzi). +======= + Urekebishaji wa ramani ya vigezo (majina ya mifumo kwa majina ya ufafanuzi). +>>>>>>> 82edf2d (New md files from RunPod) Usimamizi wa makosa kwa mchanganyiko usiofaa wa vigezo. Moduli: trustgraph-flow/trustgraph/flow/launcher.py 5. **Fomu za Vigezo za UI** +<<<<<<< HEAD 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. +======= + Uzalishaji 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 uingizaji dhidi ya ufafanuzi wa aina ya vigezo. + Vipangilio na vipuli vya vigezo. +>>>>>>> 82edf2d (New md files from RunPod) Moduli: trustgraph-ui/components/flow-parameters/ ### Mifano ya Data #### Ufafanuzi wa Vigezo (Imehifadhiwa katika Shabaha/Usanidi) +<<<<<<< HEAD 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. +======= + +Ufafanuzi wa vigezo umehifadhiwa ndani ya duka la shabaha/usanidi. + +>>>>>>> 82edf2d (New md files from RunPod) ```json { "llm-model": { @@ -217,6 +269,7 @@ Mipango ya mchakato inaelezea metadata ya vigezo pamoja na marejeleo ya aina, ma } ``` +<<<<<<< HEAD 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) @@ -230,6 +283,21 @@ 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. +======= +Sehemu ya `parameters` inaeleza jina la 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`: Mfululizo wa kuonyeshwa kwa fomu za parameter (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льку 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 ya mtiririko. +Usimamizi na uthibitishaji wa aina ya parameter unaozingatia. +Maelezo na mpangilio wa parameter unaozingatia mtiririko. +Uzoefu bora wa kiolesura (UI) na fomu za parameter zenye maelezo. +Uthibitishaji thabiti wa parameter katika mitiririko. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -256,7 +324,11 @@ 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`). +<<<<<<< HEAD 4. Kuthibitisha maadili yaliyotolewa na mtumiaji na yaliyorithiwa dhidi ya ufafanuzi wa aina ya vigezo. +======= +4. Kuthibitisha maadili yaliyotolewa na mtumiaji na yaliyorithishwa dhidi ya ufafanuzi wa aina ya vigezo. +>>>>>>> 82edf2d (New md files from RunPod) 5. Kubadilisha maadili yaliyotatuliwa katika vigezo vya kichakataji (processor) wakati wa kuunda mpango. ### Maelezo ya Utendaji @@ -266,6 +338,7 @@ Mfumo utafanya: Wakati mpango unaanza, mfumo hufanya hatua zifuatazo za kutatua vigezo: 1. **Kupakia Mpango (Flow Blueprint)**: Pakia ufafanuzi wa mpango na uchukue metadata ya vigezo. +<<<<<<< HEAD 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`. @@ -282,11 +355,30 @@ Wakati mpango unaanza, mfumo hufanya hatua zifuatazo za kutatua vigezo: 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. +======= +2. **Kuchukua Metadata**: Chukua `type`, `description`, `order`, `advanced`, na `controlled-by` kwa kila kigezo kilichoainishwa katika sehemu ya `parameters` ya ufafanuzi wa mpango. +3. **Kutafuta Ufafanuzi wa Aina**: Kwa kila kigezo katika ufafanuzi wa mpango: + Pata ufafanuzi wa aina ya kigezo 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 kigezo, thamani ya chaguo-msingi, na sheria za uthibitishaji. +4. **Kutatua Thamani ya Chaguo-msingi**: + Kwa kila kigezo kilichoainishwa katika ufafanuzi wa mpango: + Angalia ikiwa mtumiaji ametoa thamani kwa kigezo hiki. + Ikiwa hakuna thamani iliyotolewa na mtumiaji, tumia thamani ya `default` kutoka kwa ufafanuzi wa aina ya kigezo. + Unda ramani kamili ya vigezo inayojumuisha maadili yaliyotolewa na mtumiaji na maadili chaguo-msingi. +5. **Kutatua Ufuasi 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 kigezo kinachodhibiti. + Ikiwa kigezo 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 vilivyorithishwa) dhidi ya ufafanuzi wa aina. +>>>>>>> 82edf2d (New md files from RunPod) 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:** +<<<<<<< HEAD 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. @@ -314,6 +406,35 @@ 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 +======= +Huduma ya mpango INAVYOKWENDA kuchanganya vigezo vilivyotolewa na mtumiaji na chaguo-msingi kutoka kwa ufafanuzi wa aina ya kigezo. +Seti kamili ya vigezo (ikiwa ni pamoja na chaguo-msingi zilizotumiwa) INAVYOKWENDA 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 HAVI kukatisha kuanza kwa mpango na kuonyesha ujumbe wa kosa wazi. + +#### Ufuasi wa Vigezo na "controlled-by" + +Sehemu ya `controlled-by` inaruhusu urithi wa thamani ya kigezo, ambayo ni muhimu sana kwa kurahisisha mazingira ya mtumiaji huku ikiendelea kuwezesha utendaji: + +**Mfano wa Matukio:** +Kigezo cha `llm-model` kinadhibiti mfumo mkuu wa LLM. +Kigezo cha `llm-rag-model` kina `"controlled-by": "llm-model"`. +Katika hali rahisi, kuweka `llm-model` kwa "gpt-4" hufanya `llm-rag-model` pia iwe "gpt-4" kiotomatiki. +Katika hali ya juu, watumiaji wanaweza kubadilisha `llm-rag-model` na thamani tofauti. + +**Sheria za Kutatua:** +1. Ikiwa kigezo kina thamani iliyotolewa wazi, tumia thamani hiyo. +2. Ikiwa hakuna thamani iliyotolewa na `controlled-by` imewekwa, tumia thamani ya kigezo kinachodhibiti. +3. Ikiwa kigezo 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 (read-only) na thamani iliyoorithishwa. +Katika hali ya juu: Vigezo vyote huonyeshwa na vinaweza kusanidiwa kivyake. +Wakati kigezo kinachodhibiti kinapobadilika, vigezo vinavyotegemea hupatikana kiotomatiki isipokuwa ikiwa vimewekwa kuwa visivyo na uwezo. + +#### Ujumuishaji wa Pulsar +>>>>>>> 82edf2d (New md files from RunPod) 1. **Operesheni ya Kuanza-Mpango** Operesheni ya kuanza-mpango ya Pulsar inahitaji kukubali sehemu ya `parameters` inayojumuisha ramani ya maadili ya vigezo. @@ -332,10 +453,17 @@ Wakati kiparamu kinachodhibiti kinapobadilika, vigezo vinavyotegemea hupatikana } ``` +<<<<<<< HEAD 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: +======= +2. **Operesheni ya Kupata Mtiririko (Get-Flow)** + Mfumo wa Pulsar wa jibu la operesheni ya kupata mtiririko lazima ubadilishwe ili kujumuisha sehemu `parameters` + Hii inaruhusu wateja kupata maadili ya vigezo ambayo yalitumiwa wakati mtiririko ulipoanzishwa. + Mfano wa jibu: +>>>>>>> 82edf2d (New md files from RunPod) ```json { "flow_id": "customer-A-flow", @@ -370,6 +498,7 @@ Huduma ya usanidi wa mchakato (`trustgraph-flow/trustgraph/config/service/flow.p ``` Kazi hii inapaswa: +<<<<<<< HEAD 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 @@ -386,19 +515,45 @@ Huduma ya usanidi wa mchakato (`trustgraph-flow/trustgraph/config/service/flow.p 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 +======= + Kuchukua metadata ya vigezo kutoka sehemu ya `parameters` ya mpango wa mtiririko. + Kwa kila vigezo, pata ufafanuzi wa aina yake 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 vilivyofafanuliwa kwa badiliko la kiolezo. + Hifadhi seti kamili ya vigezo (si tu ile iliyotolewa na mtumiaji) pamoja na mtiririko. + Thibitisha kuwa 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. +>>>>>>> 82edf2d (New md files from RunPod) #### Ujumuishaji wa Mfumo wa Usanidi 3. **Uhifadhi wa Kitu cha Mtiririko** +<<<<<<< HEAD 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 +======= + Wakati mtiririko unaongezwa kwenye mfumo wa usanidi na kipengele cha mtiririko katika meneja wa usanidi, kitu cha mtiririko lazima kiwe na maadili yaliyofafanuliwa ya vigezo. + Meneja wa usanidi lazima ahifadhi vigezo vyote vilivyotolewa na mtumiaji na maadili yaliyofafanuliwa (pamoja na maadili chaguo). + Vitu vya mtiririko katika mfumo wa usanidi vinapaswa kujumuisha: + `parameters`: Maadili yaliyofafanuliwa ya vigezo ambayo hutumiwa kwa mtiririko. +>>>>>>> 82edf2d (New md files from RunPod) #### Ujumuishaji wa CLI 4. **Amani za CLI za Maktaba** Amani za CLI ambazo huanzisha mitiririko zinahitaji usaidizi wa vigezo: +<<<<<<< HEAD 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 @@ -407,10 +562,21 @@ Huduma ya usanidi wa mchakato (`trustgraph-flow/trustgraph/config/service/flow.p Onyesha maadili ya vigezo ambayo yalitumiwa wakati mtiririko ulipoanzishwa Onyesha vigezo vinavyopatikana kwa mpango wa mtiririko Onyesha schema na maadili chaguo ya 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 taarifa za vigezo: + Onyesha maadili ya vigezo ambayo yalitumiwa wakati mtiririko ulipoanzishwa. + Onyesha vigezo vinavyopatikana kwa mpango wa mtiririko. + Onyesha schema na maadili chaguo ya vigezo. +>>>>>>> 82edf2d (New md files from RunPod) #### Ujumuishaji wa Darasa la Msingi la Processor 5. **Usaidizi wa ParameterSpec** +<<<<<<< HEAD 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 @@ -431,6 +597,28 @@ Uthibitisho wa aina hutokea kulingana na ufafanuzi wa vigezo uliohifadhiwa katik 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())` +======= + Darasa za msingi za processor zinahitaji kusaidia badiliko la vigezo kupitia utaratibu uliopo wa ParametersSpec. + Darasa la ParametersSpec (lililopo katika moduli sawa na ConsumerSpec na ProducerSpec) linapaswa kuimarishwa ikiwa ni lazima ili kusaidia badiliko la kiolezo la vigezo. + Wasindikaji wanapaswa kuwa na uwezo wa kutumia 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 badiliko la vigezo wakati wa utekelezaji wa processor. + Thibitisha kuwa maadili yaliyobadilishwa yanalingana na aina na vikwazo vilivyotarajiwa. + Kutoa usimamizi wa makosa kwa marejeleo yaliyopotea au yasiyo halali ya vigezo. + +#### Kanuni za Badiliko + +Vigezo hutumia muundo wa `{parameter-name}` katika vigezo vya processor. +Majina ya vigezo katika vigezo yanalingana na funguo katika sehemu ya `parameters` ya mtiririko. +Badiliko 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"`). + Maneno ya kweli hubadilishwa kuwa maandishi ya chini (k.m., `true` inakuwa `"true"`). + Hii inahitajika na schema ya Pulsar ambayo ina `parameters = Map(String())`. +>>>>>>> 82edf2d (New md files from RunPod) Mfano wa utatuzi: ``` @@ -448,14 +636,22 @@ Substituted in processor: "0.7" (string) ## Mbinu ya Majaribio Majaribio ya kitengo kwa uthibitishaji wa muundo wa vigezo +<<<<<<< HEAD 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 +======= +Majaribio ya ujumuishaji kwa ubadilishaji wa vigezo katika vigezo vya kichakata +Majaribio ya mwisho kwa kuzindua mtiririko na maadili tofauti ya vigezo +Majaribio ya UI kwa utengenezaji na uthibitishaji wa fomu ya vigezo +Majaribio ya utendaji kwa mtiririko na vigezo vingi +>>>>>>> 82edf2d (New md files from RunPod) Hali za kipekee: vigezo visivyopo, aina zisizo sahihi, marejeleo ya vigezo yasiyo sahihi ## Mpango wa Uhamisho +<<<<<<< HEAD 1. Mfumo unapaswa kuendelea kusaidia mipango ya michakato bila vigezo vilivyotangazwa. 2. Mfumo unapaswa kuendelea kusaidia michakato bila vigezo vilivyobainishwa: @@ -469,12 +665,31 @@ 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 +======= +1. Mfumo unapaswa kuendelea kusaidia mipango ya mtiririko ambayo haina vigezo + vilivyotangazwa. +2. Mfumo unapaswa kuendelea kusaidia mtiririko bila vigezo vilivyobainishwa: + Hii inafanya kazi kwa mtiririko ambayo haina vigezo, na mtiririko una vigezo + (yana maadili chagu). + +## Maswali ya Wazi + +S: Je, vigezo vinapaswa kusaidia vitu vikubwa vilivyojumuishwa au kuendelea na aina rahisi? +J: Maadili ya vigezo yatakuwa yamekodishwa kama maandishi, tunapaswa + kuzingatia maandishi. + +S: Je, vigezo vya maandishi vinapaswa kuruhusiwa katika majina ya folyo au tu katika +>>>>>>> 82edf2d (New md files from RunPod) 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`? +<<<<<<< HEAD J: Ni vibaya kutaja id na darasa wakati wa kuzindua michakato +======= +J: Ni vibaya kutaja id na darasa wakati wa kuzindua mtiririko +>>>>>>> 82edf2d (New md files from RunPod) S: Je, tunapaswa kusaidia vigezo vilivyohitajiwa (vilivyotokana na vigezo vingine)? J: Tu ubadilishaji wa maandishi ili kuondoa uingizwaji wa ajabu na hali za kipekee. @@ -482,4 +697,8 @@ J: Tu ubadilishaji wa maandishi ili kuondoa uingizwaji wa ajabu na hali za kipek ## Marejeleo Vipimo vya Mpango wa JSON: https://json-schema.org/ +<<<<<<< HEAD Vipimo vya Ufafanuzi wa Mpango wa Michakato: docs/tech-specs/flow-class-definition.md +======= +Vipimo vya Ufafanuzi wa Mpango wa Mtiririko: docs/tech-specs/flow-class-definition.md +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/flow-configurable-parameters.tr.md b/docs/tech-specs/flow-configurable-parameters.tr.md index b750a286..bb468c36 100644 --- a/docs/tech-specs/flow-configurable-parameters.tr.md +++ b/docs/tech-specs/flow-configurable-parameters.tr.md @@ -4,7 +4,11 @@ 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. +<<<<<<< HEAD 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. +======= +Parametreler, `{id}` ve `{class}` değişkenlerinin nasıl çalıştığına benzer şekilde, işlemci parametrelerinde şablon değişken yerleştirmesi yoluyla çalışır, ancak kullanıcı tarafından sağlanan değerlerle. +>>>>>>> 82edf2d (New md files from RunPod) Bu entegrasyon, dört birincil kullanım senaryosunu destekler: @@ -17,17 +21,27 @@ Bu entegrasyon, dört birincil kullanım senaryosunu destekler: **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. +<<<<<<< HEAD **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. +======= +**Varsayılan Değerler**: Gelişmiş kullanıcılar için geçersiz kılmaları desteklerken anlamlı varsayılan değerleri destekleme. +**Şablon Yerleştirmesi**: İşlemci parametrelerindeki parametre yer tutucularını sorunsuz bir şekilde değiştirme. +**Kullanıcı Arayüzü Entegrasyonu**: Hem API hem de kullanıcı arayüzü arayüzleri aracılığıyla parametre girişi sağlama. +**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**: Parametreleri kullanmayan mevcut akış şemalarıyla uyumluluğu koruma. +>>>>>>> 82edf2d (New md files from RunPod) ## 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. +<<<<<<< HEAD Mevcut işlemci parametreleri şunları desteklemektedir: Sabit değerler: `"model": "gemma3:12b"` Parametre yer tutucuları: `"model": "gemma3:{model-size}"` @@ -43,11 +57,29 @@ Varyasyonlar için parametreleri kullanarak akış şeması çoğaltmasını aza 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. +======= +Mevcut işlemci parametreleri şunları destekler: +Sabit değerler: `"model": "gemma3:12b"` +Parametre yer tutucuları: `"model": "gemma3:{model-size}"` + +Bu özellik, parametrelerin nasıl olduğu tanımlar: +Akış şeması tanımlarında beyan edilir +Akışlar başlatıldığında doğrulanır +İşlemci parametrelerinde yerleştirilir +API'ler ve kullanıcı arayüzleri aracılığıyla açığa çıkarılır + +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 +>>>>>>> 82edf2d (New md files from RunPod) ## Teknik Tasarım ### Mimari +<<<<<<< HEAD Yapılandırılabilir parametreler sistemi, aşağıdaki teknik bileşenleri gerektirmektedir: 1. **Parametre Şema Tanımı** @@ -62,29 +94,65 @@ Yapılandırılabilir parametreler sistemi, aşağıdaki teknik bileşenleri ger 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. +======= +Yapılandırılabilir parametreler sistemi, aşağıdaki teknik bileşenleri gerektirir: + +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ümleyici Motoru** + Şemaya karşı çalışma zamanı parametre doğrulaması + Belirtilmemiş parametreler için varsayılan değer uygulaması + Parametreleri akış yürütme bağlamına enjekte etme + Gerekli olduğu gibi tür dönüştürme ve dönüştürme +>>>>>>> 82edf2d (New md files from RunPod) Modül: trustgraph-flow/trustgraph/flow/parameter_resolver.py 3. **Parametre Deposu Entegrasyonu** +<<<<<<< HEAD Ş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. +======= + Ş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 +>>>>>>> 82edf2d (New md files from RunPod) Modül: trustgraph-flow/trustgraph/flow/parameter_store.py 4. **Akış Başlatıcı Uzantıları** +<<<<<<< HEAD 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. +======= + 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 +>>>>>>> 82edf2d (New md files from RunPod) Modül: trustgraph-flow/trustgraph/flow/launcher.py 5. **Kullanıcı Arayüzü Parametre Formları** +<<<<<<< HEAD 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ı. +======= + 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ı +>>>>>>> 82edf2d (New md files from RunPod) Modül: trustgraph-ui/components/flow-parameters/ @@ -221,7 +289,11 @@ Akış şemaları, tür referansları, açıklamalar ve sıralama ile parametre `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) +<<<<<<< HEAD `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 +======= +`advanced` (isteğe bağlı): Bu parametrenin gelişmiş bir parametre olup olmadığını gösteren bir 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 +>>>>>>> 82edf2d (New md files from RunPod) `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: @@ -250,7 +322,11 @@ Akış başlatma API'si, parametreleri akışın parametre adlarını kullanarak } ``` +<<<<<<< HEAD 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. +======= +Not: Bu örnekte, `llm-rag-model` açıkça belirtilmemiştir, ancak `controlled-by` ilişkisi nedeniyle `llm-model`'den "claude-3" değerini alacaktır. Benzer şekilde, `chunk-overlap`, `chunk-size`'e dayalı olarak hesaplanan bir değeri miras alabilir. +>>>>>>> 82edf2d (New md files from RunPod) Sistem şunları yapacaktır: 1. Akış tanımından parametre meta verilerini çıkarın @@ -269,7 +345,11 @@ Bir akış başlatıldığında, sistem aşağıdaki parametre çözümleme adı 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 +<<<<<<< HEAD Tür tanımları, yapılandırma sisteminde "parameter-type" türüyle saklanır +======= + Tür tanımları, yapılandırma sisteminde "parameter-type" türü ile saklanır +>>>>>>> 82edf2d (New md files from RunPod) 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: @@ -283,18 +363,31 @@ Bir akış başlatıldığında, sistem aşağıdaki parametre çözümleme adı `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 +<<<<<<< HEAD 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 +======= +8. **Şablon Yerine Koyma**: İşlemci parametrelerindeki parametre yer tutucularını çözümlenmiş değerlerle değiştirin +9. **İşlemci Oluşturma**: Yerine konulan parametrelerle işlemcileri oluşturun +>>>>>>> 82edf2d (New md files from RunPod) **Ö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 +<<<<<<< HEAD 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: +======= +Varsayılanları olmayan gerekli parametrelerin eksik olması, akışın başlatılmasını açık bir hata mesajıyla başarısız yapmasına neden olmalıdır + +#### "controlled-by" ile Parametre Miras Alma + +`controlled-by` alanı, parametre değerlerinin miras alınmasını sağlar ve kullanıcı arayüzlerini basitleştirirken esnekliği korumak için özellikle kullanışlıdır: +>>>>>>> 82edf2d (New md files from RunPod) **Örnek Senaryo**: `llm-model` parametresi birincil LLM modelini kontrol eder @@ -317,7 +410,11 @@ Bir kontrol eden parametre değiştiğinde, bağımlı parametreler açıkça ge 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 +<<<<<<< HEAD Pulsar için akış başlatma isteği şeması, isteğe bağlı `parameters` alanını içerecek şekilde güncellenmelidir +======= + Pulsar'ın akışı başlatma isteği şeması, isteğe bağlı `parameters` alanını içerecek şekilde güncellenmelidir +>>>>>>> 82edf2d (New md files from RunPod) Örnek istek: ```json { @@ -378,8 +475,13 @@ Akış yapılandırma hizmeti (`trustgraph-flow/trustgraph/config/service/flow.p 2. **Değiştirilen `handle_start_flow` Metodu** Akış şemasını yükledikten sonra `resolve_parameters`'ı çağırın +<<<<<<< HEAD Ş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 +======= + Şablon yerleştirmesi için eksiksiz çözülmüş parametre kümesini kullanın + Eksiksiz parametre kümesini (yalnızca kullanıcı tarafından sağlananları değil) akışla birlikte kaydedin +>>>>>>> 82edf2d (New md files from RunPod) Tüm gerekli parametrelerin değerlere sahip olduğundan emin olun 3. **Parametre Türü Alma** @@ -389,9 +491,15 @@ Akış yapılandırma hizmeti (`trustgraph-flow/trustgraph/config/service/flow.p #### Yapılandırma Sistemi Entegrasyonu +<<<<<<< HEAD 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 +======= +3. **Akış Nesnesi Depolama** + 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) depolamalıdır +>>>>>>> 82edf2d (New md files from RunPod) Yapılandırma sistemindeki akış nesneleri şunları içermelidir: `parameters`: Akış için kullanılan son çözülmüş parametre değerleri @@ -399,7 +507,11 @@ Akış yapılandırma hizmeti (`trustgraph-flow/trustgraph/config/service/flow.p 4. **Kütüphane CLI Komutları** Akışları başlatan CLI komutları parametre desteğine sahip olmalıdır: +<<<<<<< HEAD Parametre değerlerini komut satırı bayrakları veya yapılandırma dosyaları aracılığıyla alın +======= + Parametre değerlerini komut satırı bayrakları veya yapılandırma dosyaları aracılığıyla kabul edin +>>>>>>> 82edf2d (New md files from RunPod) 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 @@ -412,8 +524,13 @@ Akış yapılandırma hizmeti (`trustgraph-flow/trustgraph/config/service/flow.p 5. **ParameterSpec Desteği** İşlemci temel sınıfları, mevcut ParametersSpec mekanizması aracılığıyla parametre yerleştirmesini desteklemelidir +<<<<<<< HEAD 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 +======= + ParameterSpec 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 çözülmüş olarak parametreleriyle yapılandırmak için ParametersSpec'i çağırmalıdır +>>>>>>> 82edf2d (New md files from RunPod) 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 @@ -428,8 +545,13 @@ 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 +<<<<<<< HEAD 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) +======= + Sayılar dizelere dönüştürülür (örneğin, `0.7` `"0.7"` olur) + Boolean değerler küçük harfli dizelere dönüştürülür (örneğin, `true` `"true"` olur) +>>>>>>> 82edf2d (New md files from RunPod) Bu, `parameters = Map(String())` tanımlayan Pulsar şeması gerekliliğidir Örnek çözüm: @@ -456,11 +578,19 @@ Kenar durumları: eksik parametreler, geçersiz türler, tanımlanmamış parame ## Geçiş Planı +<<<<<<< HEAD 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. +======= +1. Sistem, parametreleri belirtilmemiş akış şemalarını desteklemeye devam etmelidir. + 2. Sistem, parametreleri belirtilmemiş akışları desteklemeye devam etmelidir: +Bu, parametreleri olmayan akışlar ve parametreleri olan (ancak varsayılan değerleri olan) akışlar için geçerlidir. + + (bunların varsayılan değerleri vardır). +>>>>>>> 82edf2d (New md files from RunPod) ## Açık Sorular @@ -471,6 +601,7 @@ 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. +<<<<<<< HEAD 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? @@ -478,6 +609,15 @@ A: Bir akışı başlatırken, id ve class özelliklerini belirtmek geçerli de 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. +======= + +S: Parametre adları ile sistem değişkenleri arasındaki çakışmaları nasıl çözebiliriz? + `id` ve `class`? +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: Tuhaf enjeksiyonları ve uç durumları ortadan kaldırmak için sadece string değiştirme işlemi. +>>>>>>> 82edf2d (New md files from RunPod) ## Referanslar diff --git a/docs/tech-specs/flow-configurable-parameters.zh-cn.md b/docs/tech-specs/flow-configurable-parameters.zh-cn.md index 68b528e5..152524c7 100644 --- a/docs/tech-specs/flow-configurable-parameters.zh-cn.md +++ b/docs/tech-specs/flow-configurable-parameters.zh-cn.md @@ -4,11 +4,19 @@ 本规范描述了 TrustGraph 中可配置参数在流程蓝图中的实现方式。参数允许用户在流程启动时自定义处理器参数,通过提供用于替换流程蓝图定义中参数占位符的值来实现。 +<<<<<<< HEAD 参数通过处理器参数中的模板变量替换来实现,类似于 `{id}` 和 `{class}` 变量的工作方式,但使用用户提供的值。 该集成支持四种主要用例: 1. **模型选择**: 允许用户选择不同的 LLM 模型(例如,`gemma3:8b`、`gpt-4`、`claude-3`)用于处理器。 +======= +参数通过处理器参数中的模板变量替换来工作,类似于 `{id}` 和 `{class}` 变量的工作方式,但使用用户提供的值。 + +该集成支持四种主要用例: + +1. **模型选择**: 允许用户选择不同的 LLM 模型 (例如,`gemma3:8b`, `gpt-4`, `claude-3`) 用于处理器。 +>>>>>>> 82edf2d (New md files from RunPod) 2. **资源配置**: 调整处理器参数,例如块大小、批处理大小和并发限制。 3. **行为调整**: 通过参数修改处理器行为,例如温度、最大 token 数或检索阈值。 4. **环境特定参数**: 配置每个部署的环境端点、API 密钥或区域特定 URL。 @@ -17,7 +25,11 @@ **动态处理器配置**: 通过参数替换启用处理器参数的运行时配置。 **参数验证**: 在流程启动时提供参数的类型检查和验证。 +<<<<<<< HEAD **默认值**: 提供合理的默认值,同时允许高级用户进行覆盖。 +======= +**默认值**: 支持合理的默认值,同时允许高级用户进行覆盖。 +>>>>>>> 82edf2d (New md files from RunPod) **模板替换**: Seamlessly 替换处理器参数中的参数占位符。 **UI 集成**: 通过 API 和 UI 接口提供参数输入。 **类型安全**: 确保参数类型与预期的处理器参数类型匹配。 @@ -26,17 +38,28 @@ ## 背景 +<<<<<<< HEAD TrustGraph 中的流程蓝图现在支持处理器参数,这些参数可以包含固定值或参数占位符。这为运行时自定义提供了机会。 +======= +TrustGraph 中的流程蓝图现在支持处理器参数,这些参数可以包含固定值或参数占位符。 这为运行时自定义提供了机会。 +>>>>>>> 82edf2d (New md files from RunPod) 当前处理器参数支持: 固定值:`"model": "gemma3:12b"` 参数占位符:`"model": "gemma3:{model-size}"` 本规范定义了参数的: +<<<<<<< HEAD 在流程蓝图定义中的声明方式 流程启动时的验证方式 在处理器参数中的替换方式 通过 API 和 UI 的暴露方式 +======= +在流程蓝图定义中的声明 +在流程启动时的验证 +在处理器参数中的替换 +通过 API 和 UI 的暴露 +>>>>>>> 82edf2d (New md files from RunPod) 通过利用参数化的处理器参数,TrustGraph 可以: 通过使用参数进行变体,减少流程蓝图的重复。 @@ -68,21 +91,34 @@ TrustGraph 中的流程蓝图现在支持处理器参数,这些参数可以包 3. **参数存储集成** 从模式/配置存储中检索参数定义。 缓存常用的参数定义。 +<<<<<<< HEAD 对其进行验证,以确保其与中心存储的模式一致。 +======= + 对其进行集中存储的模式验证。 +>>>>>>> 82edf2d (New md files from RunPod) 模块:trustgraph-flow/trustgraph/flow/parameter_store.py 4. **流程启动器扩展** API 扩展,用于在流程启动期间接受参数值。 +<<<<<<< HEAD 参数映射解析(将流程名称映射到定义名称)。 +======= + 参数映射解析 (将流程名称映射到定义名称)。 +>>>>>>> 82edf2d (New md files from RunPod) 处理无效参数组合的错误。 模块:trustgraph-flow/trustgraph/flow/launcher.py 5. **UI 参数表单** 从流程参数元数据动态生成表单。 +<<<<<<< HEAD 使用 `order` 字段显示参数的顺序。 使用 `description` 字段提供参数的描述性标签。 +======= + 使用 `order` 字段显示参数顺序。 + 使用 `description` 字段提供描述性参数标签。 +>>>>>>> 82edf2d (New md files from RunPod) 根据参数类型定义进行输入验证。 参数预设和模板。 @@ -90,9 +126,15 @@ TrustGraph 中的流程蓝图现在支持处理器参数,这些参数可以包 ### 数据模型 +<<<<<<< HEAD #### 参数定义(存储在模式/配置中) 参数定义以类型为 "parameter-type" 的方式存储在模式和配置系统中。 +======= +#### 参数定义 (存储在模式/配置中) + +参数定义以类型 "parameter-type" 存储在模式和配置系统中。 +>>>>>>> 82edf2d (New md files from RunPod) ```json { @@ -222,7 +264,11 @@ TrustGraph 中的流程蓝图现在支持处理器参数,这些参数可以包 `description`:用于UI显示的易于理解的描述 `order`:参数表单的显示顺序(较小的数字首先显示) `advanced`(可选):布尔标志,指示是否为高级参数(默认:false)。如果设置为true,UI可能会默认隐藏此参数或将其放置在“高级”部分 +<<<<<<< HEAD `controlled-by`(可选):控制此参数在简单模式下值的另一个参数的名称。如果指定,此参数将从控制参数继承其值,除非显式覆盖 +======= +`controlled-by`(可选):控制此参数在简单模式下值的另一个参数的名称。如果指定,此参数将继承其值来自控制参数,除非显式覆盖 +>>>>>>> 82edf2d (New md files from RunPod) 这种方法允许: 在多个流程蓝图之间重用参数类型定义 @@ -250,7 +296,11 @@ TrustGraph 中的流程蓝图现在支持处理器参数,这些参数可以包 } ``` +<<<<<<< HEAD 注意:在这个例子中,`llm-rag-model` 没有明确提供,但会从 `llm-model` 继承值 "claude-3",这是因为 `llm-rag-model` 与 `llm-model` 之间存在 `controlled-by` 关系。 类似地,`chunk-overlap` 可能会继承一个基于 `chunk-size` 计算的值。 +======= +注意:在这个例子中,`llm-rag-model` 没有显式提供,但会从 `llm-model` 继承 "claude-3" 的值,这是因为 `llm-rag-model` 与 `llm-model` 之间存在 `controlled-by` 关系。 类似地,`chunk-overlap` 可能会继承一个基于 `chunk-size` 计算的值。 +>>>>>>> 82edf2d (New md files from RunPod) 系统将执行以下操作: 1. 从流程蓝图定义中提取参数元数据 @@ -268,9 +318,15 @@ TrustGraph 中的流程蓝图现在支持处理器参数,这些参数可以包 1. **流程蓝图加载**: 加载流程蓝图定义并提取参数元数据 2. **元数据提取**: 提取每个参数的 `type`、`description`、`order`、`advanced` 和 `controlled-by`,这些信息位于流程蓝图的 `parameters` 部分 3. **类型定义查找**: 对于流程蓝图中的每个参数: +<<<<<<< HEAD 使用 `type` 字段从 schema/config 存储中检索参数类型定义 类型定义存储在配置系统中,类型为 "parameter-type" 每个类型定义包含参数的 schema、默认值和验证规则 +======= + 使用 `type` 字段从模式/配置存储中检索参数类型定义 + 类型定义存储在配置系统中,类型为 "parameter-type" + 每个类型定义包含参数的模式、默认值和验证规则 +>>>>>>> 82edf2d (New md files from RunPod) 4. **默认值解析**: 对于流程蓝图中定义的每个参数: 检查用户是否为该参数提供了值 @@ -283,13 +339,21 @@ TrustGraph 中的流程蓝图现在支持处理器参数,这些参数可以包 验证 `controlled-by` 关系中是否存在循环依赖 6. **验证**: 验证完整的参数集(用户提供的、默认值和继承的值)是否符合类型定义 7. **存储**: 将完整的解析后的参数集与流程实例一起存储,以进行审计 +<<<<<<< HEAD 8. **模板替换**: 使用解析后的值替换处理器参数中的参数占位符 +======= +8. **模板替换**: 使用解析的值替换处理器参数中的参数占位符 +>>>>>>> 82edf2d (New md files from RunPod) 9. **处理器实例化**: 使用替换后的参数创建处理器 **重要的实现说明:** 流程服务必须将用户提供的参数与参数类型定义中的默认值合并 完整的参数集(包括应用的默认值)必须与流程一起存储,以进行可追溯性 +<<<<<<< HEAD 参数解析发生在流程启动时间,而不是处理器实例化时间 +======= +参数解析发生在流程启动时,而不是在处理器实例化时 +>>>>>>> 82edf2d (New md files from RunPod) 缺少没有默认值的必需参数会导致流程启动失败,并显示清晰的错误消息 #### 具有 controlled-by 的参数继承 @@ -317,7 +381,11 @@ TrustGraph 中的流程蓝图现在支持处理器参数,这些参数可以包 1. **启动流程操作** Pulsar 启动流程操作需要接受一个 `parameters` 字段,该字段包含参数值的映射 +<<<<<<< HEAD Pulsar 启动流程请求的 schema 必须更新为包含可选的 `parameters` 字段 +======= + Pulsar 用于启动流程的请求模式必须更新为包含可选的 `parameters` 字段 +>>>>>>> 82edf2d (New md files from RunPod) 示例请求: ```json { @@ -333,7 +401,11 @@ TrustGraph 中的流程蓝图现在支持处理器参数,这些参数可以包 ``` 2. **获取流程操作** +<<<<<<< HEAD 必须更新 Pulsar 模式,以包含 `parameters` 字段,用于获取流程的响应。 +======= + Pulsar 用于获取流程响应的 schema 必须更新,以包含 `parameters` 字段。 +>>>>>>> 82edf2d (New md files from RunPod) 这允许客户端检索在启动流程时使用的参数值。 示例响应: ```json @@ -391,7 +463,11 @@ TrustGraph 中的流程蓝图现在支持处理器参数,这些参数可以包 3. **流程对象存储** 当流程组件在配置管理器中向配置系统添加流程时,流程对象必须包含解析后的参数值 +<<<<<<< HEAD 配置管理器需要同时存储原始的用户提供的参数和解析后的值(已应用默认值) +======= + 配置管理器需要存储原始的用户提供的参数以及解析后的值(已应用默认值) +>>>>>>> 82edf2d (New md files from RunPod) 配置系统中的流程对象应包含: `parameters`: 用于流程的最终解析后的参数值 @@ -423,7 +499,11 @@ TrustGraph 中的流程蓝图现在支持处理器参数,这些参数可以包 #### 替换规则 参数使用格式 `{parameter-name}` 在处理器参数中 +<<<<<<< HEAD 参数名称与流程的 `parameters` 部分中的键匹配 +======= +参数名称在参数中与流程的 `parameters` 部分中的键匹配 +>>>>>>> 82edf2d (New md files from RunPod) 替换操作与 `{id}` 和 `{class}` 替换同时进行 无效的参数引用会导致启动时出错 基于中心存储的参数定义进行类型验证 @@ -456,8 +536,13 @@ Substituted in processor: "0.7" (string) ## 迁移计划 +<<<<<<< HEAD 1. 系统应继续支持未声明参数的流程蓝图。 2. 系统应继续支持未指定参数的流程: +======= +1. 系统应继续支持未声明任何参数的流程蓝图。 + 2. 系统应继续支持未指定任何参数的流程: +>>>>>>> 82edf2d (New md files from RunPod) 这适用于没有参数的流程,以及具有参数的流程(它们具有默认值)。 (它们有默认值)。 @@ -468,7 +553,11 @@ Substituted in processor: "0.7" (string) 答:参数值将被字符串编码,我们可能更倾向于 使用字符串。 +<<<<<<< HEAD 问:是否允许在队列名称中使用参数占位符,还是仅在 +======= +问:是否允许在队列名称中使用参数占位符,或者仅在 +>>>>>>> 82edf2d (New md files from RunPod) 参数中使用? 答:仅在参数中使用,以避免奇怪的注入和边缘情况。 @@ -479,7 +568,11 @@ Substituted in processor: "0.7" (string) 问:我们是否应该支持计算参数(从其他参数派生)? 答:仅进行字符串替换,以避免奇怪的注入和边缘情况。 +<<<<<<< HEAD ## 引用 +======= +## 参考文献 +>>>>>>> 82edf2d (New md files from RunPod) 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 index 404f199e..b03e0b22 100644 --- a/docs/tech-specs/graph-contexts.pt.md +++ b/docs/tech-specs/graph-contexts.pt.md @@ -26,7 +26,11 @@ Os principais objetivos deste trabalho são permitir metadados sobre fatos/decla **Proveniência/Fontes**: Rastrear quais fontes suportam um fato "Este fato foi suportado pela fonte X" +<<<<<<< HEAD Vincular fatos aos documentos de origem +======= + Vincular fatos aos seus documentos de origem +>>>>>>> 82edf2d (New md files from RunPod) **Veracidade/Confiança**: Registrar afirmações sobre a verdade "A pessoa P afirmou que isso era verdade" @@ -44,7 +48,11 @@ como algo sobre o qual você pode fazer declarações. Triplas padrão não supo ### Limitações Atuais +<<<<<<< HEAD A classe `Value` atual em `trustgraph-base/trustgraph/schema/core/primitives.py` +======= +A classe `Value` em `trustgraph-base/trustgraph/schema/core/primitives.py` +>>>>>>> 82edf2d (New md files from RunPod) pode representar: Nós URI (`is_uri=True`) Valores literais (`is_uri=False`) @@ -61,7 +69,11 @@ Esses recursos estão diretamente relacionados aos objetivos de tempo, proveniê 1. **Triplas Citadas RDF 1.2 (RDF-star)** Arestas que apontam para outras arestas +<<<<<<< HEAD Uma Tripla pode aparecer como o sujeito ou objeto de outra Tripla +======= + Uma Tripla pode aparecer como o sujeito ou o objeto de outra Tripla +>>>>>>> 82edf2d (New md files from RunPod) Permite declarações sobre declarações (reificação) Mecanismo principal para anotar fatos individuais @@ -126,7 +138,11 @@ Um Termo pode representar: ##### Abordagem Escolhida: Classe Única com Discriminador de Tipo Os requisitos de serialização determinam a estrutura - um discriminador de tipo é necessário +<<<<<<< HEAD no formato de transmissão, independentemente da representação em Python. Uma classe única com +======= +no formato de transmissão, independentemente da representação em Python. Uma única classe com +>>>>>>> 82edf2d (New md files from RunPod) 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: @@ -218,9 +234,15 @@ O contexto do grafo é metadado sobre onde a tripla reside. ### Padrões de Consulta Candidatos +<<<<<<< HEAD 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. +======= +O mecanismo de consulta atual aceita combinações de termos S, P, O. Com triplas entre aspas, +uma tripla se torna um termo válido nessas posições. Abaixo estão os padrões de consulta +candidatos que suportam os objetivos originais. +>>>>>>> 82edf2d (New md files from RunPod) #### Semântica do Parâmetro do Grafo @@ -384,7 +406,11 @@ seguirá em fases: 1. **Fase 1: Cassandra** Começar com o armazenamento Cassandra próprio +<<<<<<< HEAD O controle total sobre a camada de armazenamento permite iteração rápida +======= + Controle total sobre a camada de armazenamento permite iteração rápida +>>>>>>> 82edf2d (New md files from RunPod) 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 @@ -395,12 +421,20 @@ O Cassandra requer múltiplas tabelas para suportar diferentes padrões de acess ##### Padrões de Consulta +<<<<<<< HEAD Com quads (g, s, p, o), cada posição pode ser especificada ou curinga, dando +======= +Com tuplas (g, s, p, o), cada posição pode ser especificada ou curinga, dando +>>>>>>> 82edf2d (New md files from RunPod) 16 padrões de consulta possíveis: | # | g | s | p | o | Descrição | |---|---|---|---|---|-------------| +<<<<<<< HEAD | 1 | ? | ? | ? | ? | Todos os quads | +======= +| 1 | ? | ? | ? | ? | Todas as tuplas | +>>>>>>> 82edf2d (New md files from RunPod) | 2 | ? | ? | ? | o | Por objeto | | 3 | ? | ? | p | ? | Por predicado | | 4 | ? | ? | p | o | Por predicado + objeto | @@ -415,6 +449,7 @@ Com quads (g, s, p, o), cada posição pode ser especificada ou curinga, dando | 13 | g | s | ? | ? | Por grafo + sujeito | | 14 | g | s | ? | o | Por grafo + sujeito + objeto | | 15 | g | s | p | ? | Por grafo + sujeito + predicado | +<<<<<<< HEAD | 16 | g | s | p | o | Quad exato | ##### Design de Tabela @@ -422,11 +457,24 @@ Com quads (g, s, p, o), cada posição pode ser especificada ou curinga, dando 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 +======= +| 16 | g | s | p | o | Tupla exata | + +##### Design da 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 estar +em uma coluna de agrupamento. Para consultas com "g" especificado, "g" na chave de partição é mais +>>>>>>> 82edf2d (New md files from RunPod) eficiente. **Duas famílias de tabelas necessárias:** +<<<<<<< HEAD **Família A: consultas com curinga "g"** (g em colunas de agrupamento) +======= +**Família A: Consultas com curinga "g"** (g em colunas de agrupamento) +>>>>>>> 82edf2d (New md files from RunPod) | Tabela | Partição | Agrupamento | Suporta padrões | |-------|-----------|------------|-------------------| @@ -434,7 +482,11 @@ eficiente. | POSG | (user, collection, p) | o, s, g | 3, 4 | | OSPG | (user, collection, o) | s, p, g | 2, 6 | +<<<<<<< HEAD **Família B: consultas com "g" especificado** (g na chave de partição) +======= +**Família B: Consultas com "g" especificado** (g na chave de partição) +>>>>>>> 82edf2d (New md files from RunPod) | Tabela | Partição | Agrupamento | Suporta padrões | |-------|-----------|------------|-------------------| @@ -446,7 +498,11 @@ eficiente. | Tabela | Partição | Agrupamento | Propósito | |-------|-----------|------------|---------| +<<<<<<< HEAD | COLL | (user, collection) | g, s, p, o | Enumerar todos os quads na coleção | +======= +| COLL | (user, collection) | g, s, p, o | Enumerar todas as tuplas na coleção | +>>>>>>> 82edf2d (New md files from RunPod) ##### Caminhos de Escrita e Exclusão @@ -454,6 +510,7 @@ eficiente. **Caminho de exclusão da coleção**: 1. Iterar na tabela COLL para `(user, collection)` +<<<<<<< HEAD 2. Para cada quad, excluir de todas as 6 tabelas de consulta 3. Excluir da tabela COLL (ou exclusão por intervalo) @@ -467,6 +524,21 @@ com exclusão eficiente da coleção. ##### Triplas Citadas no Armazenamento O sujeito ou o objeto podem ser uma tripla em si. Opções: +======= +2. Para cada tupla, excluir de todas as 6 tabelas de consulta +3. Excluir da tabela COLL (ou exclusão por intervalo) + +**Caminho de exclusão de uma única tupla**: Excluir diretamente de todas as 7 tabelas. + +##### Custo de Armazenamento + +Cada tupla é armazenada 7 vezes. Este é o custo da consulta flexível +combinado com a exclusão eficiente da coleção. + +##### Triplas Citadas no Armazenamento + +Sujeito ou objeto podem ser uma tripla em si. Opções: +>>>>>>> 82edf2d (New md files from RunPod) **Opção A: Serializar triplas citadas para string canônica** ``` @@ -507,7 +579,11 @@ componentes. Esta abordagem reduz os riscos do projeto, validando em um backend totalmente controlado antes de implementar em todos os armazenamentos. +<<<<<<< HEAD #### Renomear Classe de Valor → Termo +======= +#### Renomeação de Valor → Termo +>>>>>>> 82edf2d (New md files from RunPod) 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 @@ -533,7 +609,12 @@ Nunca arestas (triplas com aspas) Nunca valores literais Nunca nós vazios +<<<<<<< HEAD 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. +======= +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. +>>>>>>> 82edf2d (New md files from RunPod) Triplas com aspas e grafos nomeados não complicam as operações vetoriais. ## Estratégia de Teste @@ -542,7 +623,10 @@ Use a estratégia de teste existente. Como esta é uma alteração disruptiva, c conjunto de testes de ponta a ponta para validar que as novas estruturas funcionam corretamente em todos os componentes. +<<<<<<< HEAD +======= +>>>>>>> 82edf2d (New md files from RunPod) ## Plano de Migração A versão 2.0 é uma versão disruptiva; nenhuma compatibilidade com versões anteriores é necessária @@ -552,18 +636,31 @@ Considere ferramentas de migração para converter triplas existentes ## Perguntas Abertas **Nós vazios**: Suporte limitado confirmado. Pode ser necessário decidir sobre +<<<<<<< HEAD estratégia de skolemização (gerar IRIs na carga, ou preservar os IDs dos nós vazios). +======= + estratégia de skolemização (gerar IRIs na carga ou preservar os IDs dos nós vazios). +>>>>>>> 82edf2d (New md files from RunPod) **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). +<<<<<<< HEAD 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 +======= + Estratégia: evitar 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 usam o grafo padrão + (corresponde ao comportamento do SPARQL, compatível com versões anteriores). Parâmetro de grafo explícito +>>>>>>> 82edf2d (New md files from RunPod) necessário para consultar grafos nomeados ou todos os grafos. ## Referências diff --git a/docs/tech-specs/graph-contexts.tr.md b/docs/tech-specs/graph-contexts.tr.md index 169091bb..a11a6c4d 100644 --- a/docs/tech-specs/graph-contexts.tr.md +++ b/docs/tech-specs/graph-contexts.tr.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD # Graph Contexts Technical Specification ## Overview @@ -7,6 +8,17 @@ RDF 1.2 ile uyumlu olacak ve tam RDF Dataset semantiğini destekleyecek şekilde ### Versioning +======= +# Graph Contexts Teknik Özellikler + +## Genel Bakış + +Bu özellik, TrustGraph'ın temel grafik öğelerindeki değişiklikleri, +RDF 1.2 ile uyumlu olacak ve tam RDF Dataset semantiğini destekleyecek şekilde tanımlar. Bu, 2.x sürüm serisi için önemli bir değişikliktir. + + +### Sürümleme +>>>>>>> 82edf2d (New md files from RunPod) **2.0**: Erken benimseyen sürüm. Temel özellikler mevcut, ancak henüz tamamen üretim ortamına hazır olmayabilir. @@ -15,11 +27,16 @@ RDF 1.2 ile uyumlu olacak ve tam RDF Dataset semantiğini destekleyecek şekilde Olgunluk konusundaki esneklik kasıtlıdır; erken benimseyenler, tüm özellikler üretim ortamına hazır hale gelmeden önce yeni yeteneklere erişebilir. +<<<<<<< HEAD ## Goals +======= +## Hedefler +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD 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 @@ -45,10 +62,38 @@ bir kenara bir şey olarak başvurmanız ve bu kenar hakkında ifadeler yapabilm ### Current Limitations Mevcut `Value` sınıfı `trustgraph-base/trustgraph/schema/core/primitives.py` içinde +======= + Bir gerçeğin doğru olduğuna inanıldığı zaman + Bir gerçeğin doğru hale geldiği zaman + Bir gerçeğin yanlış olduğu keşfedildiğinde + +**Kaynak/Köken**: Bir gerçeği destekleyen kaynakları izleme + "Bu gerçek, kaynak X tarafından destekleniyordu" + Gerçekleri, köken belgelerine bağlama + +**Doğruluk/Güvenilirlik**: Doğrulukla ilgili ifadeleri kaydetme + "Kişi P, bunun doğru olduğunu iddia etti" + "Kişi Q, bunun yanlış olduğunu iddia ediyor" + Güvenilirlik puanlaması ve çakışma tespitini etkinleştirme + +**Hipotez**: Yeniden tanımlama (RDF-star / tırnaklı üçlüler), bu sonuçları elde etmenin temel mekanizmasıdır, çünkü bunların hepsi ifadeler hakkında ifadeler yapmayı gerektirir. + + +## Arka Plan + +"Alice'nin Bob'u bildiği gerçeği 2024-01-15'te keşfedildi" veya "kaynak X, (Y'nin Z'ye neden olduğu) iddiasını destekliyor" gibi ifadeleri belirtmek için, +bir kenarı, hakkında ifadeler yapılabilecek bir şey olarak referans göstermeniz gerekir. Standart üçlüler bunu desteklemez. + +### Mevcut Sınırlamalar + + +Mevcut `Value` sınıfı `trustgraph-base/trustgraph/schema/core/primitives.py` içinde: +>>>>>>> 82edf2d (New md files from RunPod) şunları temsil edebilir: URI düğümleri (`is_uri=True`) Literal değerler (`is_uri=False`) +<<<<<<< HEAD `type` alanı mevcuttur, ancak XSD veri türlerini temsil etmek için kullanılmaz. ## Technical Design @@ -72,19 +117,53 @@ Bir veri kümesi içindeki birden fazla adlandırılmış grafik için destek 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: +======= +`type` alanı mevcut, ancak XSD veri tiplerini temsil etmek için kullanılmıyor. + +## Teknik Tasarım + +### Desteklenecek RDF Özellikleri + +#### Temel Özellikler (Somutlaştırma Hedefleriyle İlgili) + +Bu özellikler, zamansallık, köken ve doğruluk +hedefleriyle doğrudan ilişkilidir: + +1. **RDF 1.2 Tırnak İşaretli Üçlüler (RDF-star)** + Diğer kenarlara işaret eden kenarlar + Bir Üçlü, başka bir Üçlünün öznesi veya nesnesi olabilir + Üçlüler hakkında ifadeler oluşturmayı sağlar (somutlaştırma) + Bireysel gerçekleri açıklamak için temel mekanizma + +2. **RDF Veri Kümesi / Adlandırılmış Grafikler** + Bir veri kümesi içinde birden fazla adlandırılmış grafik desteği + 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 bir öznesi olabilir, örneğin: +>>>>>>> 82edf2d (New md files from RunPod) ``` "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 +<<<<<<< HEAD organizasyonu) ve ayrı bir yetenek olarak ele alınmalıdır. +======= + düzeni) ve ayrı bir yetenek olarak ele alınmalıdır. +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD **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) +======= + **Sınırlı durum**: Yükleme işleminden sonra kararlı bir kimlik konusunda garanti yoktur + Bunları jokerli sorgularla bulun (bağlantılara göre, kimliğe göre değil) +>>>>>>> 82edf2d (New md files from RunPod) 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) @@ -95,24 +174,40 @@ kırıcı değişiklikler yaparken dahil edilmesi değerli olan iyileştirmelerd 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. +<<<<<<< HEAD Mevcut sınırlamayı düzeltir: tarihleri veya tamsayıları düzgün bir şekilde temsil edilemez +======= + Mevcut sınırlamayı düzeltir: tarihleri veya tamsayıları doğru şekilde temsil edilemez +>>>>>>> 82edf2d (New md files from RunPod) 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ç) +<<<<<<< HEAD Yapay zeka/çok dilli kullanım senaryoları için önemlidir +======= + Yapay zeka/çok dilli kullanım durumları için önemlidir +>>>>>>> 82edf2d (New md files from RunPod) ### 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. +<<<<<<< HEAD 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. +======= +Bu yeniden adlandırmanın iki amacı vardır: +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. Kod incelemesini, önemli değişikliklerin yapıldığı arayüzde zorunlu kılmak - hala + `Value`'a referans veren herhangi bir kod, açıkça hatalı olacaktır ve güncellenmesi gerekecektir. +>>>>>>> 82edf2d (New md files from RunPod) Bir Terim şunları temsil edebilir: @@ -125,8 +220,13 @@ Bir Terim şunları temsil edebilir: ##### Seçilen Yaklaşım: Tip Ayırıcısı Olan Tek Sınıf +<<<<<<< HEAD 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. +======= +Serileştirme gereksinimleri yapıyı belirler - bir tür belirleyiciye ihtiyaç vardır. +Python gösteriminden bağımsız olarak, kablo formatında bir tür belirleyiciye ihtiyaç vardır. +>>>>>>> 82edf2d (New md files from RunPod) 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: @@ -222,7 +322,11 @@ Mevcut sorgu motoru, S, P, O terimlerinin kombinasyonlarını kabul eder. Tırna üç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. +<<<<<<< HEAD #### Grafik Parametre Anlamları +======= +#### Grafik Parametre Anlamı +>>>>>>> 82edf2d (New md files from RunPod) Geriye dönük uyumluluk için SPARQL kurallarına uygun olarak: @@ -233,8 +337,13 @@ Geriye dönük uyumluluk için SPARQL kurallarına uygun olarak: Bu, basit sorguları basit tutar ve adlandırılmış grafik sorgularını isteğe bağlı hale getirir. +<<<<<<< HEAD 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), +======= +Grafikler arası sorgular (g=joker karakter) tamamen desteklenir. Cassandra şeması, +g'nin bir kümeleme sütunu olduğu (bölüm anahtarı değil) özel tabloları içerir (SPOG, POSG, OSPG), +>>>>>>> 82edf2d (New md files from RunPod) bu da tüm grafikler arasında verimli sorgular yapmayı sağlar. #### Zamansal Sorgular @@ -309,13 +418,21 @@ O: < 0.5 # numeric comparison ### Mimari +<<<<<<< HEAD Birden çok bileşende önemli değişiklikler gereklidir: +======= +Birden fazla bileşende önemli değişiklikler gereklidir: +>>>>>>> 82edf2d (New md files from RunPod) #### Bu Depo (trustgraph) **Şema ilkel öğeleri** (`trustgraph-base/trustgraph/schema/core/primitives.py`) Değer → Terim yeniden adlandırması +<<<<<<< HEAD Tip ayrımcısına sahip yeni Terim yapısı +======= + Tip ayrımcısı ile yeni Terim yapısı +>>>>>>> 82edf2d (New md files from RunPod) Üçlü, grafik bağlamı için `g` alanı kazanır **Mesaj çeviricileri** (`trustgraph-base/trustgraph/messaging/translators/`) @@ -373,12 +490,17 @@ Ayrı sürüm koordinasyonu #### Çalışma alanı (ayrı depo) Önemli durum yönetimi değişiklikleri +<<<<<<< HEAD Grafik bağlamı özellikleriyle ilgili kullanıcı arayüzü güncellemeleri +======= +Grafik bağlamı özelliklerini destekleyen UI güncellemeleri +>>>>>>> 82edf2d (New md files from RunPod) ### Uygulama Ayrıntıları #### Aşamalı Depolama Uygulaması +<<<<<<< HEAD Birden çok grafik depolama arka ucu (Cassandra, Neo4j, vb.) vardır. Uygulama aşağıdaki aşamalarda gerçekleştirilecektir: @@ -386,6 +508,15 @@ aşağıdaki aşamalarda gerçekleştirilecektir: 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 +======= +Birden fazla grafik depolama arka ucu (Cassandra, Neo4j, vb.) bulunmaktadır. Uygulama, +aşağıdaki aşamalarda gerçekleştirilecektir: + +1. **1. Aşama: Cassandra** + Kendi geliştirdiğimiz Cassandra deposuyla başlayın + Depolama katmanı üzerinde tam kontrole sahip olmak, hızlı yinelemeyi sağlar + Şema, dörtlüler ve yeniden tanımlama için sıfırdan yeniden tasarlanacaktır +>>>>>>> 82edf2d (New md files from RunPod) Veri modelini ve sorgu kalıplarını gerçek kullanım durumlarına göre doğrulayın #### Cassandra Şema Tasarımı @@ -406,6 +537,7 @@ Cassandra, farklı sorgu erişim modellerini desteklemek için birden fazla tabl | 4 | ? | ? | p | o | Özne + nesneye göre | | 5 | ? | s | ? | ? | Konuya göre | | 6 | ? | s | ? | o | Konu + nesneye göre | +<<<<<<< HEAD | 7 | ? | s | p | ? | Konu + öneye göre | | 8 | ? | s | p | o | Tam üçlü (hangi grafikler?) | | 9 | g | ? | ? | ? | Grafiğe göre | @@ -415,11 +547,26 @@ Cassandra, farklı sorgu erişim modellerini desteklemek için birden fazla tabl | 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 | +======= +| 7 | ? | s | p | ? | Konu + özneliğe 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 + özneliğe göre | +| 12 | g | ? | p | o | Grafik + özneliği + 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 + özneliğe göre | +>>>>>>> 82edf2d (New md files from RunPod) | 16 | g | s | p | o | Tam "quad" | ##### Tablo Tasarımı +<<<<<<< HEAD Cassandra kısıtlaması: Yalnızca bölüm anahtarına göre verimli bir şekilde sorgulayabilirsiniz, ardından +======= +Cassandra kısıtlaması: Yalnızca bölüm anahtarına göre verimli bir şekilde sorgu yapabilirsiniz, ardından +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -476,9 +623,15 @@ 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. +<<<<<<< HEAD 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. +======= +Seri hale getirilmiş forma göre tam eşleşme sorgusu yapı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 yapılamaz. +>>>>>>> 82edf2d (New md files from RunPod) **B Seçeneği: Üçlü Kimlikleri / Hash'leri** ``` @@ -492,6 +645,7 @@ Metadata table: o: "2024-01-15" ``` Her üçlüye bir kimlik (bileşenlerin karma değeri) atayın. +<<<<<<< HEAD Ö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. @@ -505,6 +659,21 @@ B seçeneği, tırnak içinde belirtilen üçlü bileşenleri üzerinde gelişmi 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. +======= +Somutlaştırma meta veri referansları, kimlik numarasıyla üçlülere başvurur. +Artı: Temiz bir ayrım, üçlü kimlik numaralarını indekslemek mümkündür. +Eksileri: Üçlü kimliğini hesaplamayı/yönetmeyi 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. + +2. **Faz 2+: 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 risklerini azaltır. +>>>>>>> 82edf2d (New md files from RunPod) Tüm depolama sistemlerine yönelik uygulamalara başlamadan önce bu doğrulama yapılır. #### Değer → Terim Yeniden Adlandırma @@ -517,13 +686,21 @@ Yeniden adlandırma, bir zorlama işlevi olarak görev görmektedir: hala ⟦COD ## Güvenlik Hususları Adlandırılmış grafikler bir güvenlik özelliği değildir. Kullanıcılar ve koleksiyonlar, +<<<<<<< HEAD güvenlik sınırlarıdır. Adlandırılmış grafikler tamamen veri organizasyonu ve +======= +güvenlik sınırlarıdır. Adlandırılmış grafikler tamamen veri düzenlemesi ve +>>>>>>> 82edf2d (New md files from RunPod) 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. +<<<<<<< HEAD Verimli grafik kapsamlı sorgular için adlandırılmış grafik indeksleme stratejilerine ihtiyaç vardır. +======= +Verimli grafik kapsamlı sorgular için adlandırılmış grafik indeksleme stratejileri gereklidir. +>>>>>>> 82edf2d (New md files from RunPod) Cassandra şema tasarımı, dörtlü depolamayı verimli bir şekilde karşılayacak şekilde tasarlanmalıdır. ### Vektör Depolama Sınırı @@ -551,6 +728,7 @@ Mevcut üçlüleri dönüştürmek için geçiş araçlarını göz önünde bul ## Açık Sorular +<<<<<<< HEAD **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. @@ -565,6 +743,22 @@ Mevcut üçlüleri dönüştürmek için geçiş araçlarını göz önünde bul ~~**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. +======= +**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 IRİ'ler 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 da 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 edilir, + kullanıcı tarafından tanımlanmış özel özneler de dahil. RDF geçerliliği hakkında çok az varsayım yapılır. + Ç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'lara 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 + grafiğe varsayılan olarak yöneliktir (SPARQL davranışıyla eşleşir, geriye dönük uyumlu). Açık bir grafik + parametresi, adlandırılmış grafiklere veya tüm grafiklere sorgu yapmak için gereklidir. +>>>>>>> 82edf2d (New md files from RunPod) ## Referanslar diff --git a/docs/tech-specs/graphql-query.ar.md b/docs/tech-specs/graphql-query.ar.md index e19e22ea..b340edac 100644 --- a/docs/tech-specs/graphql-query.ar.md +++ b/docs/tech-specs/graphql-query.ar.md @@ -2,6 +2,7 @@ ## Overview +<<<<<<< HEAD تصف هذه المواصفات تنفيذ واجهة استعلام GraphQL للبيانات المنظمة المخزنة في Apache Cassandra. بناءً على إمكانات البيانات المنظمة الموضحة في المواصفات الموجودة في structured-data.md، يوضح هذا المستند كيفية تنفيذ استعلامات GraphQL على جداول Cassandra التي تحتوي على كائنات منظمة مستخرجة ومُدخلة. سيوفر خدمة استعلام GraphQL واجهة مرنة وآمنة من حيث النوع للاستعلام عن البيانات المنظمة المخزنة في Cassandra. ستتكيف ديناميكيًا مع تغييرات المخطط، وتدعم الاستعلامات المعقدة بما في ذلك العلاقات بين الكائنات، وتتكامل بسلاسة مع بنية TrustGraph الحالية القائمة على الرسائل. @@ -76,6 +77,82 @@ ### مراقبة مخطط التكوين ستقوم الخدمة بتسجيل معالج تكوين لتلقي تحديثات المخطط: +======= +This specification describes the implementation of a GraphQL query interface for TrustGraph's structured data storage in Apache Cassandra. Building upon the structured data capabilities outlined in the structured-data.md specification, this document details how GraphQL queries will be executed against Cassandra tables containing extracted and ingested structured objects. + +The GraphQL query service will provide a flexible, type-safe interface for querying structured data stored in Cassandra. It will dynamically adapt to schema changes, support complex queries including relationships between objects, and integrate seamlessly with TrustGraph's existing message-based architecture. + +## Goals + +**Dynamic Schema Support**: Automatically adapt to schema changes in configuration without service restarts +**GraphQL Standards Compliance**: Provide a standard GraphQL interface compatible with existing GraphQL tooling and clients +**Efficient Cassandra Queries**: Translate GraphQL queries into efficient Cassandra CQL queries respecting partition keys and indexes +**Relationship Resolution**: Support GraphQL field resolvers for relationships between different object types +**Type Safety**: Ensure type-safe query execution and response generation based on schema definitions +**Scalable Performance**: Handle concurrent queries efficiently with proper connection pooling and query optimization +**Request/Response Integration**: Maintain compatibility with TrustGraph's Pulsar-based request/response pattern +**Error Handling**: Provide comprehensive error reporting for schema mismatches, query errors, and data validation issues + +## Background + +The structured data storage implementation (trustgraph-flow/trustgraph/storage/objects/cassandra/) writes objects to Cassandra tables based on schema definitions stored in TrustGraph's configuration system. These tables use a composite partition key structure with collection and schema-defined primary keys, enabling efficient queries within collections. + +Current limitations that this specification addresses: +No query interface for the structured data stored in Cassandra +Inability to leverage GraphQL's powerful query capabilities for structured data +Missing support for relationship traversal between related objects +Lack of a standardized query language for structured data access + +The GraphQL query service will bridge these gaps by: +Providing a standard GraphQL interface for querying Cassandra tables +Dynamically generating GraphQL schemas from TrustGraph configuration +Efficiently translating GraphQL queries to Cassandra CQL +Supporting relationship resolution through field resolvers + +## Technical Design + +### Architecture + +The GraphQL query service will be implemented as a new TrustGraph flow processor following established patterns: + +**Module Location**: `trustgraph-flow/trustgraph/query/objects/cassandra/` + +**Key Components**: + +1. **GraphQL Query Service Processor** + Extends base FlowProcessor class + Implements request/response pattern similar to existing query services + Monitors configuration for schema updates + Maintains GraphQL schema synchronized with configuration + +2. **Dynamic Schema Generator** + Converts TrustGraph RowSchema definitions to GraphQL types + Creates GraphQL object types with proper field definitions + Generates root Query type with collection-based resolvers + Updates GraphQL schema when configuration changes + +3. **Query Executor** + Parses incoming GraphQL queries using Strawberry library + Validates queries against current schema + Executes queries and returns structured responses + Handles errors gracefully with detailed error messages + +4. **Cassandra Query Translator** + Converts GraphQL selections to CQL queries + Optimizes queries based on available indexes and partition keys + Handles filtering, pagination, and sorting + Manages connection pooling and session lifecycle + +5. **Relationship Resolver** + Implements field resolvers for object relationships + Performs efficient batch loading to avoid N+1 queries + Caches resolved relationships within request context + Supports both forward and reverse relationship traversal + +### Configuration Schema Monitoring + +The service will register a configuration handler to receive schema updates: +>>>>>>> 82edf2d (New md files from RunPod) ```python self.register_config_handler(self.on_schema_config) @@ -84,7 +161,11 @@ self.register_config_handler(self.on_schema_config) عندما تتغير المخططات: 1. تحليل تعريفات المخططات الجديدة من التكوين. 2. إعادة إنشاء أنواع GraphQL والمحللات. +<<<<<<< HEAD 3. تحديث المخطط القابل للتنفيذ. +======= +3. تحديث المخطط التنفيذي. +>>>>>>> 82edf2d (New md files from RunPod) 4. مسح أي ذاكرة تخزين مؤقت تعتمد على المخطط. ### توليد مخطط GraphQL @@ -92,7 +173,11 @@ self.register_config_handler(self.on_schema_config) لكل RowSchema في التكوين، قم بإنشاء: 1. **نوع كائن GraphQL**: +<<<<<<< HEAD مطابقة أنواع الحقول (string → String, integer → Int, float → Float, boolean → Boolean). +======= + تعيين أنواع الحقول (string → String, integer → Int, float → Float, boolean → Boolean). +>>>>>>> 82edf2d (New md files from RunPod) وضع علامة على الحقول المطلوبة على أنها غير قابلة للقيم الفارغة في GraphQL. إضافة أوصاف الحقول من المخطط. @@ -127,7 +212,11 @@ self.register_config_handler(self.on_schema_config) 4. **تنفيذ الاستعلام**: تنفيذ استعلام CQL مقابل Cassandra. +<<<<<<< HEAD مطابقة النتائج مع هيكل استجابة GraphQL. +======= + تعيين النتائج إلى هيكل استجابة GraphQL. +>>>>>>> 82edf2d (New md files from RunPod) حل أي حقول علاقات. تنسيق الاستجابة وفقًا لمواصفات GraphQL. @@ -138,7 +227,11 @@ self.register_config_handler(self.on_schema_config) ### نماذج البيانات +<<<<<<< HEAD > **ملاحظة**: يوجد مخطط StructuredQueryRequest/Response موجود في `trustgraph-base/trustgraph/schema/services/structured_query.py`. ومع ذلك، فإنه يفتقر إلى حقول مهمة (المستخدم، المجموعة) ويستخدم أنواعًا دون المستوى الأمثل. تمثل المخططات أدناه التطور الموصى به، والتي يجب إما أن تحل محل المخططات الحالية أو يتم إنشاؤها كأنواع ObjectsQueryRequest/Response جديدة. +======= +> **ملاحظة**: يوجد مخطط StructuredQueryRequest/Response موجود في `trustgraph-base/trustgraph/schema/services/structured_query.py`. ومع ذلك، فإنه يفتقر إلى حقول مهمة (المستخدم، المجموعة) ويستخدم أنواعًا دون المستوى الأمثل. تمثل المخططات أدناه التطور الموصى به، والتي يجب إما استبدال المخططات الموجودة بها أو إنشاؤها كأنواع ObjectsQueryRequest/Response جديدة. +>>>>>>> 82edf2d (New md files from RunPod) #### مخطط الطلب (ObjectsQueryRequest) @@ -194,17 +287,28 @@ class ObjectsQueryResponse(Record): 2. **الاستفادة من الفهارس:** استخدام الفهارس الثانوية للتصفية. دمج عوامل التصفية المتعددة كلما أمكن ذلك. +<<<<<<< HEAD التحذير عندما قد تكون الاستعلامات غير فعالة. 3. **التحميل الدفعي:** جمع استعلامات العلاقات. +======= + إصدار تحذير عندما قد تكون الاستعلامات غير فعالة. + +3. **التحميل الدفعي:** + تجميع استعلامات العلاقات. +>>>>>>> 82edf2d (New md files from RunPod) تنفيذها على دفعات لتقليل عدد الرحلات ذهابًا وإيابًا. تخزين النتائج مؤقتًا داخل سياق الطلب. 4. **إدارة الاتصالات:** الحفاظ على جلسات Cassandra مستمرة. استخدام تجميع الاتصالات. +<<<<<<< HEAD التعامل مع إعادة الاتصال في حالة حدوث أخطاء. +======= + التعامل مع إعادة الاتصال في حالة حدوث أعطال. +>>>>>>> 82edf2d (New md files from RunPod) ### أمثلة لاستعلامات GraphQL @@ -287,29 +391,49 @@ class ObjectsQueryResponse(Record): 1. قبول استعلامات GraphQL من العملاء. 2. توجيهها إلى خدمة الاستعلام عبر Pulsar. 3. إرجاع الاستجابات إلى العملاء. +<<<<<<< HEAD 4. دعم استعلامات GraphQL الخاصة بالتحقق من المخطط. +======= +4. دعم استعلامات GraphQL الخاصة بالتحقق (introspection). +>>>>>>> 82edf2d (New md files from RunPod) ### تكامل أداة الوكيل ستتيح فئة أداة وكيل جديدة: توليد استعلامات GraphQL من اللغة الطبيعية. تنفيذ استعلامات GraphQL مباشرة. +<<<<<<< HEAD تفسير وتنسيق النتائج. التكامل مع مسارات قرار الوكيل. +======= +تفسير النتائج وتنسيقها. +التكامل مع تدفقات قرار الوكيل. +>>>>>>> 82edf2d (New md files from RunPod) ## اعتبارات الأمان **تحديد عمق الاستعلام**: منع الاستعلامات المتداخلة بعمق والتي يمكن أن تسبب مشاكل في الأداء. +<<<<<<< HEAD **تحليل تعقيد الاستعلام**: الحد من تعقيد الاستعلام لمنع استنفاد الموارد. **أذونات على مستوى الحقل**: دعم مستقبلي للتحكم في الوصول على مستوى الحقل بناءً على أدوار المستخدم. **تنظيف الإدخال**: التحقق من صحة وتنظيف جميع مدخلات الاستعلام لمنع هجمات الحقن. **تحديد المعدل**: تنفيذ تحديد معدل الاستعلام لكل مستخدم/مجموعة. +======= +**تحليل تعقيد الاستعلام**: تحديد تعقيد الاستعلام لمنع استنفاد الموارد. +**أذونات على مستوى الحقل**: دعم مستقبلي للتحكم في الوصول على مستوى الحقل بناءً على أدوار المستخدم. +**تنظيف الإدخال**: التحقق من صحة وتنظيف جميع مدخلات الاستعلام لمنع هجمات الحقن. +**تحديد المعدل**: تطبيق تحديد معدل الاستعلام لكل مستخدم/مجموعة. +>>>>>>> 82edf2d (New md files from RunPod) ## اعتبارات الأداء **تخطيط الاستعلام**: تحليل الاستعلامات قبل التنفيذ لتحسين توليد CQL. **تخزين النتائج مؤقتًا**: ضع في اعتبارك تخزين البيانات التي يتم الوصول إليها بشكل متكرر مؤقتًا على مستوى محلل الحقل. +<<<<<<< HEAD **تجميع الاتصالات**: حافظ على مجموعات اتصالات فعالة إلى Cassandra. +======= +**تجميع الاتصالات**: حافظ على تجمعات اتصالات فعالة إلى Cassandra. +>>>>>>> 82edf2d (New md files from RunPod) **العمليات الدفعية**: اجمع بين استعلامات متعددة كلما أمكن ذلك لتقليل زمن الوصول. **المراقبة**: تتبع مقاييس أداء الاستعلام لتحسين الأداء. @@ -328,7 +452,11 @@ class ObjectsQueryResponse(Record): التحقق من صحة هيكل الأخطاء ### اختبارات التكامل +<<<<<<< HEAD تنفيذ استعلامات شاملة مقابل نسخة اختبار Cassandra +======= +تنفيذ الاستعلامات من طرف إلى طرف مقابل مثيل Cassandra للاختبار +>>>>>>> 82edf2d (New md files from RunPod) معالجة تحديثات المخططات حل العلاقات الترقيم والتصفية @@ -366,18 +494,30 @@ class ObjectsQueryResponse(Record): ضع في اعتبارك: الإبطال بناءً على الأحداث 3. **دعم التجميع**: هل يجب أن تدعم الخدمة تجميع GraphQL لدمجها مع مصادر بيانات أخرى؟ +<<<<<<< HEAD سيمكن ذلك من إجراء استعلامات موحدة عبر البيانات المهيكلة والبيانات الرسومية +======= + سيمكن ذلك من الاستعلامات الموحدة عبر البيانات المهيكلة والبيانات الرسومية +>>>>>>> 82edf2d (New md files from RunPod) 4. **دعم الاشتراكات**: هل يجب أن تدعم الخدمة اشتراكات GraphQL للتحديثات في الوقت الفعلي؟ سيتطلب ذلك دعم WebSocket في البوابة +<<<<<<< HEAD 5. **أنواع قياسية مخصصة**: هل يجب دعم الأنواع القياسية المخصصة لأنواع البيانات الخاصة بالمجال؟ +======= +5. **الأنواع العددية المخصصة**: هل يجب دعم الأنواع العددية المخصصة لأنواع البيانات الخاصة بالمجال؟ +>>>>>>> 82edf2d (New md files from RunPod) أمثلة: DateTime، UUID، حقول JSON ## المراجع المواصفات الفنية للبيانات المهيكلة: `docs/tech-specs/structured-data.md` +<<<<<<< HEAD وثائق GraphQL Strawberry: https://strawberry.rocks/ +======= +وثائق Strawberry GraphQL: https://strawberry.rocks/ +>>>>>>> 82edf2d (New md files from RunPod) مواصفات 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 index fe28b784..17019bac 100644 --- a/docs/tech-specs/graphql-query.es.md +++ b/docs/tech-specs/graphql-query.es.md @@ -4,12 +4,17 @@ 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. +<<<<<<< HEAD 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. +======= +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, incluidas las relaciones entre objetos, y se integrará perfectamente con la arquitectura existente basada en mensajes de TrustGraph. +>>>>>>> 82edf2d (New md files from RunPod) ## 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. +<<<<<<< HEAD **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. @@ -24,14 +29,35 @@ La implementación del almacenamiento de datos estructurados (trustgraph-flow/tr 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. +======= +**Consultas Eficientes de Cassandra**: Traducir las consultas GraphQL en consultas CQL eficientes de Cassandra, respetando las claves de partición y los índices. +**Resolución de Relaciones**: Soporte para los resolvedores de campos GraphQL para las relaciones entre diferentes tipos de objetos. +**Seguridad de Tipos**: Garantizar la ejecución de consultas y la generación de respuestas seguras, basadas en las definiciones del esquema. +**Rendimiento Escalable**: Manejar las consultas concurrentes de manera eficiente con un correcto agrupamiento de conexiones y optimización de consultas. +**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 las discrepancias del esquema, los errores de consulta y los 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 la colección y el 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 potentes capacidades de consulta de GraphQL para los datos estructurados. +>>>>>>> 82edf2d (New md files from RunPod) 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. +<<<<<<< HEAD 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. +======= +Traducir de forma eficiente las consultas GraphQL a CQL de Cassandra. +Soporte para la resolución de relaciones a través de resolvedores de campos. +>>>>>>> 82edf2d (New md files from RunPod) ## Diseño Técnico @@ -52,7 +78,11 @@ El servicio de consulta GraphQL se implementará como un nuevo procesador de flu 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. +<<<<<<< HEAD Genera el tipo de consulta raíz con resolutores basados en colecciones. +======= + Genera el tipo de consulta raíz con resolvedores basados en colecciones. +>>>>>>> 82edf2d (New md files from RunPod) Actualiza el esquema GraphQL cuando cambia la configuración. 3. **Ejecutor de Consultas** @@ -65,17 +95,28 @@ El servicio de consulta GraphQL se implementará como un nuevo procesador de flu 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. +<<<<<<< HEAD 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. +======= + Administra el agrupamiento de conexiones y el ciclo de vida de la sesión. + +5. **Resolvedor de Relaciones** + Implementa resolvedores de campos para las relaciones de objetos. +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD El servicio se registrará con un controlador de configuración para recibir actualizaciones de esquema: +======= +El servicio se registrará con un controlador de configuración para recibir actualizaciones del esquema: +>>>>>>> 82edf2d (New md files from RunPod) ```python self.register_config_handler(self.on_schema_config) @@ -138,7 +179,11 @@ Para cada RowSchema en la configuración, generar: ### Modelos de Datos +<<<<<<< HEAD > **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. +======= +> **Nota**: Existe un esquema existente de StructuredQueryRequest/Response en `trustgraph-base/trustgraph/schema/services/structured_query.py`. Sin embargo, carece de 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. +>>>>>>> 82edf2d (New md files from RunPod) #### Esquema de Solicitud (ObjectsQueryRequest) @@ -153,7 +198,11 @@ class ObjectsQueryRequest(Record): operation_name = String() # Operation to execute for multi-operation documents ``` +<<<<<<< HEAD **Justificación de los cambios desde la solicitud de consulta estructurada existente:** +======= +**Justificación de los cambios con respecto a la solicitud de consulta estructurada existente:** +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -194,7 +243,11 @@ El servicio optimizará las consultas de Cassandra mediante: 2. **Aprovechando los índices:** Utilizar índices secundarios para filtrar Combinar múltiples filtros siempre que sea posible +<<<<<<< HEAD Emitir una advertencia cuando las consultas puedan ser ineficientes +======= + Advertir cuando las consultas puedan ser ineficientes +>>>>>>> 82edf2d (New md files from RunPod) 3. **Carga por lotes:** Recopilar consultas de relaciones @@ -275,7 +328,11 @@ Argumentos estándar de FlowProcessor (configuración de Pulsar, etc.). **Tema de entrada**: `objects-graphql-query-request` Esquema: ObjectsQueryRequest +<<<<<<< HEAD Recibe consultas GraphQL de los servicios de puerta de enlace. +======= +Recibe consultas GraphQL de los servicios de la puerta de enlace. +>>>>>>> 82edf2d (New md files from RunPod) **Tema de salida**: `objects-graphql-query-response` Esquema: ObjectsQueryResponse @@ -286,8 +343,13 @@ Devuelve los resultados de la consulta y los errores. 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. +<<<<<<< HEAD 3. Devolver respuestas a los clientes. 4. Compatibilidad con consultas de introspección de GraphQL. +======= +3. Devolver las respuestas a los clientes. +4. Compatibilidad con las consultas de introspección de GraphQL. +>>>>>>> 82edf2d (New md files from RunPod) ### Integración de la herramienta de agente @@ -295,7 +357,11 @@ 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. +<<<<<<< HEAD Integración con flujos de decisión de agentes. +======= +Integración con los flujos de decisión del agente. +>>>>>>> 82edf2d (New md files from RunPod) ## Consideraciones de seguridad @@ -308,9 +374,15 @@ Integración con flujos de decisión de agentes. ## Consideraciones de rendimiento **Planificación de consultas**: Analizar las consultas antes de la ejecución para optimizar la generación de CQL. +<<<<<<< HEAD **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. +======= +**Caché de resultados**: Considerar el almacenamiento en caché de los 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 siempre que sea posible para reducir la latencia. +>>>>>>> 82edf2d (New md files from RunPod) **Supervisión**: Supervisar las métricas de rendimiento de las consultas para la optimización. ## Estrategia de pruebas @@ -379,5 +451,9 @@ Semana 6: Integración con la puerta de enlace y documentación 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/ +<<<<<<< HEAD Referencia de CQL de Apache Cassandra: https://cassandra.apache.org/doc/stable/cassandra/cql/ +======= +Referencia CQL de Apache Cassandra: https://cassandra.apache.org/doc/stable/cassandra/cql/ +>>>>>>> 82edf2d (New md files from RunPod) 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 index 7ed2b2b1..37bbd4a9 100644 --- a/docs/tech-specs/graphql-query.he.md +++ b/docs/tech-specs/graphql-query.he.md @@ -2,26 +2,44 @@ ## Overview +<<<<<<< HEAD מפרט זה מתאר את יישום ממשק שאילתות GraphQL עבור אחסון נתונים מובנים של TrustGraph ב-Apache Cassandra. בהתבסס על יכולות הנתונים המובנים המתוארות במפרט structured-data.md, מסמך זה מפרט כיצד שאילתות GraphQL יבוצעו כנגד טבלאות Cassandra המכילות אובייקטים מובנים שחולצו והועברו. +======= +מפרט זה מתאר את יישום ממשק שאילתות GraphQL עבור אחסון נתונים מובנים של TrustGraph ב-Apache Cassandra. בהתבסס על יכולות הנתונים המובנים המתוארות במפרט structured-data.md, מסמך זה מפרט כיצד שאילתות GraphQL יבוצעו כנגד טבלאות Cassandra המכילות אובייקטים מובנים שחולצו ויועברו. +>>>>>>> 82edf2d (New md files from RunPod) שירות שאילתות GraphQL יספק ממשק גמיש ובטוח טיפוסית לשאילתות נתונים מובנים המאוחסנים ב-Cassandra. הוא יסתגל באופן דינמי לשינויים בסכימה, יתמוך בשאילתות מורכבות כולל קשרים בין אובייקטים, וישתלב בצורה חלקה עם ארכיטקטורת העברת הודעות הקיימת של TrustGraph. ## Goals **תמיכה דינמית בסכימה**: הסתגלות אוטומטית לשינויים בסכימה בתצורה ללא אתחולים מחדש של השירות +<<<<<<< HEAD **עמידה בתקני GraphQL**: מתן ממשק GraphQL סטנדרטי התואם לכלי לקוחות GraphQL קיימים **שאילתות Cassandra יעילות**: המרת שאילתות GraphQL לשאילתות CQL יעילות של Cassandra תוך כיבוד מפתחות מחיצה ואינדקסים **פתרון קשרים**: תמיכה במאפייני פותרים עבור קשרים בין סוגי אובייקטים שונים **בטיחות טיפוסים**: הבטחת ביצוע שאילתות ובניית תגובות בצורה בטוחה טיפוסית בהתבסס על הגדרות סכימה **ביצועים ניתנים להרחבה**: טיפול יעיל בשאילתות מקבילות עם ניהול חיבורים מתאים ואופטימיזציה של שאילתות +======= +**עמידה בתקני GraphQL**: מתן ממשק GraphQL סטנדרטי התואם לכלי ולקוחות GraphQL קיימים +**שאילתות Cassandra יעילות**: המרת שאילתות GraphQL לשאילתות CQL יעילות של Cassandra תוך כיבוד מפתחות מחיצה ואינדקסים +**פתרון קשרים**: תמיכה בפתרוני שדות עבור קשרים בין סוגי אובייקטים שונים +**בטיחות טיפוסים**: הבטחת ביצוע שאילתות ובניית תגובות בצורה בטוחה טיפוסית בהתבסס על הגדרות סכימה +**ביצועים ניתנים להרחבה**: טיפול יעיל בשאילתות מקבילות עם ניהול בריכת חיבורים ואופטימיזציה של שאילתות +>>>>>>> 82edf2d (New md files from RunPod) **אינטגרציה של בקשות/תגובות**: שמירה על תאימות לדפוס בקשות/תגובות המבוסס על Pulsar של TrustGraph **טיפול בשגיאות**: מתן דיווח מקיף על שגיאות עבור חוסר התאמה בסכימה, שגיאות שאילתות ובעיות אימות נתונים ## Background +<<<<<<< HEAD יישום אחסון הנתונים המובנים (trustgraph-flow/trustgraph/storage/objects/cassandra/) כותב אובייקטים לטבלאות Cassandra בהתבסס על הגדרות סכימה המאוחסנות במערכת התצורה של TrustGraph. טבלאות אלה משתמשות במבנה מפתח מחיצה מורכב עם אוספים ומפתחות ראשיים המוגדרים בסכימה, המאפשרות שאילתות יעילות בתוך אוספים. מגבלות קיימות שספציפיקציה זו מתייחסת אליהן: +======= +יישום אחסון הנתונים המובנים (trustgraph-flow/trustgraph/storage/objects/cassandra/) כותב אובייקטים לטבלאות Cassandra בהתבסס על הגדרות סכימה המאוחסנות במערכת התצורה של TrustGraph. טבלאות אלה משתמשות במבנה מפתח מחיצה מורכב עם אוספים ומפתחות ראשיים המוגדרים בסכימה, המאפשרים שאילתות יעילות בתוך אוספים. + +מגבלות נוכחיות שמתפרט זה מטפל בהן: +>>>>>>> 82edf2d (New md files from RunPod) אין ממשק שאילתות עבור הנתונים המובנים המאוחסנים ב-Cassandra חוסר יכולת לנצל את יכולות השאילתות החזקות של GraphQL עבור נתונים מובנים חוסר תמיכה במעבר על קשרים בין אובייקטים קשורים @@ -31,7 +49,11 @@ מתן ממשק GraphQL סטנדרטי לשאילתות של טבלאות Cassandra יצירת סכימות GraphQL באופן דינמי מתצורה של TrustGraph המרת יעילה של שאילתות GraphQL לשאילתות CQL של Cassandra +<<<<<<< HEAD תמיכה בפתרון קשרים באמצעות פותרים של שדות +======= +תמיכה בפתרון קשרים באמצעות פתרוני שדות +>>>>>>> 82edf2d (New md files from RunPod) ## Technical Design @@ -49,10 +71,17 @@ מנטר את התצורה עבור עדכוני סכימה שומר על סכימת GraphQL מסונכרנת עם התצורה +<<<<<<< HEAD 2. **מחולל סכימה דינמי** ממיר הגדרות RowSchema של TrustGraph לטיפוסי GraphQL יוצר טיפוסי אובייקטים של GraphQL עם הגדרות שדות מתאימות מייצר טיפוס שורש Query עם פותרים מבוססי אוספים +======= +2. **מחולל סכימה דינמית** + ממיר הגדרות RowSchema של TrustGraph לסוגי GraphQL + יוצר סוגי אובייקטים של GraphQL עם הגדרות שדות מתאימות + מייצר סוג שאילתא ראשי עם פותרים מבוססי אוספים +>>>>>>> 82edf2d (New md files from RunPod) מעדכן את סכימת GraphQL כאשר התצורה משתנה 3. **מבצע שאילתות** @@ -65,10 +94,17 @@ ממיר בחירות GraphQL לשאילתות CQL מייעל שאילתות בהתבסס על אינדקסים ומפתחות מחיצה זמינים מטפל בסינון, דפוס ומיון +<<<<<<< HEAD מנהל ניהול חיבורים ומחזור חיים של סשן 5. **פותר קשרים** מיישם פותרים של שדות עבור קשרים בין אובייקטים +======= + מנהל ניהול בריכת חיבורים ומחזור חיים של סשן + +5. **פתרון קשרים** + מיישם פתרוני שדות עבור קשרים בין אובייקטים +>>>>>>> 82edf2d (New md files from RunPod) מבצע טעינה באצווה יעילה כדי למנוע שאילתות N+1 שומר על קשרים פתורים בהקשר הבקשה תומך במעבר קשרים קדימה ואחורה @@ -138,7 +174,11 @@ self.register_config_handler(self.on_schema_config) ### מודלים של נתונים +<<<<<<< HEAD > **הערה**: קיימת סכימת StructuredQueryRequest/Response קיימת ב-`trustgraph-base/trustgraph/schema/services/structured_query.py`. עם זאת, היא חסרה שדות קריטיים (משתמש, אוסף) ומשתמשת בסוגים לא אופטימליים. הסכימות שלהלן מייצגות את ההתפתחות המומלצת, שעליה להחליף את הסכימות הקיימות או ליצור סוגי ObjectsQueryRequest/Response חדשים. +======= +> **הערה**: קיימת סכימת StructuredQueryRequest/Response קיימת ב-`trustgraph-base/trustgraph/schema/services/structured_query.py`. עם זאת, היא חסרה שדות קריטיים (משתמש, אוסף) ומשתמשת בסוגים לא אופטימליים. הסכימות שלהלן מייצגות את ההתפתחות המומלצת, שעשויה להחליף את הסכימות הקיימות או ליצור סוגי ObjectsQueryRequest/Response חדשים. +>>>>>>> 82edf2d (New md files from RunPod) #### סכימת בקשה (ObjectsQueryRequest) @@ -153,12 +193,21 @@ class ObjectsQueryRequest(Record): operation_name = String() # Operation to execute for multi-operation documents ``` +<<<<<<< HEAD **ההצדקה לשינויים מתוך בקשת StructuredQueryRequest קיימת:** הוספת השדות `user` ו-`collection` כדי להתאים לדפוס של שירותי שאילתות אחרים. שדות אלה חיוניים לזיהוי ה-keyspace והקולקציה של Cassandra. המשתנים נשארים מסוג Map(String()) כרגע, אך באופן אידיאלי צריכים לתמוך בכל סוגי ה-JSON. #### סכימת תגובה (ObjectsQueryResponse) +======= +**ההצדקה לשינויים מהבקשה המובנית הקיימת (StructuredQueryRequest):** +הוספת השדות `user` ו-`collection` כדי להתאים לדפוס של שירותי שאילתות אחרים. +שדות אלה חיוניים לזיהוי מרחב המפתחות (keyspace) והאוסף (collection) של Cassandra. +המשתנים נשארים מסוג Map(String()) כרגע, אך באופן אידיאלי צריכים לתמוך בכל סוגי ה-JSON. + +#### סכימת התגובה (ObjectsQueryResponse) +>>>>>>> 82edf2d (New md files from RunPod) ```python from pulsar.schema import Record, String, Array @@ -198,7 +247,11 @@ class ObjectsQueryResponse(Record): 3. **טעינה באצווה:** לאסוף שאילתות קשר +<<<<<<< HEAD לבצע אותן באצווה כדי להפחית את מספר הפעמים +======= + לבצע אותן באצווה כדי להפחית מעברים +>>>>>>> 82edf2d (New md files from RunPod) לשמור תוצאות בהקשר הבקשה 4. **ניהול חיבורים:** @@ -256,7 +309,11 @@ class ObjectsQueryResponse(Record): **Strawberry GraphQL**: להגדרת סכימת GraphQL ולביצוע שאילתות **Cassandra Driver**: לחיבור למסד הנתונים (בשימוש כבר במודול האחסון) **TrustGraph Base**: עבור FlowProcessor והגדרות סכימה +<<<<<<< HEAD **Configuration System**: לניטור ועדכון סכימות +======= +**Configuration System**: עבור ניטור ועדכון סכימות +>>>>>>> 82edf2d (New md files from RunPod) ### ממשק שורת הפקודה @@ -332,7 +389,11 @@ class ObjectsQueryResponse(Record): טיפול בעדכוני סכימה פתרון קשרים דפוסים של דף אחרי דף וסינון +<<<<<<< HEAD תרחישי שגיאות +======= +תרחישי שגיאה +>>>>>>> 82edf2d (New md files from RunPod) ### בדיקות ביצועים תפוקת שאילתות תחת עומס @@ -342,8 +403,13 @@ class ObjectsQueryResponse(Record): ## תוכנית מעבר +<<<<<<< HEAD אין צורך במעבר מכיוון שזו יכולת חדשה. השירות י: 1. יקרא סכימות קיימות מהתצורה +======= +אין צורך במעבר מכיוון שזו יכולת חדשה. השירות יעשה את הפעולות הבאות: +1. יקרא סכימות קיימות מהגדרות +>>>>>>> 82edf2d (New md files from RunPod) 2. יתחבר לטבלאות Cassandra קיימות שנוצרו על ידי מודול האחסון 3. יתחיל לקבל שאילתות מיד עם הפריסה @@ -352,7 +418,11 @@ class ObjectsQueryResponse(Record): שבוע 1-2: יישום ליבת השירות ויצירת סכימה שבוע 3: ביצוע שאילתות ותרגום CQL שבוע 4: פתרון קשרים ואופטימיזציה +<<<<<<< HEAD שבוע 5: בדיקות וכוונון ביצועים +======= +שבוע 5: בדיקות וכיוונון ביצועים +>>>>>>> 82edf2d (New md files from RunPod) שבוע 6: שילוב עם שער ותיעוד ## שאלות פתוחות @@ -380,4 +450,8 @@ class ObjectsQueryResponse(Record): תיעוד 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 +<<<<<<< HEAD +תיעוד מעבד זרימת נתונים TrustGraph: תיעוד פנימי +======= +תיעוד מעבד זרימה של TrustGraph: תיעוד פנימי +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/graphql-query.hi.md b/docs/tech-specs/graphql-query.hi.md index 2fa6f66d..eb931483 100644 --- a/docs/tech-specs/graphql-query.hi.md +++ b/docs/tech-specs/graphql-query.hi.md @@ -4,28 +4,48 @@ यह विनिर्देश अपाचे कैसेंड्रा में ट्रस्टग्राफ के संरचित डेटा भंडारण के लिए एक GraphQL क्वेरी इंटरफ़ेस के कार्यान्वयन का वर्णन करता है। संरचित-डेटा.md विनिर्देश में उल्लिखित संरचित डेटा क्षमताओं पर निर्माण करते हुए, यह दस्तावेज़ बताता है कि निकाले गए और संसाधित संरचित ऑब्जेक्ट युक्त कैसेंड्रा तालिकाओं के खिलाफ GraphQL क्वेरी कैसे निष्पादित की जाएंगी। +<<<<<<< HEAD GraphQL क्वेरी सेवा कैसेंड्रा में संग्रहीत संरचित डेटा के लिए एक लचीला, टाइप-सुरक्षित इंटरफ़ेस प्रदान करेगी। यह स्कीमा परिवर्तनों के लिए गतिशील रूप से अनुकूल होगा, ऑब्जेक्ट के बीच संबंधों सहित जटिल प्रश्नों का समर्थन करेगा, और ट्रस्टग्राफ के मौजूदा संदेश-आधारित वास्तुकला के साथ सहजता से एकीकृत होगा। ## लक्ष्य **गतिशील स्कीमा समर्थन**: सेवा को पुनरारंभ किए बिना कॉन्फ़िगरेशन में स्कीमा परिवर्तनों के लिए स्वचालित रूप से अनुकूल होना। +======= +GraphQL क्वेरी सेवा कैसेंड्रा में संग्रहीत संरचित डेटा के लिए एक लचीला, टाइप-सुरक्षित इंटरफ़ेस प्रदान करेगी। यह स्कीमा परिवर्तनों के लिए गतिशील रूप से अनुकूल होगा, ऑब्जेक्ट के बीच संबंधों सहित जटिल क्वेरी का समर्थन करेगा, और ट्रस्टग्राफ के मौजूदा संदेश-आधारित आर्किटेक्चर के साथ सहजता से एकीकृत होगा। + +## लक्ष्य + +**डायनामिक स्कीमा समर्थन**: सेवा को पुनरारंभ किए बिना कॉन्फ़िगरेशन में स्कीमा परिवर्तनों के लिए स्वचालित रूप से अनुकूल होना। +>>>>>>> 82edf2d (New md files from RunPod) **GraphQL मानकों का अनुपालन**: मौजूदा GraphQL टूलिंग और क्लाइंट के साथ संगत एक मानक GraphQL इंटरफ़ेस प्रदान करना। **कुशल कैसेंड्रा क्वेरी**: GraphQL क्वेरी को कुशल कैसेंड्रा CQL क्वेरी में अनुवाद करना, विभाजन कुंजियों और अनुक्रमणिकाओं का सम्मान करना। **संबंध संकल्प**: विभिन्न ऑब्जेक्ट प्रकारों के बीच संबंधों के लिए GraphQL फ़ील्ड रिज़ॉल्वर का समर्थन करना। **टाइप सुरक्षा**: स्कीमा परिभाषाओं के आधार पर टाइप-सुरक्षित क्वेरी निष्पादन और प्रतिक्रिया पीढ़ी सुनिश्चित करना। +<<<<<<< HEAD **मापनीय प्रदर्शन**: उचित कनेक्शन पूलिंग और क्वेरी अनुकूलन के साथ समवर्ती प्रश्नों को कुशलतापूर्वक संभालना। +======= +**स्केलेबल प्रदर्शन**: उचित कनेक्शन पूलिंग और क्वेरी अनुकूलन के साथ समवर्ती क्वेरी को कुशलतापूर्वक संभालना। +>>>>>>> 82edf2d (New md files from RunPod) **अनुरोध/प्रतिक्रिया एकीकरण**: ट्रस्टग्राफ के पल्सर-आधारित अनुरोध/प्रतिक्रिया पैटर्न के साथ संगतता बनाए रखना। **त्रुटि प्रबंधन**: स्कीमा मिसमैच, क्वेरी त्रुटियों और डेटा सत्यापन मुद्दों के लिए व्यापक त्रुटि रिपोर्टिंग प्रदान करना। ## पृष्ठभूमि +<<<<<<< HEAD संरचित डेटा भंडारण कार्यान्वयन (trustgraph-flow/trustgraph/storage/objects/cassandra/) ट्रस्टग्राफ के कॉन्फ़िगरेशन सिस्टम में संग्रहीत स्कीमा परिभाषाओं के आधार पर कैसेंड्रा तालिकाओं में ऑब्जेक्ट लिखता है। ये तालिकाएँ एक समग्र विभाजन कुंजी संरचना का उपयोग करती हैं जिसमें संग्रह और स्कीमा-परिभाषित प्राथमिक कुंजियाँ होती हैं, जो संग्रह के भीतर कुशल प्रश्नों को सक्षम करती हैं। +======= +संरचित डेटा भंडारण कार्यान्वयन (trustgraph-flow/trustgraph/storage/objects/cassandra/) ट्रस्टग्राफ के कॉन्फ़िगरेशन सिस्टम में संग्रहीत स्कीमा परिभाषाओं के आधार पर कैसेंड्रा तालिकाओं में ऑब्जेक्ट लिखता है। ये तालिकाएँ एक समग्र विभाजन कुंजी संरचना का उपयोग करती हैं जिसमें संग्रह और स्कीमा-परिभाषित प्राथमिक कुंजियाँ होती हैं, जो संग्रह के भीतर कुशल क्वेरी को सक्षम करती हैं। +>>>>>>> 82edf2d (New md files from RunPod) वर्तमान सीमाएँ जिन्हें इस विनिर्देश द्वारा संबोधित किया गया है: कैसेंड्रा में संग्रहीत संरचित डेटा के लिए कोई क्वेरी इंटरफ़ेस नहीं। संरचित डेटा के लिए GraphQL की शक्तिशाली क्वेरी क्षमताओं का लाभ उठाने में असमर्थता। संबंधित ऑब्जेक्ट के बीच संबंध ट्रैवर्सल के लिए कोई समर्थन नहीं। +<<<<<<< HEAD संरचित डेटा एक्सेस के लिए एक मानकीकृत क्वेरी भाषा का अभाव। +======= +संरचित डेटा एक्सेस के लिए एक मानकीकृत क्वेरी भाषा की कमी। +>>>>>>> 82edf2d (New md files from RunPod) GraphQL क्वेरी सेवा इन कमियों को भरकर: कैसेंड्रा तालिकाओं के लिए एक मानक GraphQL इंटरफ़ेस प्रदान करना। @@ -35,7 +55,11 @@ GraphQL क्वेरी सेवा इन कमियों को भर ## तकनीकी डिजाइन +<<<<<<< HEAD ### वास्तुकला +======= +### आर्किटेक्चर +>>>>>>> 82edf2d (New md files from RunPod) GraphQL क्वेरी सेवा को एक नए ट्रस्टग्राफ फ्लो प्रोसेसर के रूप में लागू किया जाएगा जो स्थापित पैटर्न का पालन करता है: @@ -49,7 +73,11 @@ GraphQL क्वेरी सेवा को एक नए ट्रस्ट स्कीमा अपडेट के लिए कॉन्फ़िगरेशन की निगरानी करता है। कॉन्फ़िगरेशन के साथ GraphQL स्कीमा को सिंक्रनाइज़ रखता है। +<<<<<<< HEAD 2. **गतिशील स्कीमा जनरेटर** +======= +2. **डायनामिक स्कीमा जनरेटर** +>>>>>>> 82edf2d (New md files from RunPod) ट्रस्टग्राफ RowSchema परिभाषाओं को GraphQL प्रकारों में परिवर्तित करता है। उचित फ़ील्ड परिभाषाओं के साथ GraphQL ऑब्जेक्ट प्रकार बनाता है। संग्रह-आधारित रिज़ॉल्वर के साथ रूट क्वेरी प्रकार उत्पन्न करता है। @@ -59,9 +87,15 @@ GraphQL क्वेरी सेवा को एक नए ट्रस्ट Strawberry लाइब्रेरी का उपयोग करके आने वाली GraphQL क्वेरी को पार्स करता है। वर्तमान स्कीमा के विरुद्ध क्वेरी को मान्य करता है। क्वेरी निष्पादित करता है और संरचित प्रतिक्रियाएँ लौटाता है। +<<<<<<< HEAD विस्तृत त्रुटि संदेशों के साथ त्रुटियों को कुशलतापूर्वक संभालता है। 4. **कैसेंड्रा क्वेरी अनुवादक** +======= + विस्तृत त्रुटि संदेशों के साथ त्रुटियों को सुचारू रूप से संभालता है। + +4. **कैसेंड्रा क्वेरी ट्रांसलेटर** +>>>>>>> 82edf2d (New md files from RunPod) GraphQL चयन को CQL क्वेरी में परिवर्तित करता है। उपलब्ध अनुक्रमणिकाओं और विभाजन कुंजियों के आधार पर क्वेरी को अनुकूलित करता है। फ़िल्टरिंग, पेजिंग और सॉर्टिंग को संभालता है। @@ -109,7 +143,11 @@ self.register_config_handler(self.on_schema_config) ### क्वेरी निष्पादन प्रवाह +<<<<<<< HEAD 1. **अनुरोध स्वागत**: +======= +1. **अनुरोध रिसेप्शन**: +>>>>>>> 82edf2d (New md files from RunPod) Pulsar से ObjectsQueryRequest प्राप्त करें। GraphQL क्वेरी स्ट्रिंग और चर निकालें। उपयोगकर्ता और संग्रह संदर्भ की पहचान करें। @@ -153,7 +191,11 @@ class ObjectsQueryRequest(Record): operation_name = String() # Operation to execute for multi-operation documents ``` +<<<<<<< HEAD **मौजूदा StructuredQueryRequest से परिवर्तनों का तर्क:** +======= +**मौजूदा StructuredQueryRequest से परिवर्तनों का कारण:** +>>>>>>> 82edf2d (New md files from RunPod) अन्य क्वेरी सेवाओं के पैटर्न से मेल खाने के लिए `user` और `collection` फ़ील्ड जोड़े गए। ये फ़ील्ड कैसेंड्रा की स्पेस और कलेक्शन की पहचान करने के लिए आवश्यक हैं। वेरिएबल अभी भी Map(String()) के रूप में हैं, लेकिन आदर्श रूप से सभी JSON प्रकारों का समर्थन करना चाहिए। @@ -253,10 +295,17 @@ GraphQL विनिर्देश के अनुपालन के लि ### कार्यान्वयन निर्भरताएँ +<<<<<<< HEAD **स्ट्रॉबेरी ग्राफक्यूएल (Strawberry GraphQL)**: ग्राफक्यूएल स्कीमा परिभाषा और क्वेरी निष्पादन के लिए **कैसेंड्रा ड्राइवर (Cassandra Driver)**: डेटाबेस कनेक्टिविटी के लिए (भंडारण मॉड्यूल में पहले से उपयोग किया गया) **ट्रस्टग्राफ बेस (TrustGraph Base)**: फ्लोप्रोसेसर और स्कीमा परिभाषाओं के लिए **कॉन्फ़िगरेशन सिस्टम (Configuration System)**: स्कीमा निगरानी और अपडेट के लिए +======= +**स्ट्रॉबेरी ग्राफक्यूएल**: ग्राफक्यूएल स्कीमा परिभाषा और क्वेरी निष्पादन के लिए +**कैसेंड्रा ड्राइवर**: डेटाबेस कनेक्टिविटी के लिए (भंडारण मॉड्यूल में पहले से उपयोग किया गया) +**ट्रस्टग्राफ बेस**: फ्लोप्रोसेसर और स्कीमा परिभाषाओं के लिए +**कॉन्फ़िगरेशन सिस्टम**: स्कीमा निगरानी और अपडेट के लिए +>>>>>>> 82edf2d (New md files from RunPod) ### कमांड-लाइन इंटरफ़ेस @@ -271,6 +320,7 @@ GraphQL विनिर्देश के अनुपालन के लि ## एपीआई एकीकरण +<<<<<<< HEAD ### पल्सर विषय (Pulsar Topics) **इनपुट टॉपिक (Input Topic)**: `objects-graphql-query-request` @@ -279,19 +329,38 @@ GraphQL विनिर्देश के अनुपालन के लि **आउटपुट टॉपिक (Output Topic)**: `objects-graphql-query-response` स्कीमा: ऑब्जेक्ट्सक्वेरीरिस्पांस (ObjectsQueryResponse) +======= +### पल्सर विषय + +**इनपुट टॉपिक**: `objects-graphql-query-request` +स्कीमा: ऑब्जेक्ट्सक्वेरीरिक्वेस्ट +गेटवे सेवाओं से ग्राफक्यूएल क्वेरी प्राप्त करता है + +**आउटपुट टॉपिक**: `objects-graphql-query-response` +स्कीमा: ऑब्जेक्ट्सक्वेरीरिस्पांस +>>>>>>> 82edf2d (New md files from RunPod) क्वेरी परिणाम और त्रुटियां लौटाता है ### गेटवे एकीकरण गेटवे और रिवर्स-गेटवे को निम्नलिखित के लिए एंडपॉइंट की आवश्यकता होगी: 1. क्लाइंट से ग्राफक्यूएल क्वेरी स्वीकार करें +<<<<<<< HEAD 2. पल्सर के माध्यम से क्वेरी सेवा को आगे बढ़ाएं 3. क्लाइंट को प्रतिक्रियाएं लौटाएं +======= +2. पल्सर के माध्यम से क्वेरी सेवा को भेजें +3. क्लाइंट को प्रतिक्रिया लौटाएं +>>>>>>> 82edf2d (New md files from RunPod) 4. ग्राफक्यूएल इंट्रॉस्पेक्शन क्वेरी का समर्थन करें ### एजेंट टूल एकीकरण +<<<<<<< HEAD एक नया एजेंट टूल क्लास निम्नलिखित को सक्षम करेगा: +======= +एक नई एजेंट टूल क्लास निम्नलिखित को सक्षम करेगी: +>>>>>>> 82edf2d (New md files from RunPod) प्राकृतिक भाषा से ग्राफक्यूएल क्वेरी पीढ़ी प्रत्यक्ष ग्राफक्यूएल क्वेरी निष्पादन परिणाम व्याख्या और स्वरूपण @@ -299,6 +368,7 @@ GraphQL विनिर्देश के अनुपालन के लि ## सुरक्षा विचार +<<<<<<< HEAD **क्वेरी गहराई सीमित करना (Query Depth Limiting)**: गहराई से नेस्टेड क्वेरी को रोकें जो प्रदर्शन समस्याओं का कारण बन सकती हैं **क्वेरी जटिलता विश्लेषण (Query Complexity Analysis)**: संसाधन समाप्त होने से रोकने के लिए क्वेरी जटिलता को सीमित करें **फ़ील्ड-लेवल अनुमतियाँ (Field-Level Permissions)**: उपयोगकर्ता भूमिकाओं के आधार पर फ़ील्ड-लेवल एक्सेस नियंत्रण के लिए भविष्य का समर्थन @@ -319,18 +389,50 @@ GraphQL विनिर्देश के अनुपालन के लि रोस्कीमा परिभाषाओं से स्कीमा पीढ़ी ग्राफक्यूएल क्वेरी पार्सिंग और सत्यापन सीक्यूएल क्वेरी पीढ़ी तर्क +======= +**क्वेरी गहराई सीमित करना**: ऐसे गहराई से नेस्टेड क्वेरी को रोकें जो प्रदर्शन समस्याओं का कारण बन सकते हैं +**क्वेरी जटिलता विश्लेषण**: संसाधन समाप्त होने से रोकने के लिए क्वेरी जटिलता को सीमित करें +**फ़ील्ड-स्तरीय अनुमतियाँ**: भविष्य में उपयोगकर्ता भूमिकाओं के आधार पर फ़ील्ड-स्तरीय एक्सेस नियंत्रण के लिए समर्थन +**इनपुट सैनिटाइजेशन**: इंजेक्शन हमलों को रोकने के लिए सभी क्वेरी इनपुट को मान्य और सैनिटाइज करें +**दर सीमित करना**: प्रति उपयोगकर्ता/संग्रहण क्वेरी दर सीमित करना लागू करें + +## प्रदर्शन विचार + +**क्वेरी योजना**: CQL पीढ़ी को अनुकूलित करने के लिए निष्पादन से पहले क्वेरी का विश्लेषण करें +**परिणाम कैशिंग**: फ़ील्ड रिज़ॉल्वर स्तर पर बार-बार एक्सेस किए जाने वाले डेटा को कैश करने पर विचार करें +**कनेक्शन पूलिंग**: कैसेंड्रा के लिए कुशल कनेक्शन पूल बनाए रखें +**बैच ऑपरेशन**: जब भी संभव हो, कई क्वेरी को मिलाएं ताकि विलंबता कम हो सके +**निगरानी**: अनुकूलन के लिए क्वेरी प्रदर्शन मेट्रिक्स को ट्रैक करें + +## परीक्षण रणनीति + +### यूनिट टेस्ट +RowSchema परिभाषाओं से स्कीमा पीढ़ी +GraphQL क्वेरी पार्सिंग और सत्यापन +CQL क्वेरी पीढ़ी लॉजिक +>>>>>>> 82edf2d (New md files from RunPod) फ़ील्ड रिज़ॉल्वर कार्यान्वयन ### अनुबंध परीक्षण पल्सर संदेश अनुबंध अनुपालन +<<<<<<< HEAD ग्राफक्यूएल स्कीमा वैधता +======= +GraphQL स्कीमा वैधता +>>>>>>> 82edf2d (New md files from RunPod) प्रतिक्रिया प्रारूप सत्यापन त्रुटि संरचना सत्यापन ### एकीकरण परीक्षण +<<<<<<< HEAD परीक्षण कैसेंड्रा उदाहरण के खिलाफ एंड-टू-एंड क्वेरी निष्पादन स्कीमा अपडेट हैंडलिंग संबंध संकल्प +======= +परीक्षण कैसेंड्रा इंस्टेंस के खिलाफ एंड-टू-एंड क्वेरी निष्पादन +स्कीमा अपडेट हैंडलिंग +संबंध समाधान +>>>>>>> 82edf2d (New md files from RunPod) पेजिंग और फ़िल्टरिंग त्रुटि परिदृश्य @@ -342,14 +444,22 @@ GraphQL विनिर्देश के अनुपालन के लि ## माइग्रेशन योजना +<<<<<<< HEAD इस नई क्षमता के रूप में माइग्रेशन की आवश्यकता नहीं है। सेवा निम्नलिखित करेगी: 1. कॉन्फ़िगरेशन से मौजूदा स्कीमा पढ़ें 2. स्टोरेज मॉड्यूल द्वारा बनाए गए मौजूदा कैसेंड्रा तालिकाओं से कनेक्ट करें 3. तैनाती पर तुरंत क्वेरी स्वीकार करना शुरू करें +======= +चूंकि यह एक नई क्षमता है, इसलिए माइग्रेशन की आवश्यकता नहीं है। सेवा निम्नलिखित कार्य करेगी: +1. कॉन्फ़िगरेशन से मौजूदा स्कीमा पढ़ें +2. स्टोरेज मॉड्यूल द्वारा बनाए गए मौजूदा कैसेंड्रा तालिकाओं से कनेक्ट करें +3. परिनियोजन पर तुरंत क्वेरी स्वीकार करना शुरू करें +>>>>>>> 82edf2d (New md files from RunPod) ## समयरेखा सप्ताह 1-2: कोर सेवा कार्यान्वयन और स्कीमा पीढ़ी +<<<<<<< HEAD सप्ताह 3: क्वेरी निष्पादन और सीक्यूएल अनुवाद सप्ताह 4: संबंध संकल्प और अनुकूलन सप्ताह 5: परीक्षण और प्रदर्शन ट्यूनिंग @@ -372,12 +482,44 @@ GraphQL विनिर्देश के अनुपालन के लि 5. **कस्टम स्केलर:** क्या डोमेन-विशिष्ट डेटा प्रकारों के लिए कस्टम स्केलर प्रकारों का समर्थन किया जाना चाहिए? +======= +सप्ताह 3: क्वेरी निष्पादन और CQL अनुवाद +सप्ताह 4: संबंध समाधान और अनुकूलन +सप्ताह 5: परीक्षण और प्रदर्शन ट्यूनिंग +सप्ताह 6: गेटवे एकीकरण और दस्तावेज़ीकरण + +## खुले प्रश्न + +1. **स्कीमा विकास**: सेवा को स्कीमा संक्रमण के दौरान क्वेरी को कैसे संभालना चाहिए? + विकल्प: स्कीमा अपडेट के दौरान क्वेरी को कतार में लगाएं + विकल्प: एक साथ कई स्कीमा संस्करणों का समर्थन करें + +2. **कैशिंग रणनीति**: क्या क्वेरी परिणामों को कैश किया जाना चाहिए? + विचार करें: समय-आधारित समाप्ति + विचार करें: घटना-आधारित अमान्यकरण + +3. **संघटन समर्थन**: क्या सेवा को अन्य डेटा स्रोतों के साथ संयोजन के लिए GraphQL संघटन का समर्थन करना चाहिए? + यह संरचित और ग्राफ डेटा में एकीकृत क्वेरी को सक्षम करेगा + +4. **सदस्यता समर्थन**: क्या सेवा को वास्तविक समय अपडेट के लिए GraphQL सदस्यता का समर्थन करना चाहिए? + इसके लिए गेटवे में WebSocket समर्थन की आवश्यकता होगी + +5. **कस्टम स्केलर**: क्या डोमेन-विशिष्ट डेटा प्रकारों के लिए कस्टम स्केलर प्रकारों का समर्थन किया जाना चाहिए? +>>>>>>> 82edf2d (New md files from RunPod) उदाहरण: DateTime, UUID, JSON फ़ील्ड ## संदर्भ +<<<<<<< HEAD स्ट्रक्चर्ड डेटा तकनीकी विनिर्देश: `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 +ट्रस्टग्राफ फ्लो प्रोसेसर दस्तावेज़: आंतरिक दस्तावेज़ +======= +संरचित डेटा तकनीकी विनिर्देश: `docs/tech-specs/structured-data.md` +स्ट्रॉबेरी GraphQL दस्तावेज़ीकरण: https://strawberry.rocks/ +GraphQL विनिर्देश: https://spec.graphql.org/ +Apache Cassandra CQL संदर्भ: https://cassandra.apache.org/doc/stable/cassandra/cql/ +TrustGraph फ्लो प्रोसेसर दस्तावेज़ीकरण: आंतरिक दस्तावेज़ीकरण +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/graphql-query.pt.md b/docs/tech-specs/graphql-query.pt.md index 428a7fb0..9630b95f 100644 --- a/docs/tech-specs/graphql-query.pt.md +++ b/docs/tech-specs/graphql-query.pt.md @@ -14,12 +14,20 @@ O serviço de consulta GraphQL fornecerá uma interface flexível e segura para **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. +<<<<<<< HEAD **Integração de Solicitação/Resposta**: Manter a compatibilidade com o padrão de solicitação/resposta baseado no Pulsar do TrustGraph. +======= +**Integração de Solicitação/Resposta**: Manter a compatibilidade com o padrão de solicitação/resposta baseado em Pulsar do TrustGraph. +>>>>>>> 82edf2d (New md files from RunPod) **Tratamento de Erros**: Fornecer relatórios de erros abrangentes para incompatibilidades de esquema, erros de consulta e problemas de validação de dados. ## Contexto +<<<<<<< HEAD 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. +======= +A implementação de 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, permitindo consultas eficientes dentro de coleções. +>>>>>>> 82edf2d (New md files from RunPod) Limitações atuais que esta especificação aborda: Não há interface de consulta para os dados estruturados armazenados no Cassandra. @@ -43,15 +51,25 @@ O serviço de consulta GraphQL será implementado como um novo processador de fl **Componentes Principais**: +<<<<<<< HEAD 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. +======= +1. **Processador de Serviço de Consulta GraphQL** + Estende a classe base FlowProcessor. + Implementa um padrão de solicitação/resposta semelhante a outros serviços de consulta existentes. +>>>>>>> 82edf2d (New md files from RunPod) 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. +<<<<<<< HEAD Cria tipos de objetos GraphQL com definições de campo adequadas. +======= + Cria tipos de objetos GraphQL com definições de campo apropriadas. +>>>>>>> 82edf2d (New md files from RunPod) Gera o tipo de consulta raiz com resolvedores baseados em coleções. Atualiza o esquema GraphQL quando a configuração é alterada. @@ -138,7 +156,11 @@ Para cada RowSchema na configuração, gerar: ### Modelos de Dados +<<<<<<< HEAD > **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. +======= +> **Observação**: 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. +>>>>>>> 82edf2d (New md files from RunPod) #### Esquema de Requisição (ObjectsQueryRequest) @@ -256,11 +278,19 @@ O serviço otimizará as consultas do Cassandra, através de: **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. +<<<<<<< HEAD **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` +======= +**Sistema de Configuração**: Para monitoramento e atualizações de esquema. + +### Interface de Linha de Comando + +O serviço fornecerá um comando de interface de linha de comando: `kg-query-objects-graphql-cassandra` +>>>>>>> 82edf2d (New md files from RunPod) Argumentos: `--cassandra-host`: Ponto de contato do cluster Cassandra. @@ -283,7 +313,11 @@ Retorna resultados de consulta e erros. ### Integração de Gateway +<<<<<<< HEAD O gateway e o gateway reverso precisarão de endpoints para: +======= +O gateway e o reverse-gateway precisarão de endpoints para: +>>>>>>> 82edf2d (New md files from RunPod) 1. Aceitar consultas GraphQL de clientes. 2. Encaminhar para o serviço de consulta via Pulsar. 3. Retornar respostas aos clientes. @@ -299,23 +333,38 @@ Integração com fluxos de decisão do agente. ## Considerações de Segurança +<<<<<<< HEAD **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. +======= +**Limitação da 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 em 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 consultas por usuário/coleção. +>>>>>>> 82edf2d (New md files from RunPod) ## 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. +<<<<<<< HEAD **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. +======= +**Pool de Conexões**: Manter pools de conexões eficientes para o Cassandra. +**Operações em Lote**: Combinar várias consultas sempre que possível para reduzir a latência. +**Monitoramento**: Acompanhar métricas de desempenho de consultas para otimização. +>>>>>>> 82edf2d (New md files from RunPod) ## Estratégia de Teste ### Testes Unitários +<<<<<<< HEAD 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. @@ -339,17 +388,57 @@ 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. +======= +Geração de esquema a partir de definições RowSchema +Análise e validação de consultas GraphQL +Lógica de geração de consultas CQL +Implementações de resolvedores de campos + +### Testes de Contrato +Conformidade com o contrato de mensagens Pulsar +Validade do esquema GraphQL +Verificação do formato da resposta +Validação da estrutura de erros + +### Testes de Integração +Execução de consulta ponta a ponta contra uma instância de teste do Cassandra +Tratamento de atualizações de esquema +Resolução de relacionamentos +Paginação e filtragem +Cenários de erro + +### Testes de Desempenho +Taxa de transferência de consultas sob carga +Tempo de resposta para diferentes complexidades de consulta +Uso de memória com grandes conjuntos de resultados +Eficiência do pool de conexões +>>>>>>> 82edf2d (New md files from RunPod) ## Plano de Migração Não é necessária migração, pois esta é uma nova funcionalidade. O serviço irá: +<<<<<<< HEAD 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. +======= +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 + +## Cronograma + +Semana 1-2: Implementação do serviço principal e geração de esquema +Semana 3: Execução de consultas e tradução CQL +Semana 4: Resolução de relacionamentos e otimização +Semana 5: Testes e ajuste de desempenho +Semana 6: Integração com o gateway e documentação +>>>>>>> 82edf2d (New md files from RunPod) ## Perguntas Abertas 1. **Evolução do Esquema**: Como o serviço deve lidar com consultas durante as transições de esquema? +<<<<<<< HEAD Opção: Enfileirar consultas durante as atualizações de esquema. Opção: Suportar várias versões de esquema simultaneamente. @@ -373,11 +462,32 @@ Especificação de Dados Estruturados: ⟦CODE_0⟧ Especificação GraphQL: ⟦URL_0⟧ Referência CQL do Apache Cassandra: ⟦URL_0⟧ Documentação do Flow Processor TrustGraph: Documentação interna. +======= + Opção: Enfileirar consultas durante as atualizações de esquema + Opção: Suportar múltiplas versões de esquema simultaneamente + +2. **Estratégia de Cache**: Os resultados das consultas 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 +>>>>>>> 82edf2d (New md files from RunPod) ## Referências Especificação Técnica de Dados Estruturados: `docs/tech-specs/structured-data.md` +<<<<<<< HEAD Documentação do Strawberry GraphQL: https://strawberry.rocks/ +======= +Documentação do GraphQL Strawberry: https://strawberry.rocks/ +>>>>>>> 82edf2d (New md files from RunPod) 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 index 974fd629..f3efaabd 100644 --- a/docs/tech-specs/graphql-query.ru.md +++ b/docs/tech-specs/graphql-query.ru.md @@ -10,16 +10,28 @@ **Динамическая поддержка схемы**: Автоматическая адаптация к изменениям схемы в конфигурации без перезапуска сервиса. **Соответствие стандартам GraphQL**: Предоставление стандартного интерфейса GraphQL, совместимого с существующими инструментами и клиентами GraphQL. +<<<<<<< HEAD **Эффективные запросы к Cassandra**: Преобразование запросов GraphQL в эффективные запросы CQL к Cassandra, учитывающие первичные ключи и индексы. **Разрешение отношений**: Поддержка решателей полей GraphQL для отношений между различными типами объектов. **Типобезопасность**: Обеспечение типобезопасного выполнения запросов и генерации ответов на основе определений схемы. **Масштабируемая производительность**: Эффективная обработка одновременных запросов с использованием правильного пула соединений и оптимизации запросов. **Интеграция запросов/ответов**: Поддержка существующей архитектуры TrustGraph, основанной на шаблоне запросов/ответов с использованием Pulsar. +======= +**Эффективные запросы к Cassandra**: Преобразование запросов GraphQL в эффективные запросы CQL для Cassandra, учитывающие первичные ключи и индексы. +**Разрешение отношений**: Поддержка решателей полей GraphQL для отношений между различными типами объектов. +**Типобезопасность**: Обеспечение типобезопасного выполнения запросов и генерации ответов на основе определений схемы. +**Масштабируемая производительность**: Эффективная обработка одновременных запросов с использованием правильного пула соединений и оптимизации запросов. +**Интеграция запросов/ответов**: Поддержка существующего шаблона запросов/ответов TrustGraph, основанного на Pulsar. +>>>>>>> 82edf2d (New md files from RunPod) **Обработка ошибок**: Предоставление подробной отчетности об ошибках для несоответствий схемы, ошибок запросов и проблем проверки данных. ## Предыстория +<<<<<<< HEAD Реализация хранения структурированных данных (trustgraph-flow/trustgraph/storage/objects/cassandra/) записывает объекты в таблицы Cassandra на основе определений схемы, хранящихся в системе конфигурации TrustGraph. Эти таблицы используют структуру составного первичного ключа с коллекциями и первичными ключами, определенными схемой, что обеспечивает эффективные запросы внутри коллекций. +======= +Реализация хранения структурированных данных (trustgraph-flow/trustgraph/storage/objects/cassandra/) записывает объекты в таблицы Cassandra на основе определений схемы, хранящихся в системе конфигурации TrustGraph. Эти таблицы используют структуру составного первичного ключа с коллекциями и первичными ключами, определенными схемой, что обеспечивает эффективные запросы в пределах коллекций. +>>>>>>> 82edf2d (New md files from RunPod) Текущие ограничения, которые эта спецификация решает: Отсутствие интерфейса запросов для структурированных данных, хранящихся в Cassandra. @@ -39,7 +51,11 @@ Сервис запросов GraphQL будет реализован как новый обработчик потоков TrustGraph, следуя установленным шаблонам: +<<<<<<< HEAD **Местоположение модуля**: `trustgraph-flow/trustgraph/query/objects/cassandra/` +======= +**Расположение модуля**: `trustgraph-flow/trustgraph/query/objects/cassandra/` +>>>>>>> 82edf2d (New md files from RunPod) **Основные компоненты**: @@ -50,6 +66,7 @@ Поддерживает синхронизацию схемы GraphQL с конфигурацией. 2. **Генератор динамической схемы** +<<<<<<< HEAD Преобразует определения RowSchema TrustGraph в типы GraphQL. Создает типы объектов GraphQL с соответствующими определениями полей. Генерирует корневой тип запроса с решателями на основе коллекций. @@ -57,6 +74,15 @@ 3. **Исполнитель запросов** Анализирует входящие запросы GraphQL с использованием библиотеки Strawberry. +======= + Преобразует определения схемы TrustGraph в типы GraphQL. + Создает типы объектов GraphQL с правильными определениями полей. + Генерирует корневой тип Query с решателями на основе коллекций. + Обновляет схему GraphQL при изменении конфигурации. + +3. **Исполнитель запросов** + Разбирает входящие запросы GraphQL с использованием библиотеки Strawberry. +>>>>>>> 82edf2d (New md files from RunPod) Проверяет запросы на соответствие текущей схеме. Выполняет запросы и возвращает структурированные ответы. Обрабатывает ошибки с подробными сообщениями об ошибках. @@ -121,7 +147,11 @@ self.register_config_handler(self.on_schema_config) 3. **Генерация CQL**: Анализ выбранных элементов GraphQL +<<<<<<< HEAD Создание запроса CQL с правильными предложениями WHERE +======= + Построение запроса CQL с правильными предложениями WHERE +>>>>>>> 82edf2d (New md files from RunPod) Включение коллекции в ключ партиции Применение фильтров на основе аргументов GraphQL @@ -251,7 +281,11 @@ class ObjectsQueryResponse(Record): } ``` +<<<<<<< HEAD ### Зависимости реализации +======= +### Реализация и зависимости +>>>>>>> 82edf2d (New md files from RunPod) **Strawberry GraphQL**: Для определения схемы GraphQL и выполнения запросов. **Cassandra Driver**: Для подключения к базе данных (уже используется в модуле хранения). @@ -263,24 +297,37 @@ class ObjectsQueryResponse(Record): Сервис предоставит команду интерфейса командной строки: `kg-query-objects-graphql-cassandra` Аргументы: +<<<<<<< HEAD `--cassandra-host`: Точка контакта кластера Cassandra. +======= +`--cassandra-host`: Контактная точка кластера Cassandra. +>>>>>>> 82edf2d (New md files from RunPod) `--cassandra-username`: Имя пользователя для аутентификации. `--cassandra-password`: Пароль для аутентификации. `--config-type`: Тип конфигурации для схем (по умолчанию: "schema"). Стандартные аргументы FlowProcessor (конфигурация Pulsar и т.д.). +<<<<<<< HEAD ## Интеграция API +======= +## Интеграция с API +>>>>>>> 82edf2d (New md files from RunPod) ### Темы Pulsar **Входная тема**: `objects-graphql-query-request` Схема: ObjectsQueryRequest +<<<<<<< HEAD Получает GraphQL-запросы от шлюзовых сервисов. +======= +Получает запросы GraphQL от шлюзовых сервисов. +>>>>>>> 82edf2d (New md files from RunPod) **Выходная тема**: `objects-graphql-query-response` Схема: ObjectsQueryResponse Возвращает результаты запросов и ошибки. +<<<<<<< HEAD ### Интеграция с шлюзом Шлюз и обратный шлюз потребуют конечных точек для: @@ -288,10 +335,20 @@ class ObjectsQueryResponse(Record): 2. Передачи запросов сервису запросов через Pulsar. 3. Возврата ответов клиентам. 4. Поддержки GraphQL-запросов на интроспекцию. +======= +### Интеграция со шлюзом + +Шлюз и обратный шлюз потребуют конечных точек для: +1. Приема запросов GraphQL от клиентов. +2. Передачи запросов сервису запросов через Pulsar. +3. Возврата ответов клиентам. +4. Поддержки запросов introspection GraphQL. +>>>>>>> 82edf2d (New md files from RunPod) ### Интеграция с инструментом агента Новый класс инструмента агента позволит: +<<<<<<< HEAD Генерировать GraphQL-запросы из естественного языка. Выполнять GraphQL-запросы напрямую. Интерпретировать и форматировать результаты. @@ -308,6 +365,24 @@ class ObjectsQueryResponse(Record): ## Вопросы производительности **Планирование запросов**: Анализирует запросы перед выполнением для оптимизации генерации CQL. +======= +Преобразование естественного языка в запросы GraphQL. +Непосредственное выполнение запросов GraphQL. +Интерпретацию и форматирование результатов. +Интеграцию с потоками принятия решений агентом. + +## Вопросы безопасности + +**Ограничение глубины запросов**: Предотвращение глубоко вложенных запросов, которые могут вызвать проблемы с производительностью. +**Анализ сложности запросов**: Ограничение сложности запросов для предотвращения исчерпания ресурсов. +**Разрешения на уровне полей**: Будущая поддержка контроля доступа на уровне полей на основе ролей пользователей. +**Санитарная обработка входных данных**: Проверка и санитарная обработка всех входных данных запросов для предотвращения атак внедрения. +**Ограничение скорости**: Реализация ограничения скорости запросов на пользователя/коллекцию. + +## Вопросы производительности + +**Планирование запросов**: Анализ запросов перед выполнением для оптимизации генерации CQL. +>>>>>>> 82edf2d (New md files from RunPod) **Кэширование результатов**: Рассмотрите возможность кэширования часто используемых данных на уровне решателя полей. **Пул соединений**: Поддерживайте эффективные пулы соединений к Cassandra. **Пакетные операции**: Объединяйте несколько запросов, когда это возможно, для уменьшения задержки. @@ -315,6 +390,7 @@ class ObjectsQueryResponse(Record): ## Стратегия тестирования +<<<<<<< HEAD ### Unit Tests Генерация схемы на основе определений RowSchema Разбор и проверка запросов GraphQL @@ -339,10 +415,37 @@ class ObjectsQueryResponse(Record): Время отклика для различных уровней сложности запросов Использование памяти при работе с большими наборами результатов Эффективность пула соединений +======= +### Юнит-тесты +Генерация схем из определений RowSchema. +Разбор и проверка запросов GraphQL. +Логика генерации запросов CQL. +Реализации решателей полей. + +### Контрактные тесты +Соответствие контракту сообщений Pulsar. +Достоверность схемы GraphQL. +Проверка формата ответа. +Проверка структуры ошибок. + +### Интеграционные тесты +Комплексное выполнение запросов к тестовой инстанции Cassandra. +Обработка обновления схем. +Разрешение взаимосвязей. +Пагинация и фильтрация. +Сценарии ошибок. + +### Тесты производительности +Пропускная способность запросов при нагрузке. +Время отклика для различных уровней сложности запросов. +Использование памяти с большими наборами результатов. +Эффективность пула соединений. +>>>>>>> 82edf2d (New md files from RunPod) ## План миграции Миграция не требуется, так как это новая функциональность. Сервис будет: +<<<<<<< HEAD 1. Считывать существующие схемы из конфигурации 2. Подключаться к существующим таблицам Cassandra, созданным модулем хранения 3. Начинать принимать запросы сразу после развертывания @@ -373,6 +476,38 @@ class ObjectsQueryResponse(Record): 5. **Пользовательские скаляры**: Следует ли поддерживать пользовательские скалярные типы для специфических типов данных? Примеры: DateTime, UUID, JSON-поля +======= +1. Считывать существующие схемы из конфигурации. +Подключаться к существующим таблицам Cassandra, созданным модулем хранения. +3. Начинать принимать запросы сразу после развертывания. + +## Открытые вопросы + +**Эволюция схемы**: Как сервис должен обрабатывать запросы во время переходов схемы? +Вариант: Помещать запросы в очередь во время обновлений схемы. +Вариант: Поддерживать несколько версий схемы одновременно. + +**Стратегия кэширования**: Следует ли кэшировать результаты запросов? +Рассмотреть: Временное истечение срока действия. +Рассмотреть: Инвалидация на основе событий. + +**Поддержка федерации**: Должен ли сервис поддерживать федерацию GraphQL для объединения с другими источниками данных? + Это позволит выполнять унифицированные запросы к структурированным и графовым данным. + +**Поддержка подписок**: Должен ли сервис поддерживать подписки GraphQL для получения обновлений в режиме реального времени? +Это потребует поддержки WebSocket в шлюзе. + + **Пользовательские скаляры**: Должна ли поддерживаться поддержка пользовательских скалярных типов для специфических типов данных? +Примеры: DateTime, UUID, поля JSON. + + ## Ссылки + +Техническая спецификация структурированных данных: ⟦CODE_0⟧ + Документация Strawberry GraphQL: ⟦URL_0⟧ +Спецификация GraphQL: ⟦URL_0⟧ +Документация Cassandra Driver: ⟦URL_0⟧ + Документация Pulsar: ⟦URL_0⟧ +>>>>>>> 82edf2d (New md files from RunPod) ## Ссылки @@ -380,4 +515,8 @@ class ObjectsQueryResponse(Record): Документация 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 +<<<<<<< HEAD +Документация TrustGraph Flow Processor: Внутренняя документация +======= +Документация процессора потоков TrustGraph: Внутренняя документация +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/graphql-query.sw.md b/docs/tech-specs/graphql-query.sw.md index efaa049a..0194dc79 100644 --- a/docs/tech-specs/graphql-query.sw.md +++ b/docs/tech-specs/graphql-query.sw.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD # Vipimo vya Kiufundi vya Umasilisho wa GraphQL ## Muhtasari @@ -38,11 +39,54 @@ Kusaidia suluhisho la uhusiano kupitia suluhu za uwanja ### Usanifu Huduma ya uwasilisho wa GraphQL itatekelezwa kama mchakato mpya wa TrustGraph kufuatia mbinu zilizopo: +======= +# Vipimo vya Kiufundi vya Ulinganisho wa GraphQL + +## Muhtasari + +Maelezo haya yanaeleza utekelezaji wa kiolesura cha ulinganisho wa GraphQL kwa kuhifadhi data iliyopangwa ya TrustGraph katika Apache Cassandra. Kujenga juu ya uwezo wa data iliyopangwa uliotajwa katika maelezo ya structured-data.md, hati hii inaeleza jinsi ulinganisho wa GraphQL utakavyotekelezwa dhidi ya meza za Cassandra zinazozingatia vitu vilivyochukuliwa na kuingizwa. + +Huduma ya ulinganisho wa GraphQL itatoa kiolesura kinachobadilika na kinacholingana na aina kwa ulinganisho wa data iliyopangwa iliyohifadhiwa katika Cassandra. Itabadilika moja kwa moja kulingana na mabadiliko ya muundo, itaidhinisha ulinganisho tata ikiwa ni pamoja na uhusiano kati ya vitu, na itounganisha kikamilifu na usanifu uliopo wa TrustGraph unaotegemea ujumbe. + +## Lengo + +**Usaidizi wa Muundo Unaobadilika**: Kujifunga kiotomatiki na mabadiliko ya muundo katika usanidi bila kuacha huduma +**Uzingatiaji wa Viwango vya GraphQL**: Kutoa kiolesura cha kawaida cha GraphQL kinacholingana na zana na wateja wa GraphQL iliyopo +**Ulinganisho wa Ufanisi wa Cassandra**: Kubadilisha ulinganisho wa GraphQL kuwa ulinganisho wa CQL wa Cassandra unaofaa 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 ulinganisho salama wa aina na uzalishaji wa majibu kulingana na ufafanuzi wa muundo +**Utendaji Unaoweza Kukidhi Mahitaji**: Kushughulikia ulinganisho wa wakati mmoja kwa ufanisi kwa kutumia udhibiti wa muunganisho na uboreshaji wa ulinganisho +**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 muundo, makosa ya ulinganisho, 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 ufafanuzi wa muundo uliohifadhiwa katika mfumo wa usanidi wa TrustGraph. Meza hizi hutumia muundo wa funguo ya sehemu iliyounganishwa na funguo za msingi zilizobainishwa na muundo, na kuwezesha ulinganisho wa ufanisi ndani ya mikusanyiko. + +Marekebisho ya sasa ambayo maelezo haya yanaashiria: +Hakuna kiolesura cha ulinganisho kwa data iliyopangwa iliyohifadhiwa katika Cassandra +Uwezekano wa kutumia uwezo wa ulinganisho wa GraphQL kwa data iliyopangwa +Usaidizi usio na uhusiano wa ueleuzi kati ya vitu vinavyohusiana +Ukosefu wa lugha ya kawaida ya ulinganisho kwa ufikiaji wa data iliyopangwa + +Huduma ya ulinganisho wa GraphQL itafunga pengo hizi kwa: +Kutoa kiolesura cha kawaida cha GraphQL kwa ulinganisho wa meza za Cassandra +Kujenga schemas za GraphQL moja kwa moja kutoka kwa usanidi wa TrustGraph +Kubadilisha ulinganisho wa GraphQL kwa CQL ya Cassandra kwa ufanisi +Kusaidia suluhisho la uhusiano kupitia suluhu za uwanja + +## Muundo wa Kiufundi + +### Usanifu + +Huduma ya ulinganisho wa GraphQL itatekelezwa kama mchakato mpya wa TrustGraph kufuatia mbinu zilizopo: +>>>>>>> 82edf2d (New md files from RunPod) **Eneo la Moduli**: `trustgraph-flow/trustgraph/query/objects/cassandra/` **Vipengele Muhimu**: +<<<<<<< HEAD 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 @@ -76,6 +120,41 @@ Huduma ya uwasilisho wa GraphQL itatekelezwa kama mchakato mpya wa TrustGraph ku ### Ufuatiliaji wa Mpango wa Usanidi Huduma itasajili mshukiwa wa usanidi ili kupokea sasisho za mpango: +======= +1. **Mchakato wa Huduma ya Ulinganisho wa GraphQL** + Huendelea na darasa la msingi la FlowProcessor + Huendesha mtindo wa ombi/jibu sawa na huduma zingine za ulinganisho + Huangalia usanidi kwa sasisho za muundo + Huendeleza schema ya GraphQL ili kuendana na usanidi + +2. **Mzalishaji wa Muundo wa Njia Moja Moja** + Hubadilisha ufafanuzi wa TrustGraph RowSchema kuwa aina za GraphQL + Huunda aina za vitu vya GraphQL na ufafanuzi sahihi wa uwanja + Huunda aina ya Query ya mizizi na suluhu za msingi za mkusanyiko + Huendeleza schema ya GraphQL wakati usanidi unabadilika + +3. **Mtekelezaji wa Ulinganisho** + Huainisha ulinganisho wa GraphQL unaoingia kwa kutumia maktaba ya Strawberry + Huainisha ulinganisho dhidi ya schema ya sasa + Huendesha ulinganisho na hurudisha majibu yaliyopangwa + Hushughulikia makosa kwa njia nzuri na ujumbe wa makosa wa kina + +4. **Mhubiri wa Ulinganisho wa Cassandra** + Hubadilisha uteuzi wa GraphQL kuwa ulinganisho wa CQL + Huongeza ulinganisho kulingana na fahirisi na funguo za sehemu zinazopatikana + Hushughulikia uchujaji, upangishaji, na utaratibu + Hushughulikia udhibiti wa muunganisho na mzunguko wa kikao + +5. **Suluhu ya Uhusiano** + Huendesha suluhu za uwanja kwa uhusiano wa vitu + Hufanya upakiaji wa kundi ili kuepuka masuala ya N+1 + Huweka suluhu za uhusiano ndani ya muktadha wa ombi + Inasaidia ueleuzi wa uhusiano wa mbele na nyuma + +### Ufuatiliaji wa Muundo wa Usanidi + +Huduma itajisajili kwa mshughuliki wa usanidi ili kupokea sasisho za muundo: +>>>>>>> 82edf2d (New md files from RunPod) ```python self.register_config_handler(self.on_schema_config) @@ -83,7 +162,11 @@ self.register_config_handler(self.on_schema_config) Wakati schemas hubadilika: 1. Changanua maelezo mapya ya schema kutoka kwa usanidi +<<<<<<< HEAD 2. Tengeneza upya aina za GraphQL na suluhu +======= +2. Tengeneza upya aina na suluhu za GraphQL +>>>>>>> 82edf2d (New md files from RunPod) 3. Sasisha schema inayotumika 4. Ondoa kumbukumbu zozote zinazotegemea schema @@ -98,14 +181,23 @@ Kwa kila RowSchema katika usanidi, tengeneza: 2. **Sehemu za Uchunguzi Mkuu**: Uchunguzi wa mkusanyiko (e.g., `customers`, `transactions`) +<<<<<<< HEAD Vigezo vya kuchujwa kulingana na sehemu zilizo na fahirisi Usaidizi wa ukurasa (limit, offset) +======= + Majadiliano ya kuchujwa kulingana na sehemu zilizo na index + Usaidizi wa upangaji (limit, offset) +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD Usaidizi wa uhusiano wa kitu kimoja na orodha +======= + Saidia uhusiano wa kitu kimoja na orodha +>>>>>>> 82edf2d (New md files from RunPod) ### Mtiririko wa Utendaji wa Uchunguzi @@ -120,8 +212,13 @@ Kwa kila RowSchema katika usanidi, tengeneza: Angalia uteuzi wa sehemu na aina za hoja (argument). 3. **Uundaji wa Ombi la CQL**: +<<<<<<< HEAD Jadili uteuzi wa GraphQL. Unda ombi la CQL na vipengele sahihi vya `WHERE`. +======= + Changanua uteuzi wa GraphQL. + Unda ombi la CQL na vigezo sahihi vya `WHERE`. +>>>>>>> 82edf2d (New md files from RunPod) Jumuisha mkusanyiko katika ufunguo wa sehemu (partition key). Tumia vichujio kulingana na hoja za GraphQL. @@ -138,7 +235,11 @@ Kwa kila RowSchema katika usanidi, tengeneza: ### Mifano ya Data +<<<<<<< HEAD > **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`. +======= +> **Kumbuka**: Mpango (schema) uliopo wa `StructuredQueryRequest/Response` unafanya kazi katika `trustgraph-base/trustgraph/schema/services/structured_query.py`. Hata hivyo, hauna sehemu 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`. +>>>>>>> 82edf2d (New md files from RunPod) #### Mpango wa Ombi (ObjectsQueryRequest) @@ -153,9 +254,15 @@ class ObjectsQueryRequest(Record): operation_name = String() # Operation to execute for multi-operation documents ``` +<<<<<<< HEAD **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. +======= +**Mazingatio ya mabadiliko kutoka kwa Ombi la Ulipimaji Uliohifadhiwa (StructuredQueryRequest):** +Imeongezwa sehemu `user` na `collection` ili kuendana na mtindo wa huduma zingine za ulipimaji. +Sehemu hizi ni muhimu kwa kutambua eneo la kuhifadhi (keyspace) na mkusanyiko (collection) wa Cassandra. +>>>>>>> 82edf2d (New md files from RunPod) Vigezo vinaendelea kuwa Map(String()) kwa sasa, lakini inapaswa kusaidia aina zote za JSON. #### Muundo wa Majibu (ObjectsQueryResponse) @@ -180,12 +287,17 @@ class ObjectsQueryResponse(Record): 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 +<<<<<<< HEAD Huhifadhi data kama mnyororo wa JSON ili kuendana, ingawa aina asilia zingekuwa bora +======= +Huendeleza data kama mnyororo wa JSON kwa utangamano, ingawa aina asilia zingekuwa bora +>>>>>>> 82edf2d (New md files from RunPod) ### Uboreshaji wa Umasilisho wa Cassandra Huduma itaboresha masilisho ya Cassandra kwa: +<<<<<<< HEAD 1. **Kufuata Vipengele vya Partition:** Daima jumuisha mkusanyiko katika masilisho Tumia funguo kuu zilizotolewa na mpango kwa ufanisi @@ -197,11 +309,28 @@ Huduma itaboresha masilisho ya Cassandra kwa: Toa onyo wakati masilisho yanaweza kuwa yasiyo na ufanisi 3. **Upakiaji wa Kundi:** +======= +1. **Kutii Mifungo ya Sehemu**: + Daima jumuisha mkusanyiko katika masilisho + Tumia funguo kuu zilizotolewa na muundo kwa ufanisi + Epuka uchanganuzi kamili wa jedwali + +2. **Kutumia Faharasa**: + Tumia faharasa za sekondari kwa kuchujua + Unganisha vichujio vingi wakati inafaa + Toa onyo wakati masilisho yanaweza kuwa yasiyo na ufanisi + +3. **Upakiaji wa Kundi**: +>>>>>>> 82edf2d (New md files from RunPod) Kusanya masilisho ya uhusiano Tekeleza kwa makundi ili kupunguza safari za kurudi na kuja Hifadhi matokeo ndani ya muktadha wa ombi +<<<<<<< HEAD 4. **Usimamizi wa Muunganisho:** +======= +4. **Usimamizi wa Muunganisho**: +>>>>>>> 82edf2d (New md files from RunPod) Dumishe vipindi vya Cassandra vinavyoendelea Tumia mabwalo ya muunganisho Shughulikia muunganisho upya katika hali ya kushindwa @@ -251,11 +380,19 @@ Huduma itaboresha masilisho ya Cassandra kwa: } ``` +<<<<<<< HEAD ### 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. +======= +### Utendaji (Dependencies) + +**Strawberry GraphQL**: Kwa ufafanuzi 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 ufafanuzi wa schema. +>>>>>>> 82edf2d (New md files from RunPod) **Mfumo wa Usanidi**: Kwa ufuatiliaji na sasisho za schema. ### Kiolesura cha Amri (Command-Line Interface) @@ -266,7 +403,11 @@ Majadilisho: `--cassandra-host`: Alama ya kuwasiliana na kundi la Cassandra. `--cassandra-username`: Jina la mtumiaji la uthibitishaji. `--cassandra-password`: Nenosiri la uthibitishaji. +<<<<<<< HEAD `--config-type`: Aina ya usanidi kwa schema (ya kawaida: "schema"). +======= +`--config-type`: Aina ya usanidi kwa schema (kiwango: "schema"). +>>>>>>> 82edf2d (New md files from RunPod) Majadilisho ya kawaida ya FlowProcessor (usanidi wa Pulsar, n.k.). ## Uunganisho wa API @@ -291,7 +432,11 @@ Lango na lango la kinyume (reverse-gateway) itahitaji sehemu za: ### Uunganisho wa Zana ya Wakala +<<<<<<< HEAD Darasa mpya la zana ya wakala itaruhusu: +======= +Darasa jipya la zana ya wakala itaruhusu: +>>>>>>> 82edf2d (New md files from RunPod) Uundaji wa swali la GraphQL kutoka kwa lugha ya asili. Utendaji wa moja kwa moja wa swali la GraphQL. Tafsiri na umbizo wa matokeo. @@ -307,14 +452,21 @@ Uunganisho na mtiririko wa maamuzi wa wakala. ## Masuala ya Utendaji +<<<<<<< HEAD **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. +======= +**Upangaji wa Swali**: Kuchambua maswali kabla ya utekelezaji ili kuongeza ufanisi wa utengenezaji wa CQL. +**Kuhifadhi Matokeo**: Kuzingatia kuhifadhi data inayopatikana mara kwa mara katika kiwango cha suluhu. +**Usimamizi wa Muunganisho**: Kudumisha mikoa bora ya muunganisho kwa Cassandra. +>>>>>>> 82edf2d (New md files from RunPod) **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 +<<<<<<< HEAD ### Majaribio ya Vitengo Uzalishaji wa schema kutoka kwenye maelezo ya RowSchema Uchunguzi na uthibitisho wa swali la GraphQL @@ -335,6 +487,28 @@ Urekebishaji na utafutaji Hali za hitilafu ### Majaribio ya Utendaji +======= +### Majaribsu ya Vitengo +Uzalishaji wa schema kutoka kwa maelezo ya RowSchema +Uchunguzi na uthibitishaji wa swali la GraphQL +Mantiki ya uzalishaji wa swali la CQL +Utendaji wa suluhu za sehemu + +### Majaribsu ya Mkataba +Uzingatiaji wa mkataba wa ujumbe wa Pulsar +Uthibitisho wa utiifu wa schema ya GraphQL +Uthibitisho wa muundo wa jibu +Uthibitisho wa muundo wa hitilafu + +### Majaribsu ya Uunganishaji +Utendaji wa swali kamili dhidi ya mfano wa Cassandra wa majaribio +Usimamizi wa sasisho za schema +Suluhisho la uhusiano +Urekebishaji na utaratibu +Hali za hitilafu + +### Majaribsu ya Utendaji +>>>>>>> 82edf2d (New md files from RunPod) Ufanisi wa swali chini ya mzigo Muda wa jibu kwa utata wa swali mbalimbali Matumizi ya kumbukumbu na matokeo makubwa @@ -342,12 +516,21 @@ Ufanisi wa kikundi cha muunganisho ## Mpango wa Uhamishaji +<<<<<<< HEAD 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 +======= +Hakuna uhamishaji unaohitajika kwani hii ni uwezo mpya. Huduma itafanya: +1. Kusoma schema zilizopo kutoka kwa usanidi +2. Kuunganisha na meza zilizopo za Cassandra zilizoundwa na moduli ya uhifadhi +3. Kuanza kukubali maswali mara tu baada ya kuwekwa + +## Ratiba +>>>>>>> 82edf2d (New md files from RunPod) Wiki 1-2: Utendaji wa msingi wa huduma na uzalishaji wa schema Wiki 3: Utendaji wa swali na tafsiri ya CQL @@ -357,7 +540,11 @@ Wiki 6: Uunganisho wa lango na maandishi ## Maswali ya Wazi +<<<<<<< HEAD 1. **Maendeleo ya Schema**: Huduma inapaswa kushughulikia maswali vipi wakati wa mabadiliko ya schema? +======= +1. **Maendeleo ya Schema**: Huduma inapaswa kushughulikia maswali wakati wa mabadiliko ya schema? +>>>>>>> 82edf2d (New md files from RunPod) Chaguo: Kuweka maswali kwenye folyo wakati wa sasisho za schema Chaguo: Kusaidia matoleo mengi ya schema kwa wakati mmoja @@ -377,7 +564,14 @@ Wiki 6: Uunganisho wa lango na maandishi ## Marejeleo Maelezo ya Kimataifa ya Data Iliyopangwa: `docs/tech-specs/structured-data.md` +<<<<<<< HEAD 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 +Nyaraka za Msimamizi wa Mtiririko wa TrustGraph: Nyaraka za ndani +======= +Nyaraka za GraphQL Strawberry: 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 Mfumo wa Mchakato wa TrustGraph: Nyaraka za ndani +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/graphql-query.tr.md b/docs/tech-specs/graphql-query.tr.md index 393c184f..3e610fee 100644 --- a/docs/tech-specs/graphql-query.tr.md +++ b/docs/tech-specs/graphql-query.tr.md @@ -8,6 +8,7 @@ GraphQL sorgu hizmeti, Cassandra'da depolanan yapılandırılmış verileri sorg ## Hedefler +<<<<<<< HEAD **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. @@ -32,6 +33,32 @@ 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. +======= +**Dinamik Şema Desteği**: Hizmeti yeniden başlatmadan yapılandırmadaki şema değişikliklerine otomatik olarak uyum sağlama +**GraphQL Standartlarına Uygunluk**: Mevcut GraphQL araçları ve istemcileriyle uyumlu, standart bir GraphQL arayüzü sağlama +**Verimli Cassandra Sorguları**: GraphQL sorgularını, bölüm anahtarlarını ve dizinleri dikkate alarak verimli Cassandra CQL sorgularına çevirme +**İlişki Çözümleme**: Farklı nesne türleri arasındaki ilişkiler için GraphQL alan çözümleyicilerini destekleme +**Tür Güvenliği**: Şema tanımlarına dayalı olarak tür güvenli sorgu yürütme ve yanıt oluşturma +**Ölçeklenebilir Performans**: Uygun bağlantı havuzu ve sorgu optimizasyonu ile eşzamanlı sorguları verimli bir şekilde işleme +**İstek/Yanıt Entegrasyonu**: TrustGraph'ın Pulsar tabanlı istek/yanıt kalıbıyla uyumluluğu koruma +**Hata İşleme**: Şema uyumsuzlukları, sorgu hataları ve veri doğrulama sorunları için kapsamlı hata raporlama sağlama + +## 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 bir 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ünün olmaması +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 dilinin olmaması + +GraphQL sorgu hizmeti, bu boşlukları aşağıdaki şekilde dolduracaktır: +Cassandra tablolarını sorgulamak için standart bir GraphQL arayüzü sağlama +TrustGraph yapılandırmasından dinamik olarak GraphQL şemaları oluşturma +GraphQL sorgularını verimli bir şekilde Cassandra CQL'ye çevirme +Alan çözümleyicileri aracılığıyla ilişki çözümlemeyi destekleme +>>>>>>> 82edf2d (New md files from RunPod) ## Teknik Tasarım @@ -44,6 +71,7 @@ GraphQL sorgu hizmeti, yerleşik kalıpları izleyen yeni bir TrustGraph akış **Ana Bileşenler**: 1. **GraphQL Sorgu Hizmeti İşlemcisi** +<<<<<<< HEAD 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. @@ -72,6 +100,36 @@ GraphQL sorgu hizmeti, yerleşik kalıpları izleyen yeni bir TrustGraph akış 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. +======= + 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 +>>>>>>> 82edf2d (New md files from RunPod) ### Yapılandırma Şeması İzleme @@ -84,7 +142,11 @@ 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. +<<<<<<< HEAD 3. Çalıştırılabilir şemayı güncelleyin. +======= +3. Uygulanabilir şemayı güncelleyin. +>>>>>>> 82edf2d (New md files from RunPod) 4. Şemaya bağlı tüm önbellekleri temizleyin. ### GraphQL Şema Oluşturma @@ -129,7 +191,11 @@ Yapılandırmadaki her RowSchema için aşağıdaki öğeleri oluşturun: 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. +<<<<<<< HEAD Yanıtı GraphQL spesifikasyonuna göre biçimlendirin. +======= + Yanıtı GraphQL belirtimine göre biçimlendirin. +>>>>>>> 82edf2d (New md files from RunPod) 5. **Yanıt Teslimi**: Sonuçlarla ObjectsQueryResponse oluşturun. @@ -138,7 +204,11 @@ Yapılandırmadaki her RowSchema için aşağıdaki öğeleri oluşturun: ### Veri Modelleri +<<<<<<< HEAD > **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. +======= +> **Not**: `trustgraph-base/trustgraph/schema/services/structured_query.py`'da mevcut bir StructuredQueryRequest/Response şeması bulunmaktadır. Ancak, bu şema kritik alanları (kullanıcı, koleksiyon) içermemekte ve alt optimal türler kullanmaktadır. Aşağıdaki şemalar, önerilen gelişmeyi temsil etmektedir; bunlar ya mevcut şemaları değiştirmeli ya da yeni ObjectsQueryRequest/Response türleri olarak oluşturulmalıdır. +>>>>>>> 82edf2d (New md files from RunPod) #### İstek Şeması (ObjectsQueryRequest) @@ -154,7 +224,11 @@ class ObjectsQueryRequest(Record): ``` **Mevcut StructuredQueryRequest'ten yapılan değişikliklerin gerekçesi:** +<<<<<<< HEAD Diğer sorgu hizmetlerinin kalıbına uygun olarak `user` ve `collection` alanları eklendi. +======= +Diğer sorgu hizmetlerinin kalıbına uygun olması için `user` ve `collection` alanları eklendi. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -299,11 +373,19 @@ Aracılık karar akışlarıyla entegrasyon ## Güvenlik Hususları +<<<<<<< HEAD **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 +======= +**Sorgu Derinliği Sınırlandırması**: 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ırlandırması**: Kullanıcı/koleksiyon başına sorgu hız sınırlandırması uygulama +>>>>>>> 82edf2d (New md files from RunPod) ## Performans Hususları @@ -352,7 +434,11 @@ Bu yeni bir özellik olduğu için herhangi bir geçiş gerekli değildir. Hizme 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 +<<<<<<< HEAD 5. Hafta: Test etme ve performans ayarlaması +======= +5. Hafta: Test ve performans ayarlaması +>>>>>>> 82edf2d (New md files from RunPod) 6. Hafta: Ağ geçidi entegrasyonu ve dokümantasyon ## Açık Sorular @@ -362,8 +448,13 @@ Bu yeni bir özellik olduğu için herhangi bir geçiş gerekli değildir. Hizme Seçenek: Aynı anda birden fazla şema sürümünü destekleyin 2. **Önbellekleme Stratejisi**: Sorgu sonuçları önbelleğe alınmalı mı? +<<<<<<< HEAD Dikkat edilmesi gerekenler: Zaman tabanlı son kullanma tarihi Dikkat edilmesi gerekenler: Olay tabanlı geçersiz kılma +======= + Dikkate alınması gerekenler: Zaman tabanlı son kullanma tarihi + Dikkate alınması gerekenler: Olay tabanlı geçersiz kılma +>>>>>>> 82edf2d (New md files from RunPod) 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 diff --git a/docs/tech-specs/graphql-query.zh-cn.md b/docs/tech-specs/graphql-query.zh-cn.md index 8e0d8be7..38f5f6b6 100644 --- a/docs/tech-specs/graphql-query.zh-cn.md +++ b/docs/tech-specs/graphql-query.zh-cn.md @@ -2,7 +2,11 @@ ## 概述 +<<<<<<< HEAD 本规范描述了用于 TrustGraph 结构化数据存储在 Apache Cassandra 中的 GraphQL 查询接口的实现。 在结构化数据功能方面,本规范基于结构化数据规范 (structured-data.md),详细说明了如何对包含提取和摄取的结构化对象的 Cassandra 表执行 GraphQL 查询。 +======= +本规范描述了用于 TrustGraph 结构化数据存储在 Apache Cassandra 中的 GraphQL 查询接口的实现。 在结构化数据功能方面,本规范基于结构化数据规范 (structured-data.md),详细说明了如何针对包含提取和导入的结构化对象的 Cassandra 表执行 GraphQL 查询。 +>>>>>>> 82edf2d (New md files from RunPod) GraphQL 查询服务将提供一个灵活、类型安全的接口,用于查询存储在 Cassandra 中的结构化数据。 它将动态适应模式更改,支持包括对象之间的关系在内的复杂查询,并与 TrustGraph 现有的基于消息的架构无缝集成。 @@ -19,16 +23,27 @@ GraphQL 查询服务将提供一个灵活、类型安全的接口,用于查询 ## 背景 +<<<<<<< HEAD 结构化数据存储实现 (trustgraph-flow/trustgraph/storage/objects/cassandra/) 根据存储在 TrustGraph 配置系统中的模式定义,将对象写入 Cassandra 表。 这些表使用复合分区键结构,具有集合和基于模式定义的键,从而可以在集合中实现高效的查询。 +======= +结构化数据存储实现 (trustgraph-flow/trustgraph/storage/objects/cassandra/) 根据存储在 TrustGraph 配置系统中的模式定义,将对象写入 Cassandra 表。 这些表使用复合分区键结构,以及基于集合和模式定义的键,从而实现集合内部的高效查询。 +>>>>>>> 82edf2d (New md files from RunPod) 当前的局限性,本规范旨在解决: 缺少用于存储在 Cassandra 中的结构化数据的查询接口 无法利用 GraphQL 的强大查询功能来处理结构化数据 缺少对相关对象之间关系遍历的支持 +<<<<<<< HEAD 缺少用于结构化数据访问的标准化查询语言 GraphQL 查询服务将通过以下方式弥补这些差距: 提供用于查询 Cassandra 表的标准 GraphQL 接口 +======= +缺少一种用于结构化数据访问的标准查询语言 + +GraphQL 查询服务将通过以下方式弥补这些差距: +为查询 Cassandra 表提供标准的 GraphQL 接口 +>>>>>>> 82edf2d (New md files from RunPod) 从 TrustGraph 配置动态生成 GraphQL 模式 高效地将 GraphQL 查询转换为 Cassandra CQL 通过字段解析器支持关系解析 @@ -68,7 +83,11 @@ GraphQL 查询服务将作为新的 TrustGraph 流处理器实现,遵循既定 管理连接池和会话生命周期 5. **关系解析器** +<<<<<<< HEAD 实现用于对象之间关系的字段解析器 +======= + 实现对象之间关系的字段解析器 +>>>>>>> 82edf2d (New md files from RunPod) 执行批量加载以避免 N+1 查询 在请求上下文中缓存解析的关系 支持正向和反向关系遍历 @@ -97,7 +116,11 @@ self.register_config_handler(self.on_schema_config) 从模式中添加字段描述 2. **根查询字段**: +<<<<<<< HEAD 集合查询(例如,`customers`,`transactions`) +======= + 集合查询(例如,`customers`, `transactions`) +>>>>>>> 82edf2d (New md files from RunPod) 基于索引字段的过滤参数 分页支持(limit, offset) 可排序字段的排序选项 @@ -116,7 +139,11 @@ self.register_config_handler(self.on_schema_config) 2. **查询验证**: 使用 Strawberry 解析 GraphQL 查询 +<<<<<<< HEAD 验证与当前模式 +======= + 验证与当前模式的匹配 +>>>>>>> 82edf2d (New md files from RunPod) 检查字段选择和参数类型 3. **CQL 生成**: @@ -138,7 +165,11 @@ self.register_config_handler(self.on_schema_config) ### 数据模型 +<<<<<<< HEAD > **注意**: `trustgraph-base/trustgraph/schema/services/structured_query.py` 中存在现有的 StructuredQueryRequest/Response 模式。但是,它缺少关键字段(用户、集合),并且使用了次优类型。以下模式代表推荐的演进,应该替换现有的模式,或者创建新的 ObjectsQueryRequest/Response 类型。 +======= +> **注意**: `trustgraph-base/trustgraph/schema/services/structured_query.py` 中已存在一个 StructuredQueryRequest/Response 模式。但是,它缺少关键字段(用户、集合),并且使用了次优类型。以下模式代表推荐的演进,应替换现有模式或创建为新的 ObjectsQueryRequest/Response 类型。 +>>>>>>> 82edf2d (New md files from RunPod) #### 请求模式 (ObjectsQueryRequest) @@ -155,7 +186,11 @@ class ObjectsQueryRequest(Record): **对现有 StructuredQueryRequest 的更改原因:** 添加了 `user` 和 `collection` 字段,以匹配其他查询服务的模式。 +<<<<<<< HEAD 这些字段对于识别 Cassandra 键空间和集合至关重要。 +======= +这些字段对于标识 Cassandra 键空间和集合至关重要。 +>>>>>>> 82edf2d (New md files from RunPod) 变量目前仍然是 Map(String()),但理想情况下应该支持所有 JSON 类型。 #### 响应模式 (ObjectsQueryResponse) @@ -179,7 +214,11 @@ class ObjectsQueryResponse(Record): **对现有 StructuredQueryResponse 更改的理由:** 区分系统错误 (`error`) 和 GraphQL 错误 (`errors`) 使用结构化的 GraphQLError 对象,而不是字符串数组 +<<<<<<< HEAD 添加 `extensions` 字段,以符合 GraphQL 规范 +======= +添加 `extensions` 字段以符合 GraphQL 规范 +>>>>>>> 82edf2d (New md files from RunPod) 为了兼容性,将数据保留为 JSON 字符串,尽管使用原生类型会更好 ### Cassandra 查询优化 @@ -208,7 +247,11 @@ class ObjectsQueryResponse(Record): ### 示例 GraphQL 查询 +<<<<<<< HEAD #### 简单的集合查询 +======= +#### 简单集合查询 +>>>>>>> 82edf2d (New md files from RunPod) ```graphql { customers(status: "active") { @@ -342,7 +385,11 @@ GraphQL 模式有效性 ## 迁移计划 +<<<<<<< HEAD 由于这是一个新功能,因此不需要迁移。该服务将: +======= +由于这是一个新功能,因此不需要迁移。 该服务将: +>>>>>>> 82edf2d (New md files from RunPod) 1. 从配置中读取现有模式 2. 连接到存储模块创建的现有 Cassandra 表 3. 立即在部署后开始接受查询 diff --git a/docs/tech-specs/graphrag-performance-optimization.ar.md b/docs/tech-specs/graphrag-performance-optimization.ar.md index 49abf016..5f24c68f 100644 --- a/docs/tech-specs/graphrag-performance-optimization.ar.md +++ b/docs/tech-specs/graphrag-performance-optimization.ar.md @@ -12,8 +12,13 @@ ## الأهداف **تقليل حجم استعلامات قاعدة البيانات**: تحقيق تقليل بنسبة 50-80٪ في إجمالي استعلامات قاعدة البيانات من خلال التجميع والتخزين المؤقت. +<<<<<<< HEAD **تحسين أوقات الاستجابة**: استهداف سرعة بناء الرسوم البيانية الفرعية بمقدار 3-5 مرات وسرعة حل التسميات بمقدار 2-3 مرات. **تعزيز قابلية التوسع**: دعم رسوم بيانية معرفية أكبر مع إدارة أفضل للذاكرة. +======= +**تحسين أوقات الاستجابة**: استهداف سرعة بناء الرسوم البيانية الفرعية 3-5 مرات أسرع وسرعة حل التسميات 2-3 مرات أسرع. +**تعزيز قابلية التوسع**: دعم رسوم بيانية معرفية أكبر مع إدارة ذاكرة أفضل. +>>>>>>> 82edf2d (New md files from RunPod) **الحفاظ على الدقة**: الحفاظ على وظائف GraphRAG الحالية وجودة النتائج. **تمكين التزامن**: تحسين إمكانيات المعالجة المتوازية للطلبات المتزامنة المتعددة. **تقليل البصمة الذاكرة**: تنفيذ هياكل بيانات وإدارة ذاكرة فعالة. @@ -30,7 +35,11 @@ يقوم بإجراء 3 استعلامات لقاعدة البيانات لكل كيان لكل مستوى عمق. نمط الاستعلام: استعلامات تعتمد على الموضوع، واستعلامات تعتمد على الرابط، واستعلامات تعتمد على الكائن لكل كيان. لا يوجد تجميع: يعالج كل استعلام كيانًا واحدًا فقط في كل مرة. +<<<<<<< HEAD لا يوجد اكتشاف دورات: يمكن إعادة زيارة نفس العقد عدة مرات. +======= +لا يوجد اكتشاف للدورات: يمكن إعادة زيارة نفس العقد عدة مرات. +>>>>>>> 82edf2d (New md files from RunPod) يؤدي التنفيذ المتكرر بدون تدوين إلى تعقيد أسي. التعقيد الزمني: O(entities × max_path_length × triple_limit³) @@ -38,7 +47,11 @@ يعالج كل مكون ثلاثي (موضوع، رابط، كائن) بالتسلسل. قد يؤدي كل استدعاء لـ `maybe_label` إلى استعلام لقاعدة البيانات. لا يوجد تنفيذ متوازي أو تجميع لاستعلامات التسمية. +<<<<<<< HEAD يؤدي إلى ما يصل إلى 3 × استعلامات قاعدة بيانات فردية بحجم الرسم البياني الفرعي. +======= +يؤدي إلى ما يصل إلى 3 × استعلامات قاعدة البيانات الفردية لحجم الرسم البياني الفرعي. +>>>>>>> 82edf2d (New md files from RunPod) **3. استراتيجية تخزين مؤقت بدائية (دالة `maybe_label`، الأسطر 62-77)** ذاكرة تخزين مؤقت بسيطة للقواميس بدون حدود حجم أو TTL. @@ -49,7 +62,11 @@ **4. أنماط استعلام دون المستوى الأمثل** استعلامات تشابه متجه الكيان غير مخزنة مؤقتًا بين الطلبات المتشابهة. لا يوجد تدوين للنتائج لأنماط الاستعلام المتكررة. +<<<<<<< HEAD أنماط استعلام مفقودة للوصول الشائع. +======= +أنماط استعلام مفقودة للتحسين للأنماط الشائعة للوصول. +>>>>>>> 82edf2d (New md files from RunPod) **5. مشكلات حرجة في عمر الكائن (`rag.py:96-102`)** **يتم إعادة إنشاء كائن GraphRag لكل طلب**: يتم إنشاء نسخة جديدة لكل استعلام، مما يفقد جميع فوائد التخزين المؤقت. @@ -65,18 +82,30 @@ **اجتياز الرسم البياني**: entities × max_path_length × 3 × triple_limit استعلامات. **حل التسميات**: subgraph_size × 3 استعلامات تسمية فردية. +<<<<<<< HEAD للإعدادات الافتراضية (50 كيانًا، وطول المسار 2، وقيود على 30 ثلاثية، وحجم الرسم البياني الفرعي 150): **عدد الاستعلامات:** 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9451 استعلامًا لقاعدة البيانات** +======= +للإعدادات الافتراضية (50 كيانًا، وطول المسار 2، وقيود على 30 ثلاثية، وحجم الرسوم البيانية الفرعية 150): +**الاستعلامات الدنيا:** 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9451 استعلامًا لقاعدة البيانات** +>>>>>>> 82edf2d (New md files from RunPod) **وقت الاستجابة:** 15-30 ثانية للرسوم البيانية متوسطة الحجم **استخدام الذاكرة:** نمو غير محدود لذاكرة التخزين المؤقت بمرور الوقت **فعالية التخزين المؤقت:** 0% - يتم إعادة تعيين ذاكرة التخزين المؤقت في كل طلب **تكلفة إنشاء الكائنات:** يتم إنشاء كائنات GraphRag + Query وتدميرها لكل طلب تعالج هذه المواصفات هذه الثغرات من خلال تنفيذ الاستعلامات المجمعة، والتخزين المؤقت الذكي، والمعالجة المتوازية. من خلال تحسين أنماط الاستعلام والوصول إلى البيانات، يمكن لـ TrustGraph: +<<<<<<< HEAD دعم رسوم بيانية معرفية على نطاق المؤسسات تحتوي على ملايين الكيانات توفير أوقات استجابة أقل من ثانية للاستعلامات النموذجية التعامل مع مئات طلبات GraphRAG المتزامنة التوسع بكفاءة مع حجم الرسم البياني وتعقيده +======= +دعم الرسوم البيانية المعرفية على نطاق المؤسسات مع ملايين الكيانات +توفير أوقات استجابة أقل من ثانية للاستعلامات النموذجية +التعامل مع مئات طلبات GraphRAG المتزامنة +التوسع بكفاءة مع حجم وتعقيد الرسم البياني +>>>>>>> 82edf2d (New md files from RunPod) ## التصميم الفني @@ -88,6 +117,7 @@ **جعل GraphRag يعمل لفترة أطول:** نقل مثيل GraphRag إلى مستوى المعالج للاستمرارية عبر الطلبات **الحفاظ على ذاكرة التخزين المؤقت:** الحفاظ على ذاكرة التخزين المؤقت للتسميات، وذاكرة التخزين المؤقت للتضمينات، وذاكرة التخزين المؤقت لنتائج الاستعلام بين الطلبات **تحسين كائن الاستعلام:** إعادة هيكلة الاستعلام كسياق تنفيذ خفيف الوزن، وليس حاوية بيانات +<<<<<<< HEAD **استمرارية الاتصال:** الحفاظ على اتصالات عميل قاعدة البيانات عبر الطلبات الوحدة: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (تم التعديل) @@ -95,6 +125,15 @@ #### 2. **محرك اجتياز الرسم البياني المحسن** استبدال `follow_edges` التكراري ببحث عرضي تكراري تنفيذ معالجة مجمعة للكيانات في كل مستوى من مستويات الاجتياز +======= + **استمرار الاتصال:** الحفاظ على اتصالات عميل قاعدة البيانات عبر الطلبات + + الوحدة: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (تم التعديل) + +#### 2. **محرك اجتياز الرسوم البيانية المحسن** + استبدال `follow_edges` التكراري ببحث عرضي تكراري + تنفيذ معالجة الكيانات المجمعة في كل مستوى من مستويات الاجتياز +>>>>>>> 82edf2d (New md files from RunPod) إضافة اكتشاف الدورات باستخدام تتبع العقد التي تمت زيارتها تضمين الإنهاء المبكر عند الوصول إلى الحدود @@ -109,10 +148,17 @@ الوحدة: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py` #### 4. **طبقة تخزين مؤقت محافظة للتسميات** +<<<<<<< HEAD ذاكرة تخزين مؤقت LRU مع TTL قصيرة للتسميات فقط (5 دقائق) لتحقيق التوازن بين الأداء والاتساق مراقبة مقاييس ذاكرة التخزين المؤقت ونسبة النجاح **لا يوجد تخزين مؤقت للتضمينات:** يتم تخزينها بالفعل لكل استعلام، ولا يوجد فائدة عبر الاستعلامات **لا يوجد تخزين مؤقت لنتائج الاستعلام:** بسبب مخاوف اتساق تغييرات الرسم البياني +======= + ذاكرة تخزين مؤقت LRU مع TTL قصيرة للتسميات فقط (5 دقائق) لتحقيق التوازن بين الأداء مقابل الاتساق + مراقبة مقاييس ذاكرة التخزين المؤقت ونسبة الإصابة + **لا يوجد تخزين مؤقت للتضمينات:** يتم تخزينها بالفعل لكل استعلام، ولا يوجد فائدة عبر الاستعلامات + **لا يوجد تخزين مؤقت لنتائج الاستعلام:** بسبب مخاوف اتساق تعديل الرسم البياني +>>>>>>> 82edf2d (New md files from RunPod) الوحدة: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` @@ -126,7 +172,11 @@ ### نماذج البيانات +<<<<<<< HEAD #### حالة اجتياز الرسم البياني المحسنة +======= +#### حالة اجتياز الرسوم البيانية المحسنة +>>>>>>> 82edf2d (New md files from RunPod) يحتفظ محرك الاجتياز بالحالة لتجنب العمليات المتكررة: @@ -220,7 +270,11 @@ class CacheManager: **فئة Query** - تم إعادة هيكلتها لمعالجة الدفعات: استبدال معالجة الكيانات الفردية بعمليات الدفعات. إضافة مديري سياق غير متزامنين لتنظيف الموارد. +<<<<<<< HEAD تضمين استدعاءات رد الاتصال للتقدم لعمليات طويلة الأمد. +======= +تضمين ردود اتصال التقدم للعمليات التي تستغرق وقتًا طويلاً. +>>>>>>> 82edf2d (New md files from RunPod) ### تفاصيل التنفيذ @@ -327,7 +381,11 @@ class QueryExecutor: **تحسينات عبر الطلبات** ضمن إطارات زمنية للتخزين المؤقت (TTL). **قيود مهمة تتعلق بتناسق التخزين المؤقت:** +<<<<<<< HEAD يؤدي التخزين المؤقت طويل الأجل إلى خطر حدوث بيانات قديمة عندما يتم حذف الكيانات/التصنيفات أو تعديلها في الرسم البياني الأساسي. يوفر التخزين المؤقت الأقل استخدامًا (LRU) مع إطار زمني للتخزين (TTL) توازنًا بين مكاسب الأداء وحداثة البيانات، ولكنه لا يمكنه اكتشاف تغييرات الرسم البياني في الوقت الفعلي. +======= +يؤدي التخزين المؤقت طويل الأجل إلى خطر حدوث بيانات قديمة عندما يتم حذف الكيانات/التصنيفات أو تعديلها في الرسم البياني الأساسي. يوفر التخزين المؤقت الأقل استخدامًا (LRU) مع TTL توازنًا بين مكاسب الأداء وحداثة البيانات، ولكنه لا يمكنه اكتشاف تغييرات الرسم البياني في الوقت الفعلي. +>>>>>>> 82edf2d (New md files from RunPod) #### المرحلة الأولى: تحسين اجتياز الرسم البياني. @@ -490,7 +548,11 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **لوحات مراقبة:** تتبع معدلات نجاح ذاكرة التخزين المؤقت مقابل حوادث عدم الاستقرار. **سياسات ذاكرة تخزين مؤقت قابلة للتكوين:** السماح بضبط لكل توزيع بناءً على تكرار التعديل. +<<<<<<< HEAD **تكوين ذاكرة التخزين المؤقت الموصى به بناءً على معدل تعديل الرسم البياني:** +======= +**تكوين ذاكرة التخزين المؤقت الموصى به حسب معدل تعديل الرسم البياني:** +>>>>>>> 82edf2d (New md files from RunPod) **تعديل مرتفع (>100 تغيير/ساعة):** TTL=60 ثانية، أحجام ذاكرة تخزين مؤقت أصغر. **تعديل متوسط (10-100 تغيير/ساعة):** TTL=300 ثانية (افتراضي). **تعديل منخفض (<10 تغيير/ساعة):** TTL=600 ثانية، أحجام ذاكرة تخزين مؤقت أكبر. @@ -503,7 +565,11 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): تنفيذ حدود تعقيد الاستعلام لمنع هجمات الحرمان من الخدمة. **حماية الموارد:** +<<<<<<< HEAD فرض حدود قصوى لحجم الرسم البياني. +======= +فرض حدود قصوى لحجم الرسم البياني الفرعي. +>>>>>>> 82edf2d (New md files from RunPod) تنفيذ مهلات الاستعلام لمنع استنفاد الموارد. إضافة مراقبة حدود استخدام الذاكرة. @@ -522,19 +588,32 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **تحسينات في وقت الاستجابة:** اجتياز الرسم البياني: 15-20 ثانية → 3-5 ثوانٍ (أسرع بـ 4-5 مرات). +<<<<<<< HEAD حل التسميات: 8-12 ثانية → 2-4 ثوانٍ (أسرع بـ 3 مرات). الاستعلام الإجمالي: 25-35 ثانية → 6-10 ثوانٍ (تحسين بنسبة 3-4 مرات). +======= +حل التسمية: 8-12 ثانية → 2-4 ثوانٍ (أسرع بـ 3 مرات). +الاستعلام الإجمالي: 25-35 ثانية → 6-10 ثوانٍ (تحسين بـ 3-4 مرات). +>>>>>>> 82edf2d (New md files from RunPod) **كفاءة الذاكرة:** تمنع أحجام ذاكرة التخزين المؤقت المحددة تسرب الذاكرة. تقلل الهياكل البيانية الفعالة من البصمة الذاكرة بنسبة ~40٪. +<<<<<<< HEAD جمع القمامة بشكل أفضل من خلال التنظيف المناسب للموارد. +======= +تحسين جمع البيانات المهملة من خلال التنظيف المناسب للموارد. +>>>>>>> 82edf2d (New md files from RunPod) **توقعات واقعية للأداء:** **ذاكرة تخزين مؤقت للتسميات:** تقليل استعلام بنسبة 10-20٪ للرسوم البيانية ذات العلاقات الشائعة. **تحسين التجميع:** تقليل استعلام بنسبة 50-80٪ (التحسين الأساسي). **تحسين عمر الكائن:** إزالة النفقات العامة لإنشاء الطلبات لكل طلب. +<<<<<<< HEAD **تحسين إجمالي:** تحسين وقت الاستجابة بنسبة 3-4 مرات بشكل أساسي من خلال التجميع. +======= +**تحسين إجمالي:** تحسين وقت الاستجابة بـ 3-4 مرات بشكل أساسي من خلال التجميع. +>>>>>>> 82edf2d (New md files from RunPod) **تحسينات قابلية التوسع:** دعم رسوم بيانية معرفية أكبر بـ 3-5 مرات (محدود بمتطلبات تناسق ذاكرة التخزين المؤقت). @@ -547,7 +626,11 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): أوقات تنفيذ الاستعلام حسب نوع العملية. نسب نجاح ذاكرة التخزين المؤقت وفعاليتها. استخدام مجموعة اتصالات قاعدة البيانات. +<<<<<<< HEAD استخدام الذاكرة وتأثير جمع القمامة. +======= +استخدام الذاكرة وتأثير جمع البيانات المهملة. +>>>>>>> 82edf2d (New md files from RunPod) **قياس الأداء:** اختبارات انحدار الأداء الآلية @@ -556,6 +639,7 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ## استراتيجية الاختبار +<<<<<<< HEAD ### اختبارات الوحدة اختبار المكونات الفردية للتنقل والتخزين المؤقت وحل التسميات محاكاة تفاعلات قاعدة البيانات لأغراض اختبار الأداء @@ -564,19 +648,37 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ### اختبار التكامل اختبار شامل لاستعلامات GraphRAG مع التحسينات +======= +### اختبار الوحدة +اختبار المكونات الفردية للتنقل والتخزين المؤقت وحل التسميات +محاكاة تفاعلات قاعدة البيانات لأغراض اختبار الأداء +اختبار إزالة التخزين المؤقت وانتهاء صلاحية TTL +معالجة الأخطاء وسيناريوهات المهلة + +### اختبار التكامل +اختبار شامل لاستعلام GraphRAG مع التحسينات +>>>>>>> 82edf2d (New md files from RunPod) اختبار تفاعلات قاعدة البيانات باستخدام بيانات حقيقية معالجة الطلبات المتزامنة وإدارة الموارد اكتشاف تسرب الذاكرة والتحقق من تنظيف الموارد ### اختبار الأداء اختبارات قياس الأداء مقابل التنفيذ الحالي +<<<<<<< HEAD اختبارات التحميل بأحجام وتعقيدات رسومية مختلفة +======= +اختبارات التحميل بأحجام وتعقيدات رسوم بيانية مختلفة +>>>>>>> 82edf2d (New md files from RunPod) اختبارات الضغط لحدود الذاكرة والاتصالات اختبارات الانحدار لتحسينات الأداء ### اختبار التوافق التحقق من توافق واجهة برمجة تطبيقات GraphRAG الحالية +<<<<<<< HEAD الاختبار مع قواعد بيانات رسومية مختلفة +======= +الاختبار مع قواعد بيانات رسوم بيانية مختلفة +>>>>>>> 82edf2d (New md files from RunPod) التحقق من دقة النتائج مقارنة بالتنفيذ الحالي ## خطة التنفيذ @@ -584,25 +686,39 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ### نهج التنفيذ المباشر نظرًا لأن واجهات برمجة التطبيقات مسموح لها بالتغيير، قم بتنفيذ التحسينات مباشرةً دون تعقيد الترحيل: +<<<<<<< HEAD 1. **استبدال `follow_edges`:** أعد كتابة باستخدام تجول دفعي تكراري +======= +1. **استبدال `follow_edges`:** أعد كتابة باستخدام تجول مجمّع تكراري +>>>>>>> 82edf2d (New md files from RunPod) 2. **تحسين `get_labelgraph`:** قم بتنفيذ حل تسميات متوازي 3. **إضافة GraphRag طويل الأمد:** قم بتعديل المعالج للحفاظ على مثيل دائم 4. **تنفيذ التخزين المؤقت للتسميات:** أضف ذاكرة تخزين مؤقت LRU مع TTL إلى فئة GraphRag ### نطاق التغييرات +<<<<<<< HEAD **فئة الاستعلام:** استبدل ~50 سطرًا في `follow_edges`، وأضف ~30 سطرًا لمعالجة الدفعات +======= +**فئة الاستعلام:** استبدل ~50 سطرًا في `follow_edges`، وأضف ~30 سطرًا لمعالجة الدُفعات +>>>>>>> 82edf2d (New md files from RunPod) **فئة GraphRag:** أضف طبقة التخزين المؤقت (~40 سطرًا) **فئة المعالج:** قم بتعديل لاستخدام مثيل GraphRag دائم (~20 سطرًا) **الإجمالي:** ~140 سطرًا من التغييرات المركزة، معظمها داخل الفئات الحالية ## الجدول الزمني +<<<<<<< HEAD **الأسبوع 1: التنفيذ الأساسي** استبدل `follow_edges` بالتجول الدفعي التكراري +======= +**الأسبوع الأول: التنفيذ الأساسي** +استبدل `follow_edges` بتجول تكراري مجمّع +>>>>>>> 82edf2d (New md files from RunPod) قم بتنفيذ حل تسميات متوازي في `get_labelgraph` أضف مثيل GraphRag طويل الأمد إلى المعالج قم بتنفيذ طبقة التخزين المؤقت للتسميات +<<<<<<< HEAD **الأسبوع 2: الاختبار والتكامل** اختبارات الوحدة لمنطق التجول والتخزين المؤقت الجديد قياس أداء مقابل التنفيذ الحالي @@ -613,6 +729,18 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): نشر التنفيذ المحسن مراقبة تحسينات الأداء ضبط TTL للتخزين المؤقت وأحجام الدفعات بناءً على الاستخدام الفعلي +======= +**الأسبوع الثاني: الاختبار والتكامل** +اختبارات الوحدة لمنطق التجول والتخزين المؤقت الجديد +قياس أداء مقابل التنفيذ الحالي +اختبارات التكامل مع بيانات الرسم البياني الحقيقية +مراجعة التعليمات البرمجية والتحسين + +**الأسبوع الثالث: النشر** +نشر التنفيذ المحسن +مراقبة تحسينات الأداء +ضبط TTL للتخزين المؤقت وأحجام الدُفعات بناءً على الاستخدام الفعلي +>>>>>>> 82edf2d (New md files from RunPod) ## أسئلة مفتوحة @@ -625,5 +753,10 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ## المراجع [التنفيذ الأصلي لـ GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +<<<<<<< HEAD [مبادئ معمارية TrustGraph](architecture-principles.md) [مواصفات إدارة المجموعة](collection-management.md) +======= +[مبادئ بنية TrustGraph](architecture-principles.md) +[مواصفات إدارة المجموعات](collection-management.md) +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/graphrag-performance-optimization.he.md b/docs/tech-specs/graphrag-performance-optimization.he.md index 8e28c46d..0d4aba0d 100644 --- a/docs/tech-specs/graphrag-performance-optimization.he.md +++ b/docs/tech-specs/graphrag-performance-optimization.he.md @@ -2,6 +2,7 @@ ## סקירה כללית +<<<<<<< HEAD מפרט זה מתאר שיפורי ביצועים מקיפים עבור אלגוריתם GraphRAG (Graph Retrieval-Augmented Generation) ב-TrustGraph. יישום הנוכחי סובל מבעיות ביצועים משמעותיות המגבילות את יכולת ההרחבה וזמני התגובה. מפרט זה מתייחס לארבעה תחומים עיקריים של אופטימיזציה: 1. **אופטימיזציה של מעבר גרפים**: ביטול שאילתות מסד נתונים רקורסיביות לא יעילות ויישום חקר גרפים באצווה. @@ -19,6 +20,25 @@ **הפחתת טביעת רגל של זיכרון**: יישום מבני נתונים וניהול זיכרון יעילים. **הוספת יכולת ניטור**: הכללת מדדי ביצועים ויכולות ניטור. **הבטחת אמינות**: הוספת טיפול בשגיאות ומנגנוני תזמון מתאימים. +======= +מפרט זה מתאר שיפורים מקיפים בביצועים עבור אלגוריתם GraphRAG (Graph Retrieval-Augmented Generation) ב-TrustGraph. יישום הנוכחי סובל מבעיות ביצועים משמעותיות המגבילות את יכולת ההרחבה וזמני התגובה. מפרט זה מתייחס לארבעה תחומים עיקריים של אופטימיזציה: + +1. **אופטימיזציה של מעבר גרפים**: ביטול שאילתות מסד נתונים רקורסיביות לא יעילות ויישום חקר גרפים בקבוצות +2. **אופטימיזציה של פתרון תגיות**: החלפת שליפת תגיות רציפה בפעולות מקבילות/בקבוצות +3. **שיפור אסטרטגיית אחסון במטמון**: יישום אחסון במטמון חכם עם פינוי LRU וטעינה מראש +4. **אופטימיזציה של שאילתות**: הוספת שמירת תוצאות במטמון ואחסון במטמון של הטמעות לשיפור זמני התגובה + +## מטרות + +**הפחתת נפח שאילתות מסד הנתונים**: השגת הפחתה של 50-80% בסך כל שאילתות מסד הנתונים באמצעות קיבוץ ואחסון במטמון +**שיפור זמני תגובה**: יעד לבניית תת-גרפים מהירה פי 3-5 ופתרון תגיות מהיר פי 2-3 +**שיפור יכולת הרחבה**: תמיכה בגרפי ידע גדולים יותר עם ניהול זיכרון טוב יותר +**שמירה על דיוק**: שמירה על פונקציונליות ואיכות תוצאות GraphRAG הקיימות +**אפשרות לעיבוד מקבילי**: שיפור יכולות עיבוד מקבילי עבור בקשות מרובות בו-זמנית +**הפחתת טביעת רגל של זיכרון**: יישום מבני נתונים וניהול זיכרון יעילים +**הוספת יכולת ניטור**: הכללת מדדי ביצועים ויכולות ניטור +**הבטחת אמינות**: הוספת טיפול מתאים בשגיאות ומנגנוני תזמון +>>>>>>> 82edf2d (New md files from RunPod) ## רקע @@ -27,6 +47,7 @@ ### בעיות ביצועים נוכחיות **1. מעבר גרפים לא יעיל (פונקציה `follow_edges`, שורות 79-127)** +<<<<<<< HEAD מבצע 3 שאילתות נפרדות למסד הנתונים עבור כל ישות בכל רמת עומק. תבנית שאילתה: שאילתות מבוססות נושא, מבוססות פרידיקט ומבוססות אובייקט עבור כל ישות. ללא אצווה: כל שאילתה מעבדת רק ישות אחת בכל פעם. @@ -57,15 +78,55 @@ **מטמון תגיות מאופס עבור כל בקשה**: חימום מטמון וידע שנצבר אובדים בין בקשות. **תקורה של יצירת לקוח מחדש**: לקוחות מסד נתונים פוטנציאליים מוקמים מחדש עבור כל בקשה. **ללא אופטימיזציה חוצה בקשות**: לא ניתן להפיק תועלת מתבניות שאילתות או שיתוף תוצאות. +======= +מבצע 3 שאילתות נפרדות למסד הנתונים עבור כל ישות בכל רמת עומק +תבנית שאילתה: שאילתות מבוססות נושא, שאילתות מבוססות פרידיקט ושאילתות מבוססות אובייקט עבור כל ישות +ללא קיבוץ: כל שאילתה מעבדת רק ישות אחת בכל פעם +ללא זיהוי מעגלים: ניתן לחזור על צמתים זהים מספר פעמים +יישום רקורסיבי ללא שמירה במטמון מוביל למורכבות אקספוננציאלית +מורכבות זמן: O(entities × max_path_length × triple_limit³) + +**2. פתרון תגיות רציף (פונקציה `get_labelgraph`, שורות 144-171)** +מעבד כל רכיב משולש (נושא, פרידיקט, אובייקט) ברצף +כל קריאה ל-`maybe_label` עלולה לגרום לשאילתה למסד הנתונים +ללא ביצוע מקבילי או קיבוץ של שאילתות תגיות +גורם עד ל-3 × קריאות אישיות למסד הנתונים עבור גודל תת-גרף + +**3. אסטרטגיית אחסון במטמון בסיסית (פונקציה `maybe_label`, שורות 62-77)** +מטמון מילון פשוט ללא מגבלות גודל או TTL +מדיניות פינוי מטמון חסרת גבולות מובילה לצמיחה בלתי מוגבלת של זיכרון +החסרה במטמון גורמת לשאילתות נפרדות למסד הנתונים +ללא טעינה מראש או אחסון במטמון חכם + +**4. תבניות שאילתות לא אופטימליות** +שאילתות דמיון וקטורי לישויות אינן מאוחסנות במטמון בין בקשות דומות +ללא שמירת תוצאות במטמון לתבניות שאילתות חוזרות +חסרים אופטימיזציות שאילתות לתבניות גישה נפוצות + +**5. בעיות קריטיות של חיי אובייקט (`rag.py:96-102`)** +**אובייקט GraphRag נוצר מחדש עבור כל בקשה**: מופע חדש נוצר עבור כל שאילתה, ומאבד את כל יתרונות האחסון במטמון +**אובייקט שאילתה בעל אורך חיים קצר ביותר**: נוצר ונהרס בתוך ביצוע שאילתה יחידה (שורות 201-207) +**מטמון תגיות מאופס עבור כל בקשה**: חימום מטמון וידע שנצבר הולכים לאיבוד בין בקשות +**תקורה של יצירת לקוח**: לקוחות מסד נתונים פוטנציאליים נוצרים מחדש עבור כל בקשה +**ללא אופטימיזציה חוצה בקשות**: לא ניתן להפיק תועלת מתבניות שאילתות או שיתוף תוצאות +>>>>>>> 82edf2d (New md files from RunPod) ### ניתוח השפעת ביצועים תרחיש גרוע ביותר נוכחי עבור שאילתה טיפוסית: +<<<<<<< HEAD **אחזור ישות**: שאילתת דמיון וקטורית אחת. **מעבר גרפים**: entities × max_path_length × 3 × שאילתות triple_limit. **פתרון תגיות**: 3 × שאילתות תגיות אישיות עבור גודל תת-גרף. פלט חוזה (יש לעקוב אחר הפורמט המדויק). עבור פרמטרים ברירת מחדל (50 ישויות, אורך נתיב 2, מגבלת 30 משולשים, גודל תת-גרף 150): +======= +**שליפת ישות**: שאילתה אחת לדמיון וקטורי +**מעבר גרפים**: entities × max_path_length × 3 × שאילתות triple_limit +**פתרון תגיות**: 3 × שאילתות אישיות לגודל תת-גרף +פלט חוזה (יש לעקוב אחר הפורמט המדויק). +עבור פרמטרים ברירת מחדל (50 ישויות, אורך נתיב 2, מגבלת טריפל של 30, גודל תת-גרף של 150): +>>>>>>> 82edf2d (New md files from RunPod) **מספר שאילתות מינימלי**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451 שאילתות למסד נתונים** **זמן תגובה**: 15-30 שניות עבור גרפים בגודל בינוני **שימוש בזיכרון**: צמיחה בלתי מוגבלת של מטמון לאורך זמן @@ -87,22 +148,36 @@ #### 1. **שינוי ארכיטקטורה של משך חיי אובייקטים** **הפוך את GraphRag לבעל חיים ארוך**: העבר את המופע של GraphRag לרמה של המעבד לצורך שמירה בין בקשות **שמור על מטמון**: שמור על מטמון תוויות, מטמון הטבעות ומטמון תוצאות שאילתה בין בקשות +<<<<<<< HEAD **אופטימיזציה של אובייקט שאילתה**: שנה את מבנה אובייקט השאילתה כהקשר ביצוע קל משקל, ולא כמכל נתונים +======= + **אופטימיזציה של אובייקט שאילתה**: שנה את מבנה אובייקט השאילתה כך שיהיה הקשר ביצוע קל משקל, ולא מיכל נתונים +>>>>>>> 82edf2d (New md files from RunPod) **שמירה על חיבורים**: שמור על חיבורי לקוח למסד הנתונים בין בקשות מודול: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (עודכן) #### 2. **מנוע מעבר גרפים מותאם** החלף את `follow_edges` רקורסיבי בחיפוש רוחב-ראשוני איטרטיבי +<<<<<<< HEAD הטמעת עיבוד אצווה של ישויות בכל רמת מעבר הוסף זיהוי מעגלים באמצעות מעקב אחר צמתים מבקרים כלול סיום מוקדם כאשר מגיעים למגבלות +======= + הטמע עיבוד אצווה של ישויות בכל רמת מעבר + הוסף זיהוי מעגלים באמצעות מעקב אחר צמתים שנצפו + כלול סיום מוקדם כאשר מגיעים לגבולות +>>>>>>> 82edf2d (New md files from RunPod) מודול: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` #### 3. **מערכת פתרון תוויות מקבילה** שאילתות תוויות באצווה עבור מספר ישויות בו-זמנית +<<<<<<< HEAD הטמעת דפוסי async/await לגישה מקבילה למסד הנתונים +======= + הטמע דפוסי async/await לגישה מקבילה למסד הנתונים +>>>>>>> 82edf2d (New md files from RunPod) הוסף אחזור מוקדם לדפוסי תוויות נפוצים כלול אסטרטגיות חימום מטמון תוויות @@ -119,7 +194,11 @@ #### 5. **מסגרת אופטימיזציה של שאילתות** ניתוח אופטימיזציה של דפוסי שאילתות והצעות מתאם שאילתות באצווה לגישה למסד הנתונים +<<<<<<< HEAD ניהול בריכת חיבורים וזמן קצוב של שאילתות +======= + ניהול בריכת חיבורים ותזמון תפוגה של שאילתות +>>>>>>> 82edf2d (New md files from RunPod) ניטור ביצועים ואיסוף מדדים מודול: `trustgraph-flow/trustgraph/retrieval/graph_rag/query_optimizer.py` @@ -142,10 +221,17 @@ class TraversalState: ``` גישה זו מאפשרת: +<<<<<<< HEAD זיהוי יעיל של מעגלים באמצעות מעקב אחר ישויות שביקרו הכנת שאילתות באצווה בכל רמת מעבר ניהול מצב חסכוני בזיכרון סיום מוקדם כאשר מגיעים למגבלות גודל +======= +זיהוי יעיל של מעגלים באמצעות מעקב אחר ישויות שכבר נבדקו. +הכנת שאילתות בקבוצות בכל רמת מעבר. +ניהול מצב חסכוני בזיכרון. +סיום מוקדם כאשר מגבלות גודל הושגו. +>>>>>>> 82edf2d (New md files from RunPod) #### מבנה מטמון משופר @@ -467,7 +553,11 @@ class PerformanceMetrics: memory_usage_mb: float ``` +<<<<<<< HEAD **זמן תגובה מקסימלי ומנגנון ניתוב מחדש:** +======= +**מגבלת זמן שאילתה ומנגנון ניתוב:** +>>>>>>> 82edf2d (New md files from RunPod) ```python async def execute_with_timeout(self, query_func, timeout: int = 30): try: @@ -479,14 +569,22 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ## שיקולים בנוגע לעקביות מטמון +<<<<<<< HEAD **פשרות בנוגע לרעננות נתונים:** **מטמון תוויות (TTL של 5 דקות)**: סיכון להצגת תוויות של ישויות שנמחקו/ששמותיהן שונו. **ללא שמירת מטמון של הטמעות (embeddings)**: לא נדרש - הטמעות כבר שמורות מטמון עבור כל שאילתה. **ללא שמירת מטמון של תוצאות**: מונע קבלת תוצאות תת-גרף לא עדכניות מישויות/קשרים שנמחקו. +======= +**פשרות בין רעננות נתונים:** +**מטמון תוויות (TTL של 5 דקות)**: סיכון בהצגת תוויות של ישויות שנמחקו/ששמותיהן שונו. +**ללא שמירת מטמון של הטמעות (embeddings)**: לא נדרש - הטמעות כבר שמורות מטמון עבור כל שאילתה. +**ללא שמירת מטמון של תוצאות**: מונע תוצאות תת-גרף שגויות מישויות/קשרים שנמחקו. +>>>>>>> 82edf2d (New md files from RunPod) **אסטרטגיות הפחתה:** **ערכי TTL שמרניים**: איזון בין שיפורי ביצועים (10-20%) לבין רעננות נתונים. **מנגנוני ביטול מטמון**: שילוב אופציונלי עם אירועי שינוי בגרף. +<<<<<<< HEAD **לוחות מחוונים לניטור**: מעקב אחר אחוזי פגיעה במטמון (cache hit rates) לעומת מקרים של נתונים לא עדכניים. **מדיניות מטמון הניתנות לתצורה**: אפשרות לכוונון פר-פריסה בהתאם לתדירות השינויים. @@ -506,13 +604,38 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): אכיפת מגבלות על גודל תת-גרף מקסימלי. יישום זמני קצבה לשאילתות כדי למנוע מיצוי משאבים. הוספת ניטור מגבלות לשימוש בזיכרון. +======= +**לוחות מחוונים לניטור**: מעקב אחר שיעורי פגיעות במטמון לעומת מקרים של נתונים לא מעודכנים. +**מדיניות מטמון הניתנות לתצורה**: אפשרות לכוונון עדין בהתאם לתדירות השינויים בכל פריסה. + +**תצורת מטמון מומלצת בהתאם לקצב שינויים בגרף:** +**שינויים רבים (>100 שינויים/שעה)**: TTL=60 שניות, גדלי מטמון קטנים יותר. +**שינויים בינוניים (10-100 שינויים/שעה)**: TTL=300 שניות (ברירת מחדל). +**שינויים מעטים (<10 שינויים/שעה)**: TTL=600 שניות, גדלי מטמון גדולים יותר. + +## שיקולים בנושא אבטחה + +**מניעת הזרקת שאילתות:** +אימות כל מזהי ישויות ופרמטרים של שאילתות. +שימוש בשאילתות מפורטות עבור כל אינטראקציות עם מסד הנתונים. +יישום מגבלות מורכבות שאילתות למניעת התקפות מניעת שירות (DoS). + +**הגנה על משאבים:** +אכיפת מגבלות גודל תת-גרף מקסימלי. +יישום זמני קצבי שאילתות למניעת מיצוי משאבים. +הוספת ניטור מגבלות שימוש בזיכרון. +>>>>>>> 82edf2d (New md files from RunPod) **בקרת גישה:** שמירה על בידוד משתמשים ואוספים קיימים. הוספת רישום ביקורת עבור פעולות המשפיעות על הביצועים. יישום הגבלת קצב עבור פעולות יקרות. +<<<<<<< HEAD ## שיקולים בנוגע לביצועים +======= +## שיקולים בנושא ביצועים +>>>>>>> 82edf2d (New md files from RunPod) ### שיפורי ביצועים צפויים @@ -531,8 +654,13 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): איסוף אשפה טוב יותר באמצעות ניקוי משאבים נכון. **ציפיות ריאליות בנוגע לביצועים:** +<<<<<<< HEAD **מטמון תוויות**: הפחתה של 10-20% במספר השאילתות עבור גרפים עם קשרים נפוצים. **אופטימיזציה של קיבוץ**: הפחתה של 50-80% במספר השאילתות (אופטימיזציה עיקרית). +======= +**מטמון תוויות**: הפחתת שאילתות ב-10-20% עבור גרפים עם קשרים נפוצים. +**אופטימיזציה של קיבוץ**: הפחתת שאילתות ב-50-80% (אופטימיזציה עיקרית). +>>>>>>> 82edf2d (New md files from RunPod) **אופטימיזציה של חיי אובייקט**: ביטול תקורה של יצירה מחדש בכל בקשה. **שיפור כולל**: שיפור של פי 3-4 בזמן התגובה בעיקר בזכות קיבוץ. @@ -545,8 +673,13 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **מדדים בזמן אמת:** זמני ביצוע שאילתות לפי סוג פעולה. +<<<<<<< HEAD אחוזי פגיעה במטמון ויעילות. שימוש בבריכת חיבורים למסד הנתונים. +======= +שיעורי פגיעה ויעילות של מטמון. +שימוש בבריכת חיבורי מסד נתונים. +>>>>>>> 82edf2d (New md files from RunPod) שימוש בזיכרון והשפעת איסוף אשפה. **בדיקות ביצועים:** @@ -557,16 +690,26 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ## אסטרטגיית בדיקות ### בדיקות יחידה +<<<<<<< HEAD בדיקת רכיבים בודדים עבור מעבר, אחסון במטמון ופתרון תגיות הדמיית אינטראקציות עם מסד נתונים לצורך בדיקות ביצועים בדיקת פינוי מטמון ותפוגה של זמן תפוגה (TTL) +======= +בדיקת רכיבים בודדים עבור מעבר, אחסון במטמון ופתרון תוויות +הדמיית אינטראקציות עם מסד נתונים לצורך בדיקות ביצועים +בדיקת פינוי מטמון ותפוגת זמן (TTL) +>>>>>>> 82edf2d (New md files from RunPod) בדיקת טיפול בשגיאות ותסריטי תזמון ### בדיקות אינטגרציה בדיקות מקצה לקצה של שאילתות GraphRAG עם אופטימיזציות בדיקת אינטראקציות עם מסד נתונים עם נתונים אמיתיים טיפול בבקשות מקבילות וניהול משאבים +<<<<<<< HEAD זיהוי דליפות זיכרון ואימות ניקוי משאבים +======= +זיהוי דליפות זיכרון ובדיקת ניקוי משאבים +>>>>>>> 82edf2d (New md files from RunPod) ### בדיקות ביצועים בדיקות ביצועים מול המימוש הנוכחי @@ -582,6 +725,7 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ## תוכנית יישום ### גישת יישום ישירה +<<<<<<< HEAD מכיוון שמותר לשנות ממשקי API, ליישם אופטימיזציות ישירות ללא מורכבות של העברה: 1. **החלפת `follow_edges`:** כתיבה מחדש עם מעבר אצווה איטרטיבי @@ -593,15 +737,34 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **מחלקה של שאילתות:** החלפת כ-50 שורות ב-`follow_edges`, הוספת כ-30 שורות לטיפול באצווה **מחלקה של GraphRag:** הוספת שכבת אחסון במטמון (כ-40 שורות) **מחלקה של מעבד:** שינוי לשימוש במופע קבוע של GraphRag (כ-20 שורות) +======= +מכיוון שמותר לשנות ממשקי API, ליישם אופטימיזציות ישירות ללא מורכבות של מעבר: + +1. **החלפת `follow_edges`:** כתיבה מחדש עם מעבר אצווה איטרטיבי +2. **אופטימיזציה של `get_labelgraph`:** יישום פתרון תוויות מקבילי +3. **הוספת GraphRag ארוך טווח:** שינוי של Processor לשמירה על מופע קבוע +4. **יישום אחסון תוויות במטמון:** הוספת מטמון LRU עם TTL למחלקת GraphRag + +### היקף השינויים +**מחלקת שאילתה:** החלפת כ-50 שורות ב-`follow_edges`, הוספת כ-30 שורות לטיפול באצווה +**מחלקת GraphRag:** הוספת שכבת אחסון במטמון (כ-40 שורות) +**מחלקת Processor:** שינוי לשימוש במופע קבוע של GraphRag (כ-20 שורות) +>>>>>>> 82edf2d (New md files from RunPod) **סה"כ:** כ-140 שורות של שינויים ממוקדים, בעיקר בתוך מחלקות קיימות ## ציר זמן **שבוע 1: יישום ליבה** החלפת `follow_edges` עם מעבר אצווה איטרטיבי +<<<<<<< HEAD יישום פתרון תגיות מקבילי ב-`get_labelgraph` הוספת מופע GraphRag ארוך טווח למעבד יישום שכבת אחסון במטמון של תגיות +======= +יישום פתרון תוויות מקבילי ב-`get_labelgraph` +הוספת מופע GraphRag ארוך טווח ל-Processor +יישום שכבת אחסון במטמון +>>>>>>> 82edf2d (New md files from RunPod) **שבוע 2: בדיקות ושילוב** בדיקות יחידה ללוגיקה חדשה של מעבר ואחסון במטמון @@ -617,10 +780,17 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ## שאלות פתוחות **בריכת חיבורים למסד נתונים:** האם עלינו ליישם בריכת חיבורים מותאמת אישית או להסתמך על בריכת חיבורים קיימת של לקוח מסד נתונים? +<<<<<<< HEAD **שימור מטמון:** האם מטמון התגיות וההטבעות צריך להתמיד בין הפעלות מחדש של השירות? **אחסון במטמון מבוזר:** עבור פריסות מרובות מופעים, האם עלינו ליישם אחסון במטמון מבוזר עם Redis/Memcached? **פורמט תוצאות שאילתה:** האם עלינו לייעל את הייצוג הפנימי של משולש לטובת יעילות זיכרון טובה יותר? **שילוב ניטור:** אילו מדדים יש לחשוף למערכות ניטור קיימות (Prometheus, וכו')? +======= +**שימור מטמון:** האם מטמון תוויות ו-embedding צריך להתמיד בין הפעלות מחדש של השירות? +**אחסון מבוזר:** עבור פריסות מרובות מופעים, האם עלינו ליישם אחסון מבוזר עם Redis/Memcached? +**פורמט תוצאות שאילתה:** האם עלינו לייעל את הייצוג הפנימי של משולש לטובת יעילות זיכרון טובה יותר? +**שילוב ניטור:** אילו מדדים צריכים להיות חשופים למערכות ניטור קיימות (Prometheus, וכו')? +>>>>>>> 82edf2d (New md files from RunPod) ## הפניות diff --git a/docs/tech-specs/graphrag-performance-optimization.hi.md b/docs/tech-specs/graphrag-performance-optimization.hi.md index 9830dd9b..b104900e 100644 --- a/docs/tech-specs/graphrag-performance-optimization.hi.md +++ b/docs/tech-specs/graphrag-performance-optimization.hi.md @@ -11,12 +11,21 @@ ## लक्ष्य +<<<<<<< HEAD **डेटाबेस क्वेरी की मात्रा को कम करें**: बैचिंग और कैशिंग के माध्यम से कुल डेटाबेस प्रश्नों में 50-80% की कमी प्राप्त करें। **प्रतिक्रिया समय में सुधार**: सबग्राफ निर्माण और लेबल रिज़ॉल्यूशन में 3-5 गुना तेजी और 2-3 गुना तेजी लाने का लक्ष्य रखें। **स्केलेबिलिटी में वृद्धि**: बेहतर मेमोरी प्रबंधन के साथ बड़े नॉलेज ग्राफ का समर्थन करें। **सटीकता बनाए रखें**: मौजूदा ग्राफआरएजी कार्यक्षमता और परिणाम गुणवत्ता को संरक्षित करें। **समवर्तीता सक्षम करें**: एकाधिक समवर्ती अनुरोधों के लिए समानांतर प्रसंस्करण क्षमताओं में सुधार करें। **मेमोरी पदचिह्न को कम करें**: कुशल डेटा संरचनाओं और मेमोरी प्रबंधन को लागू करें। +======= +**डेटाबेस क्वेरी की मात्रा कम करें**: बैचिंग और कैशिंग के माध्यम से कुल डेटाबेस प्रश्नों में 50-80% की कमी प्राप्त करें। +**प्रतिक्रिया समय में सुधार**: सबग्राफ निर्माण और लेबल रिज़ॉल्यूशन में 3-5 गुना तेजी और 2-3 गुना तेजी लाने का लक्ष्य रखें। +**स्केलेबिलिटी बढ़ाएं**: बेहतर मेमोरी प्रबंधन के साथ बड़े नॉलेज ग्राफ का समर्थन करें। +**सटीकता बनाए रखें**: मौजूदा ग्राफआरएजी कार्यक्षमता और परिणाम गुणवत्ता को संरक्षित करें। +**समवर्तीता सक्षम करें**: एकाधिक समवर्ती अनुरोधों के लिए समानांतर प्रसंस्करण क्षमताओं में सुधार करें। +**मेमोरी पदचिह्न कम करें**: कुशल डेटा संरचनाओं और मेमोरी प्रबंधन को लागू करें। +>>>>>>> 82edf2d (New md files from RunPod) **अवलोकनशीलता जोड़ें**: प्रदर्शन मेट्रिक्स और निगरानी क्षमताओं को शामिल करें। **विश्वसनीयता सुनिश्चित करें**: उचित त्रुटि हैंडलिंग और टाइमआउट तंत्र जोड़ें। @@ -27,9 +36,15 @@ ### वर्तमान प्रदर्शन समस्याएं **1. अक्षम ग्राफ ट्रैवर्सल (`follow_edges` फ़ंक्शन, लाइनें 79-127)** +<<<<<<< HEAD प्रत्येक इकाई प्रति गहराई स्तर के लिए 3 अलग-अलग डेटाबेस क्वेरी करता है। क्वेरी पैटर्न: प्रत्येक इकाई के लिए विषय-आधारित, विधेय-आधारित और ऑब्जेक्ट-आधारित क्वेरी। कोई बैचिंग नहीं: प्रत्येक क्वेरी एक समय में केवल एक इकाई को संसाधित करती है। +======= +प्रति इकाई प्रति गहराई स्तर के लिए 3 अलग-अलग डेटाबेस क्वेरी करता है। +क्वेरी पैटर्न: प्रत्येक इकाई के लिए विषय-आधारित, विधेय-आधारित और ऑब्जेक्ट-आधारित क्वेरी। +कोई बैचिंग नहीं: प्रत्येक क्वेरी केवल एक इकाई को संसाधित करती है। +>>>>>>> 82edf2d (New md files from RunPod) कोई चक्र का पता नहीं: समान नोड्स को कई बार फिर से देख सकता है। मेमोइज़ेशन के बिना पुनरावर्ती कार्यान्वयन घातीय जटिलता की ओर ले जाता है। समय जटिलता: O(entities × max_path_length × triple_limit³) @@ -42,7 +57,11 @@ **3. आदिम कैशिंग रणनीति (`maybe_label` फ़ंक्शन, लाइनें 62-77)** आकार सीमा या टीटीएल के बिना एक साधारण शब्दकोश कैश। +<<<<<<< HEAD कोई कैश निष्कासन नीति नहीं जिसके परिणामस्वरूप असीमित मेमोरी वृद्धि होती है। +======= +कोई कैश निष्कासन नीति असीमित मेमोरी वृद्धि की ओर ले जाती है। +>>>>>>> 82edf2d (New md files from RunPod) कैश मिस व्यक्तिगत डेटाबेस क्वेरी को ट्रिगर करते हैं। कोई प्रीफ़ेचिंग या बुद्धिमान कैश वार्मिंग नहीं। @@ -53,7 +72,11 @@ **5. महत्वपूर्ण ऑब्जेक्ट लाइफटाइम मुद्दे (`rag.py:96-102`)** **प्रत्येक अनुरोध के लिए GraphRag ऑब्जेक्ट फिर से बनाया गया**: प्रत्येक क्वेरी के लिए एक नया उदाहरण बनाया जाता है, जिससे सभी कैश लाभ खो जाते हैं। +<<<<<<< HEAD **क्वेरी ऑब्जेक्ट बहुत कम समय तक रहता है**: एकल क्वेरी निष्पादन के भीतर बनाया और नष्ट किया जाता है (लाइनें 201-207)। +======= +**क्वेरी ऑब्जेक्ट बहुत कम समय तक जीवित रहता है**: एक ही क्वेरी निष्पादन के भीतर बनाया और नष्ट किया जाता है (लाइनें 201-207)। +>>>>>>> 82edf2d (New md files from RunPod) **प्रत्येक अनुरोध के लिए लेबल कैश रीसेट**: कैश वार्मिंग और संचित ज्ञान के बीच खो जाता है। **क्लाइंट पुन: निर्माण ओवरहेड**: प्रत्येक अनुरोध के लिए डेटाबेस क्लाइंट संभावित रूप से फिर से स्थापित होते हैं। **क्रॉस-रिक्वेस्ट अनुकूलन नहीं**: क्वेरी पैटर्न या परिणाम साझाकरण से लाभ नहीं उठाया जा सकता है। @@ -61,6 +84,7 @@ ### प्रदर्शन प्रभाव विश्लेषण एक विशिष्ट क्वेरी के लिए वर्तमान सबसे खराब स्थिति परिदृश्य: +<<<<<<< HEAD **इकाई पुनर्प्राप्ति**: 1 वेक्टर समानता क्वेरी **ग्राफ ट्रैवर्सल**: entities × max_path_length × 3 × triple_limit क्वेरी **लेबल रिज़ॉल्यूशन**: subgraph_size × 3 व्यक्तिगत लेबल क्वेरी @@ -77,17 +101,44 @@ विशिष्ट क्वेरीज़ के लिए उप-सेकंड प्रतिक्रिया समय प्रदान करें सैकड़ों समवर्ती GraphRAG अनुरोधों को संभालें ग्राफ के आकार और जटिलता के साथ कुशलतापूर्वक स्केल करें +======= +**इकाई पुनर्प्राप्ति**: 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% - प्रत्येक अनुरोध पर कैश रीसेट हो जाते हैं +**ऑब्जेक्ट निर्माण ओवरहेड**: प्रति अनुरोध बनाए गए/विनाश किए गए ग्राफराग + क्वेरी ऑब्जेक्ट + +यह विनिर्देश इन कमियों को बैच क्वेरी, बुद्धिमान कैशिंग और समानांतर प्रसंस्करण को लागू करके संबोधित करता है। क्वेरी पैटर्न और डेटा एक्सेस को अनुकूलित करके, ट्रस्टग्राफ निम्न कार्य कर सकता है: +लाखों एंटिटीज वाले एंटरप्राइज-स्केल नॉलेज ग्राफ का समर्थन करें +विशिष्ट क्वेरीज़ के लिए उप-सेकंड प्रतिक्रिया समय प्रदान करें +सैकड़ों समवर्ती ग्राफराग अनुरोधों को संभालें +ग्राफ आकार और जटिलता के साथ कुशलतापूर्वक स्केल करें +>>>>>>> 82edf2d (New md files from RunPod) ## तकनीकी डिज़ाइन ### आर्किटेक्चर +<<<<<<< HEAD GraphRAG प्रदर्शन अनुकूलन के लिए निम्नलिखित तकनीकी घटकों की आवश्यकता होती है: #### 1. **ऑब्जेक्ट लाइफटाइम आर्किटेक्चरल रीफैक्टर** **GraphRag को लंबे समय तक चलने वाला बनाएं**: GraphRag इंस्टेंस को प्रोसेसर स्तर पर ले जाएं ताकि यह अनुरोधों के बीच बना रहे **कैश बनाए रखें**: लेबल कैश, एम्बेडिंग कैश और क्वेरी परिणाम कैश को अनुरोधों के बीच बनाए रखें **क्वेरी ऑब्जेक्ट को अनुकूलित करें**: Query को एक हल्के निष्पादन संदर्भ के रूप में रीफैक्टर करें, डेटा कंटेनर के रूप में नहीं +======= +ग्राफराग प्रदर्शन अनुकूलन के लिए निम्नलिखित तकनीकी घटकों की आवश्यकता होती है: + +#### 1. **ऑब्जेक्ट लाइफटाइम आर्किटेक्चरल रीफैक्टर** + **ग्राफराग को लंबे समय तक चलने वाला बनाएं**: ग्राफराग इंस्टेंस को प्रोसेसर स्तर पर ले जाएं ताकि यह अनुरोधों के बीच बना रहे + **कैश बनाए रखें**: लेबल कैश, एम्बेडिंग कैश और क्वेरी परिणाम कैश को अनुरोधों के बीच बनाए रखें + **क्वेरी ऑब्जेक्ट को अनुकूलित करें**: क्वेरी को एक हल्के निष्पादन संदर्भ के रूप में रीफैक्टर करें, डेटा कंटेनर के रूप में नहीं +>>>>>>> 82edf2d (New md files from RunPod) **कनेक्शन दृढ़ता**: डेटाबेस क्लाइंट कनेक्शन को अनुरोधों के बीच बनाए रखें मॉड्यूल: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (संशोधित) @@ -101,7 +152,11 @@ GraphRAG प्रदर्शन अनुकूलन के लिए नि मॉड्यूल: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` #### 3. **समानांतर लेबल रिज़ॉल्यूशन सिस्टम** +<<<<<<< HEAD एक साथ कई एंटिटीज के लिए लेबल क्वेरीज़ को बैच करें +======= + एक साथ कई एंटिटीज के लिए बैच लेबल क्वेरी +>>>>>>> 82edf2d (New md files from RunPod) समवर्ती डेटाबेस एक्सेस के लिए एसिंक्रोनस/अवेट पैटर्न लागू करें सामान्य लेबल पैटर्न के लिए बुद्धिमान प्रीफ़ेटिंग जोड़ें लेबल कैश वार्मिंग रणनीतियों शामिल करें @@ -109,10 +164,17 @@ GraphRAG प्रदर्शन अनुकूलन के लिए नि मॉड्यूल: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py` #### 4. **रूढ़िवादी लेबल कैशिंग लेयर** +<<<<<<< HEAD प्रदर्शन बनाम स्थिरता को संतुलित करने के लिए केवल लेबल के लिए लघु TTL के साथ LRU कैश (5 मिनट) कैश मेट्रिक्स और हिट अनुपात निगरानी **कोई एम्बेडिंग कैशिंग नहीं**: पहले से ही प्रति-क्वेरी कैश किया गया है, कोई क्रॉस-क्वेरी लाभ नहीं **कोई क्वेरी परिणाम कैशिंग नहीं**: ग्राफ परिवर्तन स्थिरता संबंधी चिंताओं के कारण +======= + केवल लेबल के लिए लघु TTL के साथ LRU कैश (5 मिनट) प्रदर्शन बनाम स्थिरता को संतुलित करने के लिए + कैश मेट्रिक्स और हिट अनुपात निगरानी + **कोई एम्बेडिंग कैशिंग नहीं**: पहले से ही प्रति-क्वेरी कैश किया गया है, कोई क्रॉस-क्वेरी लाभ नहीं + **कोई क्वेरी परिणाम कैशिंग नहीं**: ग्राफ उत्परिवर्तन स्थिरता संबंधी चिंताओं के कारण +>>>>>>> 82edf2d (New md files from RunPod) मॉड्यूल: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` @@ -141,7 +203,11 @@ class TraversalState: query_batch: List[TripleQuery] ``` +<<<<<<< HEAD यह दृष्टिकोण निम्नलिखित सुविधाएँ प्रदान करता है: +======= +यह दृष्टिकोण निम्नलिखित कार्य करने की अनुमति देता है: +>>>>>>> 82edf2d (New md files from RunPod) विज़िट किए गए एंटिटी को ट्रैक करके कुशल चक्र का पता लगाना प्रत्येक ट्रैवर्सल स्तर पर बैच में क्वेरी तैयार करना मेमोरी-कुशल स्थिति प्रबंधन @@ -219,12 +285,20 @@ class CacheManager: **क्वेरी क्लास** - बैच प्रोसेसिंग के लिए पुनर्गठित: व्यक्तिगत इकाई प्रसंस्करण को बैच ऑपरेशनों से बदलें +<<<<<<< HEAD संसाधन सफाई के लिए एसिंक्रोनस कॉन्टेक्स्ट मैनेजर जोड़ें +======= +संसाधन सफाई के लिए एसिंक्रोनस संदर्भ प्रबंधक जोड़ें +>>>>>>> 82edf2d (New md files from RunPod) लंबे समय तक चलने वाले ऑपरेशनों के लिए प्रगति कॉलबैक शामिल करें ### कार्यान्वयन विवरण +<<<<<<< HEAD #### चरण 0: महत्वपूर्ण आर्किटेक्चरल लाइफटाइम रिफैक्टर +======= +#### चरण 0: महत्वपूर्ण वास्तुशिल्प जीवनचक्र पुनर्गठन +>>>>>>> 82edf2d (New md files from RunPod) **वर्तमान समस्याग्रस्त कार्यान्वयन:** ```python @@ -327,7 +401,11 @@ class QueryExecutor: **कैश टीटीएल विंडो के भीतर क्रॉस-अनुरोध अनुकूलन** **महत्वपूर्ण कैश स्थिरता सीमा:** +<<<<<<< HEAD दीर्घकालिक कैशिंग से अप्रचलन का जोखिम होता है जब अंतर्निहित ग्राफ में एंटिटीज/लेबल हटा दिए जाते हैं या संशोधित किए जाते हैं। एलआरयू कैश जिसमें टीटीएल है, प्रदर्शन लाभ और डेटा ताज़गी के बीच संतुलन प्रदान करता है, लेकिन यह वास्तविक समय में ग्राफ परिवर्तनों का पता नहीं लगा सकता है। +======= +दीर्घकालिक कैशिंग से पुरानी जानकारी का जोखिम होता है जब अंतर्निहित ग्राफ में एंटिटीज/लेबल हटा दिए जाते हैं या संशोधित किए जाते हैं। एलआरयू कैश, टीटीएल के साथ, प्रदर्शन लाभ और डेटा ताज़गी के बीच एक संतुलन प्रदान करता है, लेकिन यह वास्तविक समय में ग्राफ परिवर्तनों का पता नहीं लगा सकता है। +>>>>>>> 82edf2d (New md files from RunPod) #### चरण 1: ग्राफ ट्रैवर्सल अनुकूलन @@ -480,9 +558,15 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ## कैश कंसिस्टेंसी पर विचार **डेटा स्टेलनेस ट्रेड-ऑफ:** +<<<<<<< HEAD **लेबल कैश (5 मिनट TTL)**: डिलीट किए गए/रीनेम किए गए एंटिटी लेबल को प्रदर्शित करने का जोखिम। **कोई एम्बेडिंग कैशिंग नहीं:** आवश्यक नहीं है - एम्बेडिंग पहले से ही प्रति-क्वेरी कैश किए गए हैं। **कोई परिणाम कैशिंग नहीं:** डिलीट किए गए एंटिटीज/रिलेशनशिप से पुराने सबग्राफ परिणामों को रोकता है। +======= +**लेबल कैश (5 मिनट TTL)**: हटाए गए/पुनर्नाम किए गए एंटिटी लेबल को प्रदर्शित करने का जोखिम। +**कोई एम्बेडिंग कैशिंग नहीं:** आवश्यक नहीं है - एम्बेडिंग पहले से ही प्रति-क्वेरी कैश किए गए हैं। +**कोई परिणाम कैशिंग नहीं:** हटाए गए एंटिटीज/रिलेशनशिप से पुराने सबग्राफ परिणामों को रोकता है। +>>>>>>> 82edf2d (New md files from RunPod) **शमन रणनीतियाँ:** **रूढ़िवादी TTL मान:** प्रदर्शन लाभ (10-20%) को डेटा की ताजगी के साथ संतुलित करें। @@ -490,7 +574,11 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **निगरानी डैशबोर्ड:** कैश हिट दरों बनाम स्टेलनेस घटनाओं को ट्रैक करें। **कॉन्फ़िगर करने योग्य कैश नीतियां:** उत्परिवर्तन आवृत्ति के आधार पर प्रति-तैनाती ट्यूनिंग की अनुमति दें। +<<<<<<< HEAD **ग्राफ उत्परिवर्तन दर द्वारा अनुशंसित कैश कॉन्फ़िगरेशन:** +======= +**अनुशंसित कैश कॉन्फ़िगरेशन ग्राफ उत्परिवर्तन दर द्वारा:** +>>>>>>> 82edf2d (New md files from RunPod) **उच्च उत्परिवर्तन (>100 परिवर्तन/घंटा):** TTL=60s, छोटे कैश आकार। **मध्यम उत्परिवर्तन (10-100 परिवर्तन/घंटा):** TTL=300s (डिफ़ॉल्ट)। **कम उत्परिवर्तन (<10 परिवर्तन/घंटा):** TTL=600s, बड़े कैश आकार। @@ -502,21 +590,31 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): सभी डेटाबेस इंटरैक्शन के लिए पैरामीटराइज़्ड क्वेरी का उपयोग करें। DoS हमलों को रोकने के लिए क्वेरी जटिलता सीमाएं लागू करें। +<<<<<<< HEAD **संसाधन सुरक्षा:** +======= +**संसाधन संरक्षण:** +>>>>>>> 82edf2d (New md files from RunPod) अधिकतम सबग्राफ आकार सीमाओं को लागू करें। संसाधन समाप्त होने से रोकने के लिए क्वेरी टाइमआउट लागू करें। मेमोरी उपयोग निगरानी और सीमाएं जोड़ें। **पहुंच नियंत्रण:** मौजूदा उपयोगकर्ता और संग्रह अलगाव बनाए रखें। +<<<<<<< HEAD प्रदर्शन-प्रभावित करने वाले कार्यों के लिए ऑडिट लॉगिंग जोड़ें। महंगे कार्यों के लिए दर सीमित करना लागू करें। +======= +प्रदर्शन-प्रभावित संचालन के लिए ऑडिट लॉगिंग जोड़ें। +महंगे संचालन के लिए दर सीमित करना लागू करें। +>>>>>>> 82edf2d (New md files from RunPod) ## प्रदर्शन संबंधी विचार ### अपेक्षित प्रदर्शन सुधार **क्वेरी में कमी:** +<<<<<<< HEAD वर्तमान: विशिष्ट अनुरोध के लिए ~9,000+ क्वेरी अनुकूलित: ~50-100 बैच क्वेरी (98% कमी) @@ -527,6 +625,18 @@ DoS हमलों को रोकने के लिए क्वेरी **मेमोरी दक्षता:** बाउंडेड कैश आकार मेमोरी लीक को रोकते हैं। +======= +वर्तमान: विशिष्ट अनुरोध के लिए ~9,000+ क्वेरी। +अनुकूलित: ~50-100 बैच क्वेरी (98% कमी)। + +**प्रतिक्रिया समय में सुधार:** +ग्राफ ट्रैवर्सल: 15-20s → 3-5s (4-5x तेज़)। +लेबल रिज़ॉल्यूशन: 8-12s → 2-4s (3x तेज़)। +कुल क्वेरी: 25-35s → 6-10s (3-4x सुधार)। + +**मेमोरी दक्षता:** +बंधी हुई कैश आकार मेमोरी लीक को रोकते हैं। +>>>>>>> 82edf2d (New md files from RunPod) कुशल डेटा संरचनाएं मेमोरी पदचिह्न को ~40% तक कम करती हैं। उचित संसाधन सफाई के माध्यम से बेहतर कचरा संग्रह। @@ -582,7 +692,11 @@ DoS हमलों को रोकने के लिए क्वेरी ## कार्यान्वयन योजना ### प्रत्यक्ष कार्यान्वयन दृष्टिकोण +<<<<<<< HEAD चूंकि API में परिवर्तन की अनुमति है, इसलिए माइग्रेशन जटिलता के बिना अनुकूलन को सीधे लागू करें: +======= +चूंकि एपीआई में बदलाव की अनुमति है, इसलिए माइग्रेशन जटिलता के बिना अनुकूलन को सीधे लागू करें: +>>>>>>> 82edf2d (New md files from RunPod) 1. **`follow_edges` विधि को बदलें**: पुनरावृत्त बैच ट्रैवर्सल के साथ फिर से लिखें 2. **`get_labelgraph` को अनुकूलित करें**: समानांतर लेबल रिज़ॉल्यूशन लागू करें @@ -604,7 +718,11 @@ DoS हमलों को रोकने के लिए क्वेरी एक लेबल कैशिंग परत लागू करें **सप्ताह 2: परीक्षण और एकीकरण** +<<<<<<< HEAD नए ट्रैवर्सल और कैशिंग तर्क के लिए यूनिट परीक्षण +======= +नए ट्रैवर्सल और कैशिंग लॉजिक के लिए यूनिट परीक्षण +>>>>>>> 82edf2d (New md files from RunPod) वर्तमान कार्यान्वयन के खिलाफ प्रदर्शन बेंचमार्किंग वास्तविक ग्राफ डेटा के साथ एकीकरण परीक्षण कोड समीक्षा और अनुकूलन @@ -617,7 +735,11 @@ DoS हमलों को रोकने के लिए क्वेरी ## खुले प्रश्न **डेटाबेस कनेक्शन पूलिंग**: क्या हमें कस्टम कनेक्शन पूलिंग लागू करनी चाहिए या मौजूदा डेटाबेस क्लाइंट पूलिंग पर भरोसा करना चाहिए? +<<<<<<< HEAD **कैश दृढ़ता**: क्या लेबल और एम्बेडिंग कैश सेवा पुनरारंभों में बने रहने चाहिए? +======= +**कैश दृढ़ता**: क्या लेबल और एम्बेडिंग कैश सेवा पुनरारंभों में बने रहेंगे? +>>>>>>> 82edf2d (New md files from RunPod) **वितरित कैशिंग**: मल्टी-इंस्टेंस परिनियोजन के लिए, क्या हमें Redis/Memcached के साथ वितरित कैशिंग लागू करनी चाहिए? **क्वेरी परिणाम प्रारूप**: क्या हमें बेहतर मेमोरी दक्षता के लिए आंतरिक ट्रिपल प्रतिनिधित्व को अनुकूलित करना चाहिए? **निगरानी एकीकरण**: मौजूदा निगरानी प्रणालियों (Prometheus, आदि) के लिए कौन से मेट्रिक्स उजागर किए जाने चाहिए? diff --git a/docs/tech-specs/graphrag-performance-optimization.pt.md b/docs/tech-specs/graphrag-performance-optimization.pt.md index 8b04b106..0c118e1e 100644 --- a/docs/tech-specs/graphrag-performance-optimization.pt.md +++ b/docs/tech-specs/graphrag-performance-optimization.pt.md @@ -7,7 +7,11 @@ Esta especificação descreve otimizações abrangentes de desempenho para o alg 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. +<<<<<<< HEAD 4. **Otimização de Consultas**: Adicionar memorização de resultados e cache de incorporações para melhorar os tempos de resposta. +======= +4. **Otimização de Consulta**: Adicionar memorização de resultados e cache de embeddings para melhorar os tempos de resposta. +>>>>>>> 82edf2d (New md files from RunPod) ## Objetivos @@ -18,7 +22,11 @@ Esta especificação descreve otimizações abrangentes de desempenho para o alg **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. +<<<<<<< HEAD **Garantir a Confiabilidade**: Adicionar tratamento de erros adequado e mecanismos de tempo limite. +======= +**Garantir a Confiabilidade**: Adicionar tratamento de erros adequado e mecanismos de timeout. +>>>>>>> 82edf2d (New md files from RunPod) ## Contexto @@ -47,7 +55,11 @@ 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** +<<<<<<< HEAD Consultas de similaridade de vetores de entidade não são armazenadas em cache entre запросов semelhantes. +======= +Consultas de similaridade de vetores de entidades não são armazenadas em cache entre запросов semelhantes. +>>>>>>> 82edf2d (New md files from RunPod) Sem memorização de resultados para padrões de consulta repetidos. Otimização de consulta ausente para padrões de acesso comuns. @@ -66,11 +78,19 @@ Cenário de pior caso atual para uma consulta típica: **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): +<<<<<<< HEAD **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 +======= +**Número de consultas:** 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 +>>>>>>> 82edf2d (New md files from RunPod) 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 @@ -85,10 +105,17 @@ Escalar de forma eficiente com o tamanho e a complexidade do grafo A otimização de desempenho do GraphRAG requer os seguintes componentes técnicos: #### 1. **Refatoração Arquitetural do Ciclo de Vida dos Objetos** +<<<<<<< HEAD **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 +======= + **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 +>>>>>>> 82edf2d (New md files from RunPod) Módulo: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (modificado) @@ -111,12 +138,21 @@ A otimização de desempenho do GraphRAG requer os seguintes componentes técnic #### 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 +<<<<<<< HEAD **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** +======= + **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 Consultas** +>>>>>>> 82edf2d (New md files from RunPod) 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 @@ -213,9 +249,15 @@ class CacheManager: #### APIs Modificados: **GraphRag.query()** - Aprimorado com otimizações de desempenho: +<<<<<<< HEAD Adicionado parâmetro `cache_manager` para controle de cache. Incluído valor de retorno `performance_metrics`. Adicionado parâmetro `query_timeout` para confiabilidade. +======= +Adicionado o parâmetro `cache_manager` para controle de cache. +Incluído o valor de retorno `performance_metrics`. +Adicionado o parâmetro `query_timeout` para confiabilidade. +>>>>>>> 82edf2d (New md files from RunPod) **Classe Query** - Refatorada para processamento em lote: Substituição do processamento individual de entidades por operações em lote. @@ -326,8 +368,13 @@ Esta mudança arquitetural oferece: **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 +<<<<<<< HEAD **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. +======= +**Importante Limitação 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 detecta alterações em tempo real no grafo. +>>>>>>> 82edf2d (New md files from RunPod) #### Fase 1: Otimização de Traversal de Grafos @@ -480,6 +527,7 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ## Considerações sobre a Consistência do Cache **Compensações entre a Atualidade dos Dados:** +<<<<<<< HEAD **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. @@ -494,10 +542,27 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **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. +======= +**Cache de rótulos (TTL de 5 minutos)**: Risco de servir 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 retornados 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 +>>>>>>> 82edf2d (New md files from RunPod) ## Considerações de Segurança **Prevenção de Injeção de Consulta:** +<<<<<<< HEAD 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). @@ -511,12 +576,28 @@ Adicione monitoramento e limites de uso de memória. 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. +======= +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 +>>>>>>> 82edf2d (New md files from RunPod) ## Considerações de Desempenho ### Melhorias de Desempenho Esperadas **Redução de Consultas:** +<<<<<<< HEAD Atual: ~9.000+ consultas para um pedido típico. Otimizado: ~50-100 consultas agrupadas (redução de 98%). @@ -540,14 +621,46 @@ Melhor coleta de lixo através da limpeza adequada de recursos. 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. +======= +Atual: ~9.000+ consultas para um pedido típico +Otimizado: ~50-100 consultas em lote (redução de 98%) + +**Melhorias no Tempo de Resposta:** +Traversal do grafo: 15-20s → 3-5s (4-5x mais rápido) +Resolução de rótulos: 8-12s → 2-4s (3x mais rápido) +Consulta geral: 25-35s → 6-10s (melhora de 3-4x) + +**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 lote**: 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-4x no tempo de resposta, principalmente devido ao lote + +**Melhorias na Escalabilidade:** +Suporte para grafos de conhecimento 3-5x maiores (limitado pelas necessidades de consistência do cache) +Capacidade de solicitação concorrente 3-5x maior +Melhor utilização de recursos através da reutilização de conexões +>>>>>>> 82edf2d (New md files from RunPod) ### Monitoramento de Desempenho **Métricas em Tempo Real:** +<<<<<<< HEAD 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. +======= +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 na coleta de lixo +>>>>>>> 82edf2d (New md files from RunPod) **Benchmarking de Desempenho:** Testes de regressão de desempenho automatizados @@ -557,7 +670,11 @@ Benchmarks de comparação com a implementação atual ## Estratégia de Testes ### Testes Unitários +<<<<<<< HEAD Teste de componentes individuais para travessia, cache e resolução de rótulos +======= +Testes de componentes individuais para travessia, cache e resolução de rótulos +>>>>>>> 82edf2d (New md files from RunPod) 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 @@ -570,7 +687,11 @@ 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 +<<<<<<< HEAD Testes de carga com tamanhos e complexidades de grafos variáveis +======= +Testes de carga com diferentes tamanhos e complexidades de grafos +>>>>>>> 82edf2d (New md files from RunPod) Testes de estresse para limites de memória e conexões Testes de regressão para melhorias de desempenho diff --git a/docs/tech-specs/graphrag-performance-optimization.ru.md b/docs/tech-specs/graphrag-performance-optimization.ru.md index f4b8b82d..9954cc69 100644 --- a/docs/tech-specs/graphrag-performance-optimization.ru.md +++ b/docs/tech-specs/graphrag-performance-optimization.ru.md @@ -16,7 +16,11 @@ **Повышение масштабируемости**: Поддержка более крупных графов знаний с улучшением управления памятью. **Сохранение точности**: Сохранение существующей функциональности GraphRAG и качества результатов. **Обеспечение параллельности**: Улучшение возможностей параллельной обработки для нескольких одновременных запросов. +<<<<<<< HEAD **Уменьшение объема памяти**: Реализация эффективных структур данных и управления памятью. +======= +**Уменьшение объема используемой памяти**: Реализация эффективных структур данных и управления памятью. +>>>>>>> 82edf2d (New md files from RunPod) **Добавление возможностей мониторинга**: Включение показателей производительности и возможностей мониторинга. **Обеспечение надежности**: Добавление надлежащей обработки ошибок и механизмов таймаута. @@ -38,7 +42,11 @@ Обрабатывает каждый компонент тройки (субъект, предикат, объект) последовательно. Каждый вызов `maybe_label` потенциально вызывает запрос к базе данных. Без параллельного выполнения или пакетной обработки запросов меток. +<<<<<<< HEAD В результате получается до 3 × subgraph_size отдельных вызовов базы данных. +======= +Приводит до 3 × subgraph_size отдельных вызовов базы данных. +>>>>>>> 82edf2d (New md files from RunPod) **3. Примитивная стратегия кэширования (функция `maybe_label`, строки 62-77)** Простой кэш в виде словаря без ограничений размера или TTL. @@ -49,14 +57,23 @@ **4. Субоптимальные шаблоны запросов** Запросы на сравнение векторного сходства сущностей не кэшируются между похожими запросами. Без мемоизации результатов для повторяющихся шаблонов запросов. +<<<<<<< HEAD Отсутствие оптимизации запросов для распространенных шаблонов доступа. +======= +Отсутствует оптимизация запросов для распространенных шаблонов доступа. +>>>>>>> 82edf2d (New md files from RunPod) **5. Критические проблемы с жизненным циклом объектов (`rag.py:96-102`)** **Объект GraphRag создается для каждого запроса**: Новый экземпляр создается для каждого запроса, что приводит к потере всех преимуществ кэша. **Объект запроса имеет очень короткий срок службы**: Создается и уничтожается в течение выполнения одного запроса (строки 201-207). **Кэш меток сбрасывается для каждого запроса**: Подогрев кэша и накопленные знания теряются между запросами. +<<<<<<< HEAD **Накладные расходы на повторное создание клиента**: Клиенты базы данных потенциально повторно устанавливаются для каждого запроса. **Без оптимизации между запросами**: Невозможно извлечь выгоду из шаблонов запросов или совместного использования результатов. +======= +**Накладные расходы на повторное создание клиента**: Клиенты базы данных потенциально пересоздаются для каждого запроса. +**Отсутствие оптимизации между запросами**: Невозможно извлечь выгоду из шаблонов запросов или обмена результатами. +>>>>>>> 82edf2d (New md files from RunPod) ### Анализ влияния на производительность @@ -65,10 +82,17 @@ **Обход графа**: entities × max_path_length × 3 × triple_limit запросов. **Разрешение меток**: subgraph_size × 3 отдельных запросов на разрешение меток. +<<<<<<< HEAD Для параметров по умолчанию (50 сущностей, длина пути 2, ограничение в 30 тройки, размер подграфа 150): **Минимальное количество запросов**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9451 запрос к базе данных** **Время отклика**: 15-30 секунд для графов среднего размера **Использование памяти**: Неограниваемый рост кэша со временем +======= +Для параметров по умолчанию (50 сущностей, длина пути 2, ограничение в 30 троек, размер подграфа 150): +**Минимальное количество запросов**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9451 запрос к базе данных** +**Время отклика**: 15-30 секунд для графов среднего размера +**Использование памяти**: Неограниченный рост кэша со временем +>>>>>>> 82edf2d (New md files from RunPod) **Эффективность кэша**: 0% - кэши сбрасываются при каждом запросе **Накладные расходы на создание объектов**: Объекты GraphRag + Query создаются/удаляются для каждого запроса @@ -76,7 +100,11 @@ Поддерживать графы знаний корпоративного уровня с миллионами сущностей Обеспечивать время отклика менее 1 секунды для типичных запросов Обрабатывать сотни одновременных запросов GraphRAG +<<<<<<< HEAD Эффективно масштабироваться в зависимости от размера и сложности графа +======= +Эффективно масштабироваться с увеличением размера и сложности графа +>>>>>>> 82edf2d (New md files from RunPod) ## Технический дизайн @@ -85,17 +113,30 @@ Оптимизация производительности GraphRAG требует следующих технических компонентов: #### 1. **Архитектурная реорганизация жизненного цикла объектов** +<<<<<<< HEAD **Сделать GraphRag долгоживущим**: Переместить экземпляр GraphRag на уровень Processor для сохранения между запросами **Сохранять кэши**: Поддерживать кэш меток, кэш вложений и кэш результатов запросов между запросами **Оптимизировать объект Query**: Переработать Query как легковесный контекст выполнения, а не контейнер данных **Сохранять подключения к базе данных**: Поддерживать подключения к базе данных между запросами +======= + **Сделать GraphRag долгоживущим**: Переместить экземпляр GraphRag на уровень Processor для сохранения данных между запросами + **Сохранять кэши**: Поддерживать кэш меток, кэш вложений и кэш результатов запросов между запросами + **Оптимизировать объект Query**: Переработать Query как легковесный контекст выполнения, а не контейнер данных + **Сохранять соединения с базой данных**: Поддерживать соединения с базой данных между запросами +>>>>>>> 82edf2d (New md files from RunPod) Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (изменен) #### 2. **Оптимизированный движок обхода графа** +<<<<<<< HEAD Заменить рекурсивную `follow_edges` на итеративный поиск в ширину Реализовать пакетную обработку сущностей на каждом уровне обхода Добавить обнаружение циклов с помощью отслеживания посещенных узлов +======= + Заменить рекурсивную функцию `follow_edges` на итеративный поиск в ширину + Реализовать пакетную обработку сущностей на каждом уровне обхода + Добавить обнаружение циклов с использованием отслеживания посещенных узлов +>>>>>>> 82edf2d (New md files from RunPod) Включить раннее завершение при достижении лимитов Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` @@ -110,8 +151,13 @@ #### 4. **Консервативный слой кэширования меток** Кэш LRU с коротким TTL только для меток (5 минут) для баланса между производительностью и согласованностью +<<<<<<< HEAD Мониторинг метрик кэша и коэффициента попадания **Без кэширования вложений**: Уже кэшируются для каждого запроса, нет преимуществ для межзапросных данных +======= + Мониторинг метрик кэша и коэффициента попаданий + **Без кэширования вложений**: Уже кэшируются для каждого запроса, нет преимуществ для межзапросных операций +>>>>>>> 82edf2d (New md files from RunPod) **Без кэширования результатов запросов**: Из-за проблем согласованности изменений графа Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` @@ -119,7 +165,11 @@ #### 5. **Фреймворк оптимизации запросов** Анализ шаблонов запросов и предложения по оптимизации Пакетный координатор запросов для доступа к базе данных +<<<<<<< HEAD Управление пулами соединений и временем ожидания запросов +======= + Управление пулом соединений и временем ожидания запросов +>>>>>>> 82edf2d (New md files from RunPod) Мониторинг производительности и сбор метрик Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/query_optimizer.py` @@ -481,11 +531,16 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **Компромиссы между актуальностью данных:** **Кэш меток (TTL 5 минут):** Риск предоставления устаревших меток сущностей (удаленных или переименованных). +<<<<<<< HEAD **Отсутствие кэширования вложений:** Не требуется, так как вложения уже кэшируются для каждого запроса. +======= +**Отсутствие кэширования вложений:** Не требуется - вложения уже кэшируются для каждого запроса. +>>>>>>> 82edf2d (New md files from RunPod) **Отсутствие кэширования результатов:** Предотвращает получение устаревших результатов подграфов из-за удаленных сущностей/связей. **Стратегии смягчения:** **Консервативные значения TTL:** Баланс между приростом производительности (10-20%) и актуальностью данных. +<<<<<<< HEAD **Хуки для аннулирования кэша:** Необязательная интеграция с событиями изменения графа. **Панели мониторинга:** Отслеживание показателей попадания в кэш по сравнению с инцидентами устаревания данных. **Настраиваемые политики кэширования:** Возможность тонкой настройки для каждого развертывания в зависимости от частоты изменений. @@ -494,6 +549,16 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **Высокая частота изменений (>100 изменений/час):** TTL=60 секунд, меньшие размеры кэша. **Средняя частота изменений (10-100 изменений/час):** TTL=300 секунд (по умолчанию). **Низкая частота изменений (<10 изменений/час):** TTL=600 секунд, большие размеры кэша. +======= +**Механизмы аннулирования кэша:** Необязательная интеграция с событиями изменения графа. +**Информационные панели мониторинга:** Отслеживание показателей попадания в кэш по сравнению с инцидентами устаревания данных. +**Настраиваемые политики кэширования:** Возможность тонкой настройки для каждого развертывания в зависимости от частоты изменений. + +**Рекомендуемая конфигурация кэша в зависимости от скорости изменений графа:** +**Высокая скорость изменений (>100 изменений/час):** TTL=60 секунд, меньшие размеры кэша. +**Средняя скорость изменений (10-100 изменений/час):** TTL=300 секунд (по умолчанию). +**Низкая скорость изменений (<10 изменений/час):** TTL=600 секунд, большие размеры кэша. +>>>>>>> 82edf2d (New md files from RunPod) ## Соображения безопасности @@ -514,11 +579,19 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ## Соображения производительности +<<<<<<< HEAD ### Ожидаемые улучшения производительности **Сокращение количества запросов:** Сейчас: ~9000+ запросов для типичного запроса. Оптимизировано: ~50-100 пакетных запросов (снижение на 98%). +======= +### Ожидаемое повышение производительности + +**Сокращение количества запросов:** +Текущее: ~9000+ запросов для типичного запроса. +Оптимизированное: ~50-100 пакетных запросов (снижение на 98%). +>>>>>>> 82edf2d (New md files from RunPod) **Улучшение времени отклика:** Обход графа: 15-20 секунд → 3-5 секунд (в 4-5 раза быстрее). @@ -528,7 +601,11 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **Эффективность использования памяти:** Ограниченные размеры кэша предотвращают утечки памяти. Эффективные структуры данных уменьшают объем используемой памяти примерно на 40%. +<<<<<<< HEAD Улучшен сбор мусора благодаря правильной очистке ресурсов. +======= +Улучшенная сборка мусора благодаря правильной очистке ресурсов. +>>>>>>> 82edf2d (New md files from RunPod) **Реалистичные ожидания производительности:** **Кэш меток:** Уменьшение количества запросов на 10-20% для графов с общими связями. @@ -570,7 +647,11 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ### Тестирование производительности Тестирование производительности по сравнению с текущей реализацией +<<<<<<< HEAD Тестирование нагрузки с различными размерами и сложностью графов +======= +Тестирование нагрузки с графами различного размера и сложности +>>>>>>> 82edf2d (New md files from RunPod) Стресс-тестирование для проверки лимитов памяти и соединений Регрессионное тестирование для проверки улучшений производительности @@ -587,13 +668,21 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): 1. **Замените метод `follow_edges`**: Перепишите с использованием пакетного итеративного обхода 2. **Оптимизируйте `get_labelgraph`**: Реализуйте параллельное разрешение меток 3. **Добавьте долгоживущий GraphRag**: Измените Processor для поддержания постоянной инстанции +<<<<<<< HEAD 4. **Реализуйте кэширование меток**: Добавьте кэш LRU с TTL в класс GraphRag +======= +4. **Реализуйте кэширование меток**: Добавьте кэш LRU со сроком действия TTL в класс GraphRag +>>>>>>> 82edf2d (New md files from RunPod) ### Область изменений **Класс запроса**: Замените ~50 строк в `follow_edges`, добавьте ~30 строк для обработки пакетов **Класс GraphRag**: Добавьте слой кэширования (~40 строк) **Класс Processor**: Измените для использования постоянной инстанции GraphRag (~20 строк) +<<<<<<< HEAD **Всего**: ~140 строк целенаправленных изменений, в основном в существующих классах +======= +**Всего**: ~140 строк изменений, в основном в существующих классах +>>>>>>> 82edf2d (New md files from RunPod) ## Временная шкала @@ -606,12 +695,17 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **Неделя 2: Тестирование и интеграция** Модульные тесты для новой логики обхода и кэширования Бенчмаркинг производительности по сравнению с текущей реализацией +<<<<<<< HEAD Интеграционное тестирование с реальными данными графа +======= +Интеграционное тестирование с реальными графовыми данными +>>>>>>> 82edf2d (New md files from RunPod) Проверка кода и оптимизация **Неделя 3: Развертывание** Разверните оптимизированную реализацию Отслеживайте улучшения производительности +<<<<<<< HEAD Тонкая настройка TTL кэша и размеров пакетов на основе реального использования ## Открытые вопросы @@ -620,10 +714,24 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **Постоянство кэша**: Должны ли кэши меток и внедрений сохраняться после перезапуска службы? **Распределенное кэширование**: Для развернутых в нескольких экземплярах систем следует ли нам реализовать распределенное кэширование с использованием Redis/Memcached? **Формат результата запроса**: Следует ли нам оптимизировать внутреннее представление тройки для повышения эффективности использования памяти? +======= +Тонкая настройка срока действия TTL кэша и размеров пакетов на основе реального использования + +## Открытые вопросы + +**Пул соединений с базой данных**: Следует ли нам реализовывать собственный пул соединений или использовать существующий пул соединений от клиента базы данных? +**Постоянство кэша**: Должны ли кэши меток и вложений сохраняться после перезапуска сервиса? +**Распределенное кэширование**: Для развернутых в нескольких инстанциях систем следует ли реализовывать распределенное кэширование с использованием Redis/Memcached? +**Формат результата запроса**: Следует ли оптимизировать внутреннее представление тройки для повышения эффективности использования памяти? +>>>>>>> 82edf2d (New md files from RunPod) **Интеграция мониторинга**: Какие метрики следует предоставлять существующим системам мониторинга (Prometheus и т. д.)? ## Ссылки +<<<<<<< HEAD [Оригинальная реализация GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +======= +[Исходная реализация GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +>>>>>>> 82edf2d (New md files from RunPod) [Принципы архитектуры 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 94f8a2fb..2a72aab4 100644 --- a/docs/tech-specs/graphrag-performance-optimization.sw.md +++ b/docs/tech-specs/graphrag-performance-optimization.sw.md @@ -1,7 +1,12 @@ +<<<<<<< HEAD # Vipimo vya Ufanisi wa GraphRAG kwa Uboreshaji wa Kawaida +======= +# Vipimo vya Ufanisi wa GraphRAG kwa Uboreshaji wa Kiufundi +>>>>>>> 82edf2d (New md files from RunPod) ## Maelezo +<<<<<<< HEAD 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 hivi karibuni ya hivi karibuni na tekeleza utafutaji wa grafu wa kikundi @@ -19,6 +24,25 @@ Hati hii inaeleza uboreshaji wa kina wa utendaji wa algorithm ya GraphRAG (Graph **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 +======= +Maelekezo haya yanaelezea uboreshaji wa kina wa utendaji kwa 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. Maelekezo haya yanaangazia maeneo manne makuu ya uboreshaji: + +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 lebo wa mfululizo 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. + +## Lengo + +**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 subgraph 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. +>>>>>>> 82edf2d (New md files from RunPod) ## Asili @@ -27,6 +51,7 @@ Utaratibu wa sasa wa GraphRAG katika `trustgraph-flow/trustgraph/retrieval/graph ### Matatizo ya Sasa ya Utendaji **1. Ufuatiliaji Usio na Ufanisi wa Grafu (kitendaji cha `follow_edges`, mistari 79-127)** +<<<<<<< HEAD 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 @@ -57,10 +82,43 @@ Uboreshaji wa swali unaokosekana kwa mifumo ya kawaida ya ufikiaji **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 +======= +Hufanya maswali 3 tofauti ya hivi karibuni kwa kila kitu kwa kila ngazi ya 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 kielelekeo. +Utata wa muda: O(vitabu × urefu_max_wa_njia × kikomo_cha_triple³) + +**2. Utatuzi wa Msingi wa Lebo (kitendaji cha `get_labelgraph`, mistari 144-171)** +Huchakata kila sehemu ya triple (mhusika, tabia, kitu) kwa utaratibu. +Kila wito wa `maybe_label` inaweza kusababisha swali la hivi karibuni. +Hakuna utekelezaji sambamba au kikundi cha maswali ya lebo. +Hupelekea hadi simu 3 × ya hivi karibuni ya mtu binafsi ya hivi karibuni. + +**3. Mkakati wa Kumbukumbu ya Msingi (kitendaji cha `maybe_label`, mistari 62-77)** +Kumbukumbu rahisi ya kamusi bila mipaka ya ukubwa au TTL. +Hakuna sera ya kuondoa kumbukumbu inayosababisha ukuaji usio na kikomo wa kumbukumbu. +Kupoteza kumbukumbu hutuma maswali ya hivi karibuni ya mtu binafsi ya hivi karibuni. +Hakuna utabiri au uongezaji mahiri wa kumbukumbu. + +**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**: Mfano mpya huundwa kwa kila swali, ukipoteza 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 maombi**: Uongezaji wa kumbukumbu na maarifa yaliyokusanywa hupotea kati ya maombi. +**Upekee wa upya wa mteja**: Wateja wa hivi karibuni wanaweza kuanzishwa tena kwa kila maombi. +**Hakuna uboreshaji wa maombi**: Haiwezi kufaidika na mifumo ya swali au ushirikishwaji wa matokeo. +>>>>>>> 82edf2d (New md files from RunPod) ### Uchambuzi wa Athari ya Utendaji Hali mbaya zaidi ya sasa kwa swali la kawaida: +<<<<<<< HEAD **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 @@ -70,6 +128,17 @@ Kwa vigezo chache (vitu 50, urefu wa njia 2, kikomo cha triplet 30, saizi ya sub **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 +======= +**Upekuzi wa Kitu**: swali 1 la ufanano wa vekta. +**Ufuatiliaji wa Grafu**: vitabu × urefu_max_wa_njia × 3 × maswali ya hivi karibuni ya triple. +**Utatuzi wa Lebo**: maswali ya mtu binafsi ya hivi karibuni ya lebo ya subgraph_size × 3. + +Kwa vigezo chaguvi (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**: ukuaji usio na kikomo wa kumbukumbu kwa muda +**Ufanisi wa kumbukumbu**: 0% - kumbukumbu hurekebishwa kila mara +>>>>>>> 82edf2d (New md files from RunPod) **Utozo wa kuunda vitu**: Vitu vya GraphRag + Query vinaundwa/vinaharibiwa kwa kila ombi 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: @@ -85,10 +154,17 @@ Kuongezeka kwa ufanisi na saizi na utata wa vielelezo Uboreshaji wa utendaji wa GraphRAG unahitaji vipengele hivi vya kiufundi: #### 1. **Urekebishaji wa Usanifu wa Muda wa Vitu** +<<<<<<< HEAD **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 +======= + **Fanya GraphRag iwe ya muda mrefu**: Hamisha mfano wa GraphRag hadi ngazi ya Processor ili kudumu katika ombi + **Ondoa kumbukumbu**: Dumishe kumbukumbu ya lebo, kumbukumbu ya uingizaji, na kumbukumbu ya matokeo ya swali kati ya ombi + **Boresha kitu cha Swali**: Rekebisha Swali ili iwe muktadha wa utekelezaji mwepesi, sio chombo cha data + **Usaidizi wa muunganisho**: Dumishe miunganisho ya mteja wa hifadhidata katika ombi +>>>>>>> 82edf2d (New md files from RunPod) Moduli: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (iliyorekebishwa) @@ -100,6 +176,7 @@ Uboreshaji wa utendaji wa GraphRAG unahitaji vipengele hivi vya kiufundi: Moduli: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py` +<<<<<<< HEAD #### 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 @@ -113,6 +190,21 @@ Uboreshaji wa utendaji wa GraphRAG unahitaji vipengele hivi vya kiufundi: 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 +======= +#### 3. **Mfumo wa Suluhisho la Lebo Sambamba** + Kikundi maswali ya lebo kwa vitu vingi kwa wakati mmoja + Tekeleza mifumo ya async/await kwa ufikiaji sambamba wa hifadhidata + Ongeza utabiri wa kupata kwa mifumo ya kawaida ya lebo + Jumuisha mikakati ya kupasha joto ya kumbukumbu ya lebo + + Moduli: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py` + +#### 4. **Nafasi Hifadhi ya Lebo** + Kumbukumbu ya LRU na TTL fupi kwa lebo pekee (dakika 5) ili kusawazisha utendaji dhidi ya uthabiti + Fuatilia metriki na uwiano wa hit + **Hakuna kumbukumbu ya uingizaji**: Tayari imehifadhiwa kwa kila swali, hakuna faida ya kati ya maswali + **Hakuna kumbukumbu ya matokeo ya swali**: Kutokana na wasiwasi wa uthabiti wa mabadiliko ya vielelezo +>>>>>>> 82edf2d (New md files from RunPod) Moduli: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py` @@ -128,7 +220,11 @@ Uboreshaji wa utendaji wa GraphRAG unahitaji vipengele hivi vya kiufundi: #### Hali Iliyoboreshwa ya Ufuatiliaji wa Vielelezo +<<<<<<< HEAD Injini ya ufuatiliaji inahifadhi hali ili kuepuka shughuli za ziada: +======= +Injini ya ufuatiliaji inadumisha hali ili kuepuka shughuli za ziada: +>>>>>>> 82edf2d (New md files from RunPod) ```python @dataclass @@ -142,10 +238,17 @@ class TraversalState: ``` Mbinu hii inaruhusu: +<<<<<<< HEAD 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 +======= +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. +>>>>>>> 82edf2d (New md files from RunPod) #### Muundo Ulioboreshwa wa Kumbukumbu (Cache) @@ -164,7 +267,11 @@ class CacheManager: cache_stats: CacheStatistics ``` +<<<<<<< HEAD #### Muundo wa Maswali ya Kundi +======= +#### Muundo wa Maswali kwa Wingi +>>>>>>> 82edf2d (New md files from RunPod) ```python @dataclass @@ -217,6 +324,7 @@ Ongeza parameter ya `cache_manager` kwa udhibiti wa kumbukumbu. Jumuisha thamani ya kurudiwa ya `performance_metrics`. Ongeza parameter ya `query_timeout` kwa uaminifu. +<<<<<<< HEAD **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. @@ -225,6 +333,16 @@ Jumuisha miongozo ya maendeleo kwa operesheni za muda mrefu. ### Maelezo ya Utendaji #### Awamu ya 0: Urekebishaji Muhimu wa Muundo na Muda wa Maisha +======= +**Kifaa cha `Query`** - Kimepangwa upya kwa usindikaji wa jumla: +Badilisha usindikaji wa kila kitu kwa shughuli za jumla. +Ongeza menejimenti ya muktadha wa async kwa usafi wa rasilimali. +Jumuisha miongozo ya maendeleo kwa shughuli za muda mrefu. + +### Maelezo ya Utendaji + +#### Awamu ya 0: Urekebishaji Muhimu wa Muundo na Muda +>>>>>>> 82edf2d (New md files from RunPod) **Utendaji Sasa Usiofaa:** ```python @@ -250,7 +368,11 @@ class GraphRag: # q automatically destroyed when function exits ``` +<<<<<<< HEAD **Muundo Ulioboreshwa na Umeundwa Kudumu:** +======= +**Muundo Uliounganishwa Vizuri na Umeundwa kwa Muda Mrefu:** +>>>>>>> 82edf2d (New md files from RunPod) ```python class Processor(FlowProcessor): def __init__(self, **params): @@ -322,12 +444,21 @@ class QueryExecutor: 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) +<<<<<<< HEAD **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. +======= +**Kuondolewa kwa gharama ya utengenezaji wa kitu** kwa kila ombi +**Uunganishaji wa kudumu na matumizi ya mteja tena** +**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 hatari ya 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 uongevu wa data, lakini haiwezi kuchunguza mabadiliko ya grafu ya wakati halisi. +>>>>>>> 82edf2d (New md files from RunPod) #### Awamu ya 1: Uboreshaji wa Ufuatiliaji wa Grafu @@ -381,7 +512,11 @@ async def optimized_traversal(self, entities: List[str], max_depth: int) -> Set[ #### Awamu ya 2: Utatuzi wa Lebo Sambamba +<<<<<<< HEAD **Utendaji wa Sasa wa Mfululizo:** +======= +**Utaratibu wa Sasa wa Utendaji:** +>>>>>>> 82edf2d (New md files from RunPod) ```python # INEFFICIENT: Sequential processing for edge in subgraph: @@ -413,9 +548,15 @@ async def resolve_labels_parallel(self, subgraph: List[Triple]) -> List[Triple]: ] ``` +<<<<<<< HEAD #### Awamu ya 3: Mkakati wa Kupanua Data (Caching) wa Juu **Kupanua Data (Cache) la LRU pamoja na TTL:** +======= +#### Awamu ya 3: Mbinu Iliyoboreshwa ya Kuhifadhi Data + +**Kifaa cha Kuhifadhi Data cha LRU (Least Recently Used) pamoja na TTL (Time To Live):** +>>>>>>> 82edf2d (New md files from RunPod) ```python class LRUCacheWithTTL: def __init__(self, max_size: int, default_ttl: int = 3600): @@ -451,7 +592,11 @@ class LRUCacheWithTTL: self.access_times[key] = time.time() ``` +<<<<<<< HEAD #### Awamu ya 4: Ubora wa Ufuatiliaji na Ufuatiliaji +======= +#### Awamu ya 4: Ubora wa Ufuatiliaji na Usimamizi +>>>>>>> 82edf2d (New md files from RunPod) **Ukusanyaji wa Vipimo vya Utendaji:** ```python @@ -477,6 +622,7 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): raise GraphRagTimeoutError(f"Query exceeded timeout of {timeout}s") ``` +<<<<<<< HEAD ## Mawasilisho ya Ulinganishaji wa Kumbukumbu (Cache) **Ulinganishaji wa Uharibifu wa Data:** @@ -498,17 +644,48 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ## Mawasilisho ya Usalama **Kuzuia Uingizwaji wa Swali:** +======= +## Mawasilisho ya Ulinganishaji wa Hifadhi (Cache) + +**Ulinganishaji wa Uharibifu wa Data:** +**Hifadhi ya lebo (TTL ya dakika 5)**: Hatari ya kuonyesha lebo za vitu ambazo zimefutwa/kubadilishwa +**Hakuna uhifadhi wa embeddings**: Haihitajiki - embeddings tayari zimehifadhiwa kwa kila swali +**Hakuna uhifadhi wa matokeo**: Inazuia matokeo ya subgrafu ya zamani kutoka kwa vitu/uhusiano ambao umeondolewa + +**Mikakati ya Kupunguza Madhara:** +**Manufaa ya TTL ya kiuchunguzi:** Kusawazisha faida za utendaji (10-20%) na usafi wa data +**Viunganishi vya kutengua hifadhi:** Unganisho wa hiari na matukio ya mabadiliko ya grafu +**Dashibodi za ufuatiliaji:** Kufuatilia viwango vya hit ya hifadhi dhidi ya matukio ya uharibifu +**Mbinu za hifadhi zinazoweza kusanidi:** Kuruhusu urekebishaji wa kila usakinishaji kulingana na masafa ya mabadiliko + +**Mazingatio Yanayopendekezwa ya Hifadhi Kulingana na Kasi ya Mabadiliko ya Grafu:** +**Mabadiliko ya juu (>100 mabadiliko/saa)**: TTL=60s, saizi ndogo za hifadhi +**Mabadiliko ya wastani (10-100 mabadiliko/saa)**: TTL=300s (ya kawaida) +**Mabadiliko ya chini (<10 mabadiliko/saa)**: TTL=600s, saizi kubwa za hifadhi + +## Masuala ya Usalama + +**Kuzuia Uingizwaji wa Maswali:** +>>>>>>> 82edf2d (New md files from RunPod) 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) **Ulinzi wa Rasilimali:** Enforce mipaka ya juu ya saizi ya subgrafu +<<<<<<< HEAD Tekeleza muda wa mwisho wa swali ili kuzuia kutokuwa na rasilimali Ongeza ufuatiliaji na mipaka ya matumizi ya kumbukumbu **Kidhibiti cha Ufikiaji:** Endeleza kutengwa kwa watumiaji na ukusanyaji iliyopo +======= +Tekeleza muda wa mwisho wa swali ili kuzuia uchovu wa rasilimali +Ongeza ufuatiliaji na mipaka ya matumizi ya kumbukumbu + +**Kidhibiti cha Ufikiaji:** +Endeleza kutengwa kwa watumiaji na mkusanyiko iliyopo +>>>>>>> 82edf2d (New md files from RunPod) Ongeza uandikaji wa ukaguzi kwa operesheni zinazoathiri utendaji Tekeleza kikomo cha kiwango kwa operesheni ghali @@ -516,9 +693,15 @@ Tekeleza kikomo cha kiwango kwa operesheni ghali ### Maboresho Yanayotarajiwa ya Utendaji +<<<<<<< HEAD **Upunguzaji wa Swali:** Sasa: ~9,000+ maswali kwa ombi la kawaida Yaliyoboreshwa: ~50-100 maswali yaliyunganishwa (upunguzaji wa 98%) +======= +**Upunguzaji wa Maswali:** +Sasa: ~9,000+ maswali kwa ombi la kawaida +Yaliyoboreshwa: ~50-100 maswali yaliyogawanywa (upunguzaji wa 98%) +>>>>>>> 82edf2d (New md files from RunPod) **Maboresho ya Muda wa Jibu:** Ufuatiliaji wa grafu: 15-20s → 3-5s (haraka 4-5x) @@ -526,11 +709,16 @@ Utatuzi wa lebo: 8-12s → 2-4s (haraka 3x) Swali kamili: 25-35s → 6-10s (maboresho ya 3-4x) **Ufanisi wa Kumbukumbu:** +<<<<<<< HEAD Saizi zilizokadiriwa za kumbukumbu inazuia uvujaji wa kumbukumbu +======= +Saizi zilizokadiriwa za hifadhi inazuia uvujaji wa kumbukumbu +>>>>>>> 82edf2d (New md files from RunPod) Miundo ya data inayofaa hupunguza athari ya kumbukumbu kwa ~40% Urekebishaji wa taka bora kupitia usafi sahihi wa rasilimali **Mataifa ya Kweli ya Utendaji:** +<<<<<<< HEAD **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 @@ -538,26 +726,48 @@ Urekebishaji wa taka bora kupitia usafi sahihi wa rasilimali **Maboresho ya Uwezo wa Kupanuka:** Usaidizi wa grafu za maarifa kubwa 3-5x (vikomo na mahitaji ya ulinganishaji wa utendaji) +======= +**Hifadhi ya lebo**: Upunguzaji wa 10-20% wa maswali kwa grafu zilizo na uhusiano wa kawaida +**Uboreshaji wa uainishaji**: Upunguzaji wa 50-80% wa maswali (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 uainishaji + +**Maboresho ya Uwezo wa Kupanuka:** +Usaidizi wa grafu za maarifa kubwa 3-5x (mdogo na mahitaji ya ulinganishaji wa data) +>>>>>>> 82edf2d (New md files from RunPod) Uwezo wa juu 3-5x wa ombi la wakati mmoja Matumizi bora ya rasilimali kupitia matumizi ya upya ya muunganisho ### Ufuatiliaji wa Utendaji +<<<<<<< HEAD **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 +======= +**Mataifa ya Muda Halisi:** +Muda wa utekelezaji wa swali kwa aina ya operesheni +Viwango vya hit na ufanisi wa hifadhi +Matumizi ya dimbidi ya muunganisho wa hifadhidata +>>>>>>> 82edf2d (New md files from RunPod) Matumizi ya kumbukumbu na athari ya urekebishaji wa taka **Ufuatiliaji wa Utendaji:** Mtihirika wa kiotomatiki wa utendaji +<<<<<<< HEAD Mtihirika wa mzigo ukitumia data halisi Viwango vya utendaji dhidi ya utekelezaji wa sasa +======= +Mtihirika wa mzigo kwa matumizi halisi ya data +Viwango vya kulinganisho dhidi ya utekelezaji wa sasa +>>>>>>> 82edf2d (New md files from RunPod) ## Mkakati wa Mtihirika ### Mtihirika wa Vitengo Mtihirika wa vipengele vya mtu binafsi kwa ajili ya utekelezaji, kuhifadhi, na utatuzi wa lebo +<<<<<<< HEAD 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 @@ -565,11 +775,21 @@ 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 +======= +Mwingiliano wa bandarini ya hila kwa ajili ya mtihirika wa utendaji +Mtihirika wa kuondoa data kutoka kwa kumbukumbu na kumalizika kwa muda +Usimamizi wa makosa na hali za muda + +### Mtihirika wa Uunganisho +Mtihirika wa mwisho hadi mwisho wa swali la GraphRAG na uboreshaji +Mtihirika wa mwingiliano wa bandarini ya data halisi +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD Mtihirika wa mzigo ukitumia saizi na utata tofauti wa grafu Mtihirika wa shinikizo kwa mipaka ya kumbukumbu na uunganisho Mtihirika wa utendaji kwa uboreshaji @@ -577,6 +797,15 @@ 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 +======= +Mtihirika wa mzigo kwa saizi na utata tofauti wa grafu +Mtihirika wa shinikizo kwa mipaka ya kumbukumbu na uunganisho +Mtihirika wa marejesho kwa maboresho ya utendaji + +### Mtihirika wa Ulinganishi +Thibitisha ulinganishi wa API ya GraphRAG iliyopo +Mtihirika na bandarini tofauti za hifadhi ya grafu +>>>>>>> 82edf2d (New md files from RunPod) Thibitisha usahihi wa matokeo ikilinganishwa na utekelezaji wa sasa ## Mpango wa Utendaji @@ -584,8 +813,13 @@ Thibitisha usahihi wa matokeo ikilinganishwa na utekelezaji wa sasa ### Mbinu ya Utendaji Moja kwa Moja Kwa kuwa API zinaweza kubadilika, tekeleza uboreshaji moja kwa moja bila utata wa uhamishaji: +<<<<<<< HEAD 1. **Badilisha `follow_edges` mbinu**: Andika upya ukitumia utekelezaji wa kikundi 2. **Boresha `get_labelgraph`**: Tepeleza utatuzi wa lebo kwa wingi +======= +1. **Badilisha `follow_edges` mbinu**: Andika upya kwa utekelezaji wa kikundi +2. **Boresha `get_labelgraph`**: Tepeleza utatuzi wa lebo kwa njia ya sambamba +>>>>>>> 82edf2d (New md files from RunPod) 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 @@ -598,13 +832,19 @@ Kwa kuwa API zinaweza kubadilika, tekeleza uboreshaji moja kwa moja bila utata w ## Ratiba **Wiki ya 1: Utendaji wa Msingi** +<<<<<<< HEAD Badilisha `follow_edges` ukitumia utekelezaji wa kikundi Tepeleza utatuzi wa lebo kwa wingi katika `get_labelgraph` +======= +Badilisha `follow_edges` kwa utekelezaji wa kikundi +Tepeleza utatuzi wa lebo kwa njia ya sambamba katika `get_labelgraph` +>>>>>>> 82edf2d (New md files from RunPod) Ongeza mfano wa GraphRag wa muda mrefu kwa Processor Tepeleza safu ya uhifadhi **Wiki ya 2: Mtihirika na Uunganisho** Mtihirika wa vitengo kwa ajili ya utekelezaji mpya wa utekelezaji na uhifadhi +<<<<<<< HEAD Ufuatiliaji wa utendaji dhidi ya utekelezaji wa sasa Mtihirika wa uunganisho ukitumia data halisi ya grafu Mtihirika wa msimamizi na uboreshaji @@ -621,9 +861,31 @@ Punguza muda wa TTL wa kumbukumbu na saizi za kikundi kulingana na matumizi hali **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.)? +======= +Mtihirika wa utendaji dhidi ya utekelezaji wa sasa +Mtihirika wa uunganisho na data halisi ya grafu +Mtihirika wa msimamizi na uboreshaji + +**Wiki ya 3: Uwekaji** +Weka utekelezaji ulioboreshwa +Fuatilia maboresho ya utendaji +Punguza muda wa uhifadhi na saizi za kikundi kulingana na matumizi halisi + +## Maswali ya Funguo + +**Uunganisho wa Bandarini**: Je, tunapaswa kutekeleza bandarini ya uunganisho maalum au kutegemea bandarini ya mteja wa hifadhi iliyopo? +**Ukurasa wa Uhifadhi**: Je, uhifadhi wa lebo na uwekaji unapaswa kudumu katika kuanzishwa upya huduma? +**Ukurasa Uliogawanyika**: Kwa matoleo mengi, je, tunapaswa kutekeleza ukurasa uliogawanyika na Redis/Memcached? +**Muundo wa Matokeo ya Swali**: Je, tunapaswa kuboresha uwakilishi wa ndani wa utatu kwa ufanisi bora wa kumbukumbu? +**Uunganisho wa Ufuatiliaji**: Ni metri gani ambazo zinapaswa kuonyeshwa kwa mifumo ya ufuatiliaji iliyopo (Prometheus, n.k.)? +>>>>>>> 82edf2d (New md files from RunPod) ## Marejeleo [Utekelezaji Asili wa GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +<<<<<<< HEAD [Kanuni za Usanifu wa TrustGraph](architecture-principles.md) +======= +[Kanuni za Usawa wa TrustGraph](architecture-principles.md) +>>>>>>> 82edf2d (New md files from RunPod) [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 index bdb1d687..9905ae46 100644 --- a/docs/tech-specs/graphrag-performance-optimization.tr.md +++ b/docs/tech-specs/graphrag-performance-optimization.tr.md @@ -17,7 +17,11 @@ Bu özellik, TrustGraph'taki GraphRAG (Graf Çıkarım Destekli Üretim) algorit **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. +<<<<<<< HEAD **Gözlemlenebilirliği Ekleyin**: Performans ölçümleri ve izleme yetenekleri ekleyin. +======= +**Gözlenebilirliği Ekleyin**: Performans ölçümleri ve izleme yetenekleri ekleyin. +>>>>>>> 82edf2d (New md files from RunPod) **Güvenilirliği Sağlayın**: Uygun hata işleme ve zaman aşımı mekanizmaları ekleyin. ## Arka Plan @@ -27,6 +31,7 @@ Bu özellik, TrustGraph'taki GraphRAG (Graf Çıkarım Destekli Üretim) algorit ### Mevcut Performans Sorunları **1. Verimsiz Graf Gezinme (`follow_edges` fonksiyonu, 79-127 satırlar)** +<<<<<<< HEAD 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. @@ -50,19 +55,52 @@ Boyut sınırları veya TTL (Yaşam Süresi) olmadan basit bir sözlük önbelle 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. +======= +Her varlık için 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 × maks_yol_uzunluğu × üçlü_sınırı³) + +**2. Sıralı Etiket Çözümleme (`get_labelgraph` fonksiyonu, 144-171 satırlar)** +Her üç bileşenli (konu, öznelik, nesne) sırayla 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 yok. +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 Sonu) 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 yok. + +**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 yok. +Yaygın erişim kalıpları için sorgu optimizasyonu eksik. +>>>>>>> 82edf2d (New md files from RunPod) **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. +<<<<<<< HEAD **İstekler arası optimizasyon yok**: Sorgu kalıplarından veya sonuç paylaşımından yararlanamaz. +======= +**Çapraz istek optimizasyonu yok**: Sorgu kalıplarından veya sonuç paylaşımından yararlanamaz. +>>>>>>> 82edf2d (New md files from RunPod) ### Performans Etki Analizi Tipik bir sorgu için mevcut en kötü senaryo: **Varlık Alma**: 1 vektör benzerliği sorgusu. +<<<<<<< HEAD **Graf Gezinme**: varlıklar × max_path_length × 3 × triple_limit sorgusu. +======= +**Graf Gezinme**: varlıklar × maks_yol_uzunluğu × 3 × üçlü_sınırı sorguları. +>>>>>>> 82edf2d (New md files from RunPod) **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): @@ -70,7 +108,11 @@ Varsayılan parametreler için (50 varlık, yol uzunluğu 2, 30 üçlü sınır **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 +<<<<<<< HEAD **Nesne oluşturma ek yükü**: Her istek için oluşturulan/silinen GraphRag + Sorgu nesneleri +======= +**Nesne oluşturma ek yükü**: Her istek için GraphRag + Sorgu nesneleri oluşturulur/silinir +>>>>>>> 82edf2d (New md files from RunPod) 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 @@ -322,12 +364,20 @@ class QueryExecutor: 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) +<<<<<<< HEAD Her istek için **ortadan kaldırılan nesne oluşturma ek yükü** +======= +Her istek için **oluşturulan nesnelerin getirdiği ek yükün ortadan kaldırılması** +>>>>>>> 82edf2d (New md files from RunPod) **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ı:** +<<<<<<< HEAD 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. +======= +Uzun süreli önbellekleme, temel grafikteki varlıkların/etiketlerin silindiği veya değiştirildiği durumlarda, verilerin güncelliğini yitirme riski oluşturur. LRU (En Son Kullanılmayan) önbelleği, performans artışları ve veri tazeliği arasında bir denge sağlar, ancak gerçek zamanlı grafik değişikliklerini tespit edemez. +>>>>>>> 82edf2d (New md files from RunPod) #### 1. Aşama: Grafik Gezinme Optimizasyonu @@ -486,7 +536,11 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **Azaltma Stratejileri:** **Muhafazakar TTL değerleri:** Performans kazanımları (10-20%) ile veri güncelliği arasındaki denge. +<<<<<<< HEAD **Önbellek geçersiz kılma kancaları:** İsteğe bağlı olarak grafik mutasyon olaylarıyla entegrasyon. +======= +**Önbellek geçersiz kılma mekanizmaları:** Grafik mutasyon olaylarıyla isteğe bağlı entegrasyon. +>>>>>>> 82edf2d (New md files from RunPod) **İ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. @@ -497,14 +551,23 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ## Güvenlik Hususları +<<<<<<< HEAD **Sorgu Enjeksiyonunu Önleme:** +======= +**Sorgu Enjeksiyonu Önleme:** +>>>>>>> 82edf2d (New md files from RunPod) 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ı:** +<<<<<<< HEAD Maksimum alt grafik boyutları limitlerini uygulayın. Kaynak tükenmesini önlemek için sorgu zaman aşımlarını uygulayın. +======= +Maksimum alt grafik boyutları için limitler uygulayın. +Kaynak tükenmesini önlemek için sorgu zaman aşımları uygulayın. +>>>>>>> 82edf2d (New md files from RunPod) Bellek kullanımı izleme ve limitleri ekleyin. **Erişim Kontrolü:** @@ -517,7 +580,11 @@ Pahalı işlemler için hız sınırlaması uygulayın. ### Beklenen Performans İyileştirmeleri **Sorgu Azaltma:** +<<<<<<< HEAD Mevcut: Tipik bir istek için ~9.000+ sorgu. +======= +Mevcut: Tipik bir istek için ~9.000'den fazla sorgu. +>>>>>>> 82edf2d (New md files from RunPod) Optimize edilmiş: ~50-100 toplu sorgu (98% azalma). **Yanıt Süresi İyileştirmeleri:** @@ -537,7 +604,11 @@ Uygun kaynak temizliği sayesinde daha iyi çöp toplama. **Genel iyileşme:** Toplu işlemden kaynaklanan 3-4 kat yanıt süresi iyileşmesi. **Ölçeklenebilirlik İyileştirmeleri:** +<<<<<<< HEAD 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 büyük bilgi grafiklerini destekler (önbellek tutarlılık gereksinimleriyle sınırlıdır). +>>>>>>> 82edf2d (New md files from RunPod) 3-5 kat daha yüksek eşzamanlı istek kapasitesi. Bağlantı yeniden kullanımı sayesinde daha iyi kaynak kullanımı. @@ -564,7 +635,11 @@ Hata işleme ve zaman aşımı senaryoları ### Entegrasyon Testi Optimizasyonlarla uçtan uca GraphRAG sorgu testi +<<<<<<< HEAD Gerçek verilerle veritabanı etkileşim testi +======= +Gerçek verilerle veritabanı etkileşimi testi +>>>>>>> 82edf2d (New md files from RunPod) Eşzamanlı istek işleme ve kaynak yönetimi Bellek sızıntısı tespiti ve kaynak temizleme doğrulaması @@ -585,9 +660,15 @@ Mevcut uygulamaya kıyasla sonuç doğruluğunu doğrulayın 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 +<<<<<<< HEAD 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 +======= +2. **`get_labelgraph`'ı optimize edin**: Paralel etiket çözümlemesini uygulayın +3. **Uzun ömürlü GraphRag ekleyin**: Kalıcı bir örnek tutmak için İşlemci'yi değiştirin +4. **Etiket önbelleklemesini uygulayın**: GraphRag sınıfına TTL ile LRU (En Son Kullanılan) önbelleği ekleyin +>>>>>>> 82edf2d (New md files from RunPod) ### 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 @@ -599,7 +680,11 @@ API'lerin değişmesine izin verildiğinden, geçiş karmaşıklığı olmadan d **1. Hafta: Temel Uygulama** `follow_edges`'ı toplu yinelemeli gezinmeyle değiştirin +<<<<<<< HEAD `get_labelgraph` içinde paralel etiket çözümlemeyi uygulayın +======= +`get_labelgraph` içinde paralel etiket çözümlemesini uygulayın +>>>>>>> 82edf2d (New md files from RunPod) İşlemci'ye uzun ömürlü GraphRag örneği ekleyin Etiket önbellekleme katmanı uygulayın @@ -612,7 +697,11 @@ Kod incelemesi ve optimizasyon **3. Hafta: Dağıtım** Optimize edilmiş uygulamayı dağıtın Performans iyileştirmelerini izleyin +<<<<<<< HEAD Gerçek kullanım temelinde önbellek TTL'sini ve toplu boyutları ayarlayın +======= +Gerçek kullanım bazında önbellek TTL'sini ve toplu boyutları ayarlayın +>>>>>>> 82edf2d (New md files from RunPod) ## Açık Sorular diff --git a/docs/tech-specs/graphrag-performance-optimization.zh-cn.md b/docs/tech-specs/graphrag-performance-optimization.zh-cn.md index 3c26c71d..b434f49d 100644 --- a/docs/tech-specs/graphrag-performance-optimization.zh-cn.md +++ b/docs/tech-specs/graphrag-performance-optimization.zh-cn.md @@ -13,7 +13,11 @@ **减少数据库查询量**: 通过批量和缓存,实现总数据库查询量减少 50-80% **提高响应时间**: 目标是子图构建速度提高 3-5 倍,标签解析速度提高 2-3 倍 +<<<<<<< HEAD **增强可扩展性**: 更好地管理内存,支持更大的知识图谱 +======= +**增强可扩展性**: 通过更好的内存管理,支持更大的知识图谱 +>>>>>>> 82edf2d (New md files from RunPod) **保持准确性**: 保持现有的 GraphRAG 功能和结果质量 **启用并发性**: 提高并行处理能力,以支持多个并发请求 **减少内存占用**: 实现高效的数据结构和内存管理 @@ -70,11 +74,19 @@ **响应时间**: 中等大小图的响应时间为15-30秒 **内存使用**: 缓存会随着时间增长 **缓存有效性**: 0% - 每次请求都会重置缓存 +<<<<<<< HEAD **对象创建开销**: 每个请求都会创建/销毁GraphRag + Query对象 本规范通过实现批量查询、智能缓存和并行处理来解决这些问题。通过优化查询模式和数据访问,TrustGraph可以: 支持拥有数百万个实体的企业级知识图谱 为典型的查询提供亚秒级的响应时间 +======= +**对象创建开销**: 每个请求会创建/销毁GraphRag + Query对象 + +本规范通过实现批量查询、智能缓存和并行处理来解决这些问题。通过优化查询模式和数据访问,TrustGraph可以: +支持拥有数百万个实体的企业级知识图谱 +为典型查询提供亚秒级的响应时间 +>>>>>>> 82edf2d (New md files from RunPod) 处理数百个并发的GraphRAG请求 随着图的大小和复杂性而高效扩展 @@ -142,7 +154,11 @@ class TraversalState: ``` 这种方法允许: +<<<<<<< HEAD 通过跟踪访问的实体实现高效的循环检测 +======= +通过跟踪访问过的实体实现高效的循环检测 +>>>>>>> 82edf2d (New md files from RunPod) 在每个遍历层级进行批量查询准备 内存效率高的状态管理 当达到大小限制时,可以提前终止 @@ -213,6 +229,7 @@ class CacheManager: #### 修改后的 API: **GraphRag.query()** - 增强了性能优化: +<<<<<<< HEAD 添加了 cache_manager 参数以进行缓存控制 包含 performance_metrics 返回值 添加了 query_timeout 参数以提高可靠性 @@ -220,6 +237,15 @@ class CacheManager: **Query 类** - 进行了重构,用于批量处理: 将单个实体处理替换为批量操作 添加了异步上下文管理器以进行资源清理 +======= +添加 `cache_manager` 参数以进行缓存控制 +包含 `performance_metrics` 返回值 +添加 `query_timeout` 参数以提高可靠性 + +**Query 类** - 重新设计,用于批量处理: +将单个实体处理替换为批量操作 +添加异步上下文管理器以进行资源清理 +>>>>>>> 82edf2d (New md files from RunPod) 包含进度回调函数,用于长时间运行的操作 ### 实施细节 @@ -250,7 +276,11 @@ class GraphRag: # q automatically destroyed when function exits ``` +<<<<<<< HEAD **优化后的长期运行架构:** +======= +**优化后的长寿命架构:** +>>>>>>> 82edf2d (New md files from RunPod) ```python class Processor(FlowProcessor): def __init__(self, **params): @@ -320,9 +350,15 @@ class QueryExecutor: return await self.rag.execute_optimized_query(query, self.context) ``` +<<<<<<< HEAD 这种架构上的改变提供了: **对于具有常见关系的图,数据库查询减少 10-20%**(相对于目前 0% 的减少) **消除了每个请求中的对象创建开销** +======= +这一架构变更提供了: +**对于具有常见关系的图,数据库查询减少 10-20%**(相对于目前 0% 的减少) +**消除了每个请求的对象的创建开销** +>>>>>>> 82edf2d (New md files from RunPod) **持久连接池和客户端重用** **缓存 TTL 窗口内的跨请求优化** @@ -390,7 +426,11 @@ for edge in subgraph: o = await self.maybe_label(edge[2]) # Individual query ``` +<<<<<<< HEAD **优化后的并行实现:** +======= +**优化并行实现:** +>>>>>>> 82edf2d (New md files from RunPod) ```python async def resolve_labels_parallel(self, subgraph: List[Triple]) -> List[Triple]: # Collect all unique entities needing labels @@ -487,10 +527,17 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **缓解策略:** **保守的 TTL 值**:在性能提升 (10-20%) 和数据新鲜度之间取得平衡。 **缓存失效钩子**:可选地与图的修改事件集成。 +<<<<<<< HEAD **监控仪表板**:跟踪缓存命中率与数据时效性事件。 **可配置的缓存策略**:允许根据修改频率进行按部署的调整。 **根据图修改速率推荐的缓存配置:** +======= +**监控仪表板**:跟踪缓存命中率与数据陈旧事件。 +**可配置的缓存策略**:允许根据修改频率进行按部署的调整。 + +**基于图修改速率的推荐缓存配置:** +>>>>>>> 82edf2d (New md files from RunPod) **高修改速率 (>100 次/小时)**:TTL=60 秒,较小的缓存大小。 **中等修改速率 (10-100 次/小时)**:TTL=300 秒 (默认值)。 **低修改速率 (<10 次/小时)**:TTL=600 秒,较大的缓存大小。 @@ -517,8 +564,13 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): ### 预期的性能提升 **查询减少:** +<<<<<<< HEAD 当前:典型请求需要 ~9,000+ 次查询。 优化后:~50-100 个批处理查询 (减少 98%)。 +======= +当前:典型请求约 9,000+ 个查询。 +优化后:约 50-100 个批处理查询 (减少 98%)。 +>>>>>>> 82edf2d (New md files from RunPod) **响应时间改进:** 图遍历:15-20 秒 → 3-5 秒 (快 4-5 倍)。 @@ -527,7 +579,11 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **内存效率:** 限制的缓存大小可防止内存泄漏。 +<<<<<<< HEAD 高效的数据结构可减少内存占用 ~40%。 +======= +高效的数据结构可将内存占用减少约 40%。 +>>>>>>> 82edf2d (New md files from RunPod) 通过适当的资源清理实现更好的垃圾回收。 **现实的性能期望:** @@ -549,13 +605,21 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): 数据库连接池利用率。 内存使用情况和垃圾回收影响。 +<<<<<<< HEAD **性能基准测试 (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ì) +======= +**性能基准测试:** +自动化性能回归测试 +使用真实数据量的负载测试 +与当前实现相比的基准测试 +>>>>>>> 82edf2d (New md files from RunPod) ## 测试策略 (Cèshì Cèlüè) +<<<<<<< HEAD ### 单元测试 (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ì) @@ -578,9 +642,34 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): 验证现有 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) +======= +### 单元测试 +对遍历、缓存和标签解析的各个组件进行测试 +模拟数据库交互以进行性能测试 +缓存驱逐和 TTL 过期测试 +错误处理和超时场景 + +### 集成测试 +使用优化后的 GraphRAG 查询进行端到端测试 +使用真实数据进行数据库交互测试 +并发请求处理和资源管理 +内存泄漏检测和资源清理验证 + +### 性能测试 +与当前实现相比的基准测试 +使用不同大小和复杂度的图进行负载测试 +压力测试以检查内存和连接限制 +针对性能改进进行的回归测试 + +### 兼容性测试 +验证现有 GraphRAG API 的兼容性 +使用各种图数据库后端进行测试 +验证与当前实现相比的结果准确性 +>>>>>>> 82edf2d (New md files from RunPod) ## 实施计划 (Shíshī Jìhuà) +<<<<<<< HEAD ### 直接实施方法 (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à:) @@ -594,9 +683,25 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): **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) +======= +### 直接实施方法 +由于允许 API 更改,因此无需迁移复杂性,可以直接实现优化: + +1. **替换 `follow_edges` 方法**: 使用迭代批量遍历重写 +2. **优化 `get_labelgraph`**: 实现并行标签解析 +3. **添加长期 GraphRag**: 修改 Processor 以维护持久实例 +4. **实现标签缓存**: 为 GraphRag 类添加 LRU 缓存和 TTL + +### 变更范围 +**查询类**: 替换 `follow_edges` 中的约 50 行代码,添加约 30 行批量处理代码 +**GraphRag 类**: 添加缓存层(约 40 行代码) +**Processor 类**: 修改为使用持久的 GraphRag 实例(约 20 行代码) +**总计**: 约 140 行代码的集中性变更,主要在现有类中 +>>>>>>> 82edf2d (New md files from RunPod) ## 时间线 (Shíjiān Xiàn) +<<<<<<< HEAD **第一周: 核心实施 (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ì) @@ -613,9 +718,28 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): 部署优化后的实现 (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) +======= +**第一周:核心实施** +使用批量迭代遍历替换 `follow_edges` +在 `get_labelgraph` 中实现并行标签解析 +在 Processor 中添加长期 GraphRag 实例 +实现标签缓存层 + +**第二周:测试和集成** +对新的遍历和缓存逻辑进行单元测试 +与当前实现相比的性能基准测试 +使用真实图数据的集成测试 +代码审查和优化 + +**第三周:部署** +部署优化的实现 +监控性能改进 +根据实际使用情况微调缓存 TTL 和批次大小 +>>>>>>> 82edf2d (New md files from RunPod) ## 开放性问题 (Kāifàng Xìng Wèntí) +<<<<<<< HEAD **数据库连接池 (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ǔ?) @@ -627,3 +751,16 @@ async def execute_with_timeout(self, query_func, timeout: int = 30): GraphRAG API 文档 (GraphRAG API 文档) 示例代码 (Lìmiàn dàimǎ) 相关论文 (Xiāngguān lùnwén) +======= +**数据库连接池**: 我们应该实现自定义连接池,还是依赖于现有的数据库客户端池? +**缓存持久性**: 标签和嵌入式缓存是否应该在服务重启后持久存在? +**分布式缓存**: 对于多实例部署,我们是否应该实现使用 Redis/Memcached 的分布式缓存? +**查询结果格式**: 我们是否应该优化内部三元组表示以获得更好的内存效率? +**监控集成**: 哪些指标应该暴露给现有的监控系统(Prometheus 等)? + +## 参考文献 + +[GraphRAG 原始实现](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py) +[TrustGraph 架构原则](architecture-principles.md) +[集合管理规范](collection-management.md) +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/import-export-graceful-shutdown.ar.md b/docs/tech-specs/import-export-graceful-shutdown.ar.md index c5c9b9f0..1cb221e6 100644 --- a/docs/tech-specs/import-export-graceful-shutdown.ar.md +++ b/docs/tech-specs/import-export-graceful-shutdown.ar.md @@ -25,7 +25,11 @@ Export Flow: Pulsar Queue -> Subscriber -> TriplesExport -> Websocket -> Client ``` +<<<<<<< HEAD ## التحسينات المقترحة +======= +## الحلول المقترحة +>>>>>>> 82edf2d (New md files from RunPod) ### 1. تحسينات الناشر (جانب الاستيراد) @@ -142,7 +146,11 @@ class Publisher: **المزايا الرئيسية للتصميم:** **موقع إرسال واحد**: جميع استدعاءات `producer.send()` تحدث في مكان واحد داخل الطريقة `run()`. +<<<<<<< HEAD **آلة حالة واضحة:** ثلاثة حالات واضحة - قيد التشغيل، في مرحلة التفريغ، متوقفة. +======= +**آلة حالة واضحة:** ثلاثة حالات واضحة - قيد التشغيل، في طور التفريغ، متوقفة. +>>>>>>> 82edf2d (New md files from RunPod) **حماية من المهلة الزمنية:** لن تتعطل بشكل دائم أثناء التفريغ. **إمكانية مراقبة أفضل:** تسجيل واضح لتقدم التفريغ والانتقالات بين الحالات. **رفض الرسائل الاختياري:** يمكن رفض الرسائل الجديدة أثناء مرحلة الإغلاق. @@ -362,10 +370,17 @@ class Subscriber: ``` **المزايا الرئيسية للتصميم (مطابقة لنمط الناشر):** +<<<<<<< HEAD **موقع معالجة واحد:** تتم جميع عمليات معالجة الرسائل في الطريقة `run()`. **آلة حالة واضحة:** ثلاثة حالات واضحة - قيد التشغيل، في مرحلة التفريغ، متوقفة. **الإيقاف المؤقت أثناء التفريغ:** تتوقف عن قبول رسائل جديدة من Pulsar أثناء تفريغ قوائم الانتظار الحالية. **حماية ضد المهلة:** لن تتعطل إلى أجل غير مسمى أثناء التفريغ. +======= +**موقع معالجة واحد:** تتم معالجة جميع الرسائل في الطريقة `run()`. +**آلة حالة واضحة:** ثلاثة حالات واضحة - قيد التشغيل، في مرحلة التفريغ، متوقفة. +**الإيقاف المؤقت أثناء التفريغ:** تتوقف عن قبول رسائل جديدة من Pulsar أثناء تفريغ قوائم الانتظار الحالية. +**حماية المهلة الزمنية:** لن تتعطل إلى أجل غير مسمى أثناء التفريغ. +>>>>>>> 82edf2d (New md files from RunPod) **تنظيف صحيح:** تعترف بأي رسائل لم يتم تسليمها على الإغلاق. #### ب. تحسينات معالج التصدير @@ -637,7 +652,11 @@ async def test_export_no_message_loss(): النشر في بيئة الاختبار ### المرحلة الثانية: الإغلاق التدريجي (الأسبوع الثاني) +<<<<<<< HEAD تطبيق تنسيق الإغلاق +======= +تطبيق التنسيق للإغلاق +>>>>>>> 82edf2d (New md files from RunPod) إضافة استراتيجيات الضغط العكسي اختبار الأداء @@ -670,7 +689,11 @@ async def test_export_no_message_loss(): ## اعتبارات الأمان +<<<<<<< HEAD لم يتم إدخال مسارات هجوم جديدة +======= +لم يتم تقديم مسارات هجوم جديدة +>>>>>>> 82edf2d (New md files from RunPod) يمنع الضغط العكسي هجمات استنفاد الذاكرة تمنع الحدود القابلة للتكوين إساءة استخدام الموارد @@ -678,5 +701,9 @@ async def test_export_no_message_loss(): تكلفة إضافية قليلة أثناء التشغيل العادي قد يستغرق الإغلاق ما يصل إلى 5 ثوانٍ إضافية (قابل للتكوين) +<<<<<<< HEAD يحد استخدام الذاكرة من خلال حدود حجم قائمة الانتظار +======= +استخدام الذاكرة محدود بحدود حجم قائمة الانتظار +>>>>>>> 82edf2d (New md files from RunPod) التأثير على وحدة المعالجة المركزية ضئيل (<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 index 803f9195..bfeb74aa 100644 --- a/docs/tech-specs/import-export-graceful-shutdown.es.md +++ b/docs/tech-specs/import-export-graceful-shutdown.es.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD # Especificación Técnica para el Cierre de Sesión Gratuito de Importación/Exportación ## Declaración del Problema @@ -10,6 +11,20 @@ Actualmente, la puerta de enlace TrustGraph experimenta pérdida de mensajes dur 3. No hay un mecanismo de confirmación para la entrega exitosa de mensajes. ### Problemas del Lado de Exportación +======= +# Especificación Técnica para el Cierre 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 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 de Pulsar para importaciones, clientes de WebSocket para exportaciones). + +### Problemas del Lado de la Importación +1. El búfer de la cola asyncio del publicador no se vacía durante el apagado. +2. El 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 la Exportación +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -362,11 +377,19 @@ class Subscriber: ``` **Beneficios clave del diseño (que coinciden con el patrón del editor):** +<<<<<<< HEAD **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. +======= +**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 +>>>>>>> 82edf2d (New md files from RunPod) #### B. Mejoras del controlador de exportación @@ -634,7 +657,11 @@ async def test_export_no_message_loss(): ### 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 +<<<<<<< HEAD Implementar en el entorno de pruebas +======= +Desplegar en el entorno de pruebas +>>>>>>> 82edf2d (New md files from RunPod) ### Fase 2: Cierre Gratuito (Semana 2) Implementar la coordinación del cierre @@ -652,7 +679,11 @@ Ajustar los valores de tiempo de espera según los datos de producción `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 +<<<<<<< HEAD `websocket.graceful_shutdowns` - Cierres gratuitos exitosos +======= +`websocket.graceful_shutdowns` - Cierres suaves exitosos +>>>>>>> 82edf2d (New md files from RunPod) `websocket.forced_shutdowns` - Cierres forzados/por tiempo de espera ### Alertas @@ -665,7 +696,11 @@ Tiempo de espera del cierre excedido Todos los cambios mantienen la compatibilidad con versiones anteriores: El comportamiento predeterminado no cambia sin configuración +<<<<<<< HEAD Las implementaciones existentes continúan funcionando +======= +Los despliegues existentes continúan funcionando +>>>>>>> 82edf2d (New md files from RunPod) Degradación gradual si las nuevas funciones no están disponibles ## Consideraciones de Seguridad diff --git a/docs/tech-specs/import-export-graceful-shutdown.he.md b/docs/tech-specs/import-export-graceful-shutdown.he.md index 6d92cdf4..fed5d80b 100644 --- a/docs/tech-specs/import-export-graceful-shutdown.he.md +++ b/docs/tech-specs/import-export-graceful-shutdown.he.md @@ -2,7 +2,11 @@ ## הצהרת בעיה +<<<<<<< HEAD שער TrustGraph חווה כרגע אובדן הודעות במהלך סגירת WebSocket בפעולות ייבוא ויצוא כאחד. זה קורה עקב מצבי מירוץ שבהם הודעות בתנועה נזרקות לפני שהן מגיעות ליעדים שלהן (תורי Pulsar לייבוא, לקוחות WebSocket לייצוא). +======= +שער TrustGraph חווה כרגע אובדן הודעות במהלך סגירת WebSocket בפעולות ייבוא ויצוא כאחד. זה קורה עקב מצבי מירוץ שבהם הודעות בתנועה נזרקות לפני שהן מגיעות ליעדים שלהן (תורי Pulsar עבור ייבוא, לקוחות WebSocket עבור יצוא). +>>>>>>> 82edf2d (New md files from RunPod) ### בעיות בצד הייבוא 1. מאגר ה-asyncio.Queue של המפרסם אינו מרוקן במהלך השבתה. @@ -143,7 +147,11 @@ class Publisher: **יתרונות עיצוב מרכזיים:** **מיקום שליחה יחיד**: כל הקריאות ל-`producer.send()` מתרחשות במקום אחד בתוך השיטה `run()`. **מצב פעולה ברור:** שלושה מצבים ברורים - פעיל, ריקון, עצור. +<<<<<<< HEAD **הגנה מפני תזמון מוגזם:** לא יימשך ללא הגבלת זמן במהלך הריקון. +======= +**הגנה מפני תזמון מוגזם:** לא יימשך ללא סוף במהלך הריקון. +>>>>>>> 82edf2d (New md files from RunPod) **יכולת ניטור משופרת:** רישום ברור של התקדמות הריקון ומעברי מצב. **דחיית הודעות אופציונלית:** ניתן לדחות הודעות חדשות במהלך שלב השבתה. @@ -171,7 +179,11 @@ class TriplesImport: #### א. תבנית ניקוז משולבת +<<<<<<< HEAD **קובץ**: `trustgraph-base/trustgraph/base/subscriber.py` +======= +**קובץ:** `trustgraph-base/trustgraph/base/subscriber.py` +>>>>>>> 82edf2d (New md files from RunPod) ```python class Subscriber: @@ -362,10 +374,17 @@ class Subscriber: ``` **יתרונות עיצוב מרכזיים (התאמה לדפוס של המפרסם):** +<<<<<<< HEAD **מיקום עיבוד יחיד**: כל עיבוד ההודעות מתבצע בשיטה `run()`. **מצב מכונה נקי**: שלושה מצבים ברורים - פעיל, ריקון, עצור. **השהיה במהלך ריקון**: מפסיק לקבל הודעות חדשות מ-Pulsar תוך כדי ריקון תורים קיימים. **הגנה מפני תזמון מוגזם**: לא ייקפא ללא סיבה במהלך הריקון. +======= +**מיקום עיבוד יחיד**: כל פעולות העיבוד של ההודעות מתבצעות בשיטה `run()`. +**מצב מכונה נקי**: שלושה מצבים ברורים - פעיל, ריקון, עצור. +**השהיה במהלך הריקון**: מפסיק לקבל הודעות חדשות מ-Pulsar תוך כדי ריקון תורים קיימים. +**הגנה מפני תקיעות**: לא ייגרם תקיעה אינסופי במהלך הריקון. +>>>>>>> 82edf2d (New md files from RunPod) **ניקוי תקין**: מודה בשלילה על כל הודעות שלא נמסרו בעת השבתה. #### ב. שיפורים למטפל ייצוא @@ -679,4 +698,8 @@ async def test_export_no_message_loss(): תקורה מינימלית במהלך פעולה רגילה השבתה עשויה לקחת עד 5 שניות נוספות (ניתן להגדרה) השימוש בזיכרון מוגבל על ידי מגבלות גודל התור -השפעה על ה-CPU זניחה (<1% עלייה) \ No newline at end of file +<<<<<<< HEAD +השפעה על ה-CPU זניחה (<1% עלייה) +======= +השפעה על מעבד זניחה (<1% עלייה) +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/import-export-graceful-shutdown.hi.md b/docs/tech-specs/import-export-graceful-shutdown.hi.md index e5957e50..cfbd5657 100644 --- a/docs/tech-specs/import-export-graceful-shutdown.hi.md +++ b/docs/tech-specs/import-export-graceful-shutdown.hi.md @@ -2,7 +2,11 @@ ## समस्या विवरण +<<<<<<< HEAD ट्रस्टग्राफ गेटवे वर्तमान में आयात और निर्यात दोनों कार्यों के दौरान वेबसॉकेट बंद होने के समय संदेश हानि का अनुभव करता है। यह दौड़ की स्थितियों के कारण होता है जहां पारगमन में मौजूद संदेश अपने गंतव्य (आयात के लिए पल्सर कतारों, निर्यात के लिए वेबसॉकेट क्लाइंट) तक पहुंचने से पहले त्याग दिए जाते हैं। +======= +ट्रस्टग्राफ गेटवे वर्तमान में आयात और निर्यात दोनों कार्यों के दौरान वेबसॉकेट बंद होने के समय संदेशों के खो जाने की समस्या का सामना करता है। यह दौड़ की स्थितियों के कारण होता है, जिसमें रास्ते में मौजूद संदेशों को उनके गंतव्य (आयात के लिए पल्सर कतारों, निर्यात के लिए वेबसॉकेट क्लाइंट) तक पहुंचने से पहले त्याग दिया जाता है। +>>>>>>> 82edf2d (New md files from RunPod) ### आयात-पक्ष की समस्याएं 1. प्रकाशक का asyncio.Queue बफर शटडाउन पर खाली नहीं होता है। @@ -13,7 +17,11 @@ 1. संदेशों को क्लाइंट को सफलतापूर्वक वितरित होने से पहले पल्सर में स्वीकार किया जाता है। 2. हार्ड-कोडेड टाइमआउट के कारण संदेश ड्रॉप हो जाते हैं जब कतारें भरी होती हैं। 3. धीमी उपभोक्ताओं को संभालने के लिए कोई बैकप्रेशर तंत्र नहीं है। +<<<<<<< HEAD 4. कई बफर बिंदु जहां डेटा खो सकता है। +======= +4. कई बफर बिंदु हैं जहां डेटा खो सकता है। +>>>>>>> 82edf2d (New md files from RunPod) ## वास्तुकला अवलोकन @@ -361,12 +369,20 @@ class Subscriber: return False ``` +<<<<<<< HEAD **मुख्य डिज़ाइन लाभ (प्रकाशक पैटर्न से मेल खाता):** +======= +**मुख्य डिज़ाइन लाभ (प्रकाशक पैटर्न से मेल खाता है):** +>>>>>>> 82edf2d (New md files from RunPod) **एकल प्रसंस्करण स्थान**: सभी संदेश प्रसंस्करण `run()` विधि में होता है। **स्वच्छ स्टेट मशीन**: तीन स्पष्ट अवस्थाएँ - चल रही, खाली करने की प्रक्रिया में, बंद। **खाली करते समय विराम**: मौजूदा कतारों को खाली करते समय, पल्सर से नए संदेश स्वीकार करना बंद हो जाता है। **समय-सीमा सुरक्षा**: खाली करने की प्रक्रिया के दौरान अनिश्चित काल तक नहीं रुकेगा। +<<<<<<< HEAD **उचित सफाई**: शटडाउन पर, किसी भी अप्राप्त संदेश को नकारात्मक रूप से स्वीकार किया जाता है। +======= +**उचित सफाई**: शटडाउन पर किसी भी अप्राप्त संदेश को नकारात्मक रूप से स्वीकार करता है। +>>>>>>> 82edf2d (New md files from RunPod) #### बी. एक्सपोर्ट हैंडलर में सुधार @@ -436,7 +452,11 @@ class TriplesExport: # Graceful cleanup handled in destroy() ``` +<<<<<<< HEAD ### 3. सॉकेट-स्तरीय सुधार +======= +### 3. सॉकेट-स्तर में सुधार +>>>>>>> 82edf2d (New md files from RunPod) **फ़ाइल**: `trustgraph-flow/trustgraph/gateway/endpoint/socket.py` @@ -539,7 +559,11 @@ class GracefulShutdownConfig: ## परीक्षण रणनीति +<<<<<<< HEAD ### यूनिट परीक्षण +======= +### इकाई परीक्षण +>>>>>>> 82edf2d (New md files from RunPod) ```python async def test_publisher_queue_drain(): @@ -575,7 +599,11 @@ async def test_subscriber_deferred_ack(): assert not msg.acknowledge.called ``` +<<<<<<< HEAD ### एकीकरण परीक्षण (एकीकरण परीक्षण) +======= +### एकीकरण परीक्षण +>>>>>>> 82edf2d (New md files from RunPod) ```python async def test_import_graceful_shutdown(): diff --git a/docs/tech-specs/import-export-graceful-shutdown.pt.md b/docs/tech-specs/import-export-graceful-shutdown.pt.md index bfbb250d..8a154e20 100644 --- a/docs/tech-specs/import-export-graceful-shutdown.pt.md +++ b/docs/tech-specs/import-export-graceful-shutdown.pt.md @@ -141,7 +141,11 @@ class Publisher: ``` **Principais Vantagens do Design:** +<<<<<<< HEAD **Local de Envio Único**: Todas as chamadas de `producer.send()` ocorrem em um único local dentro do método `run()`. +======= +**Local de Envio Único**: Todas as chamadas `producer.send()` ocorrem em um único local dentro do método `run()`. +>>>>>>> 82edf2d (New md files from RunPod) **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. @@ -361,11 +365,19 @@ class Subscriber: return False ``` +<<<<<<< HEAD **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 +======= +**Principais Vantagens do Design (compatível com o padrão do Publicador):** +**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 bloqueado durante o esvaziamento +>>>>>>> 82edf2d (New md files from RunPod) **Limpeza Adequada**: Reconhece negativamente quaisquer mensagens não entregues durante o desligamento #### B. Melhorias no Manipulador de Exportação @@ -637,7 +649,11 @@ Adicionar esvaziamento da fila do publicador Implantar no ambiente de teste ### Fase 2: Desligamento Gradual (Semana 2) +<<<<<<< HEAD Implementar coordenação de desligamento +======= +Implementar a coordenação de desligamento +>>>>>>> 82edf2d (New md files from RunPod) Adicionar estratégias de backpressure Testes de desempenho @@ -672,7 +688,11 @@ Degradação gradual se novos recursos não estiverem disponíveis Nenhum novo vetor de ataque introduzido O backpressure impede ataques de esgotamento de memória +<<<<<<< HEAD Limites configuráveis ​​evitam o abuso de recursos +======= +Limites configuráveis evitam o abuso de recursos +>>>>>>> 82edf2d (New md files from RunPod) ## Impacto no Desempenho diff --git a/docs/tech-specs/import-export-graceful-shutdown.ru.md b/docs/tech-specs/import-export-graceful-shutdown.ru.md index 4f1a0708..63f6fe68 100644 --- a/docs/tech-specs/import-export-graceful-shutdown.ru.md +++ b/docs/tech-specs/import-export-graceful-shutdown.ru.md @@ -362,11 +362,19 @@ class Subscriber: ``` **Основные преимущества дизайна (соответствие шаблону издателя):** +<<<<<<< HEAD **Единое место обработки сообщений**: Вся обработка сообщений происходит в методе `run()` **Чистая конечная машина состояний**: Три четких состояния - работа, слив, остановка **Приостановка во время слива**: Прекращает прием новых сообщений из Pulsar во время слива существующих очередей **Защита от таймаутов**: Не зависнет бесконечно во время слива **Правильная очистка**: Отправляет отрицательные подтверждения для любых неотправленных сообщений при завершении работы +======= +**Единое место обработки сообщений**: Вся обработка сообщений происходит в методе `run()`. +**Чистый конечный автомат**: Три четких состояния - работа, слив, остановка. +**Приостановка во время слива**: Прекращает прием новых сообщений из Pulsar во время слива существующих очередей. +**Защита от таймаутов**: Не зависнет бесконечно во время слива. +**Правильная очистка**: Отправляет отрицательные подтверждения для любых неотправленных сообщений при завершении работы. +>>>>>>> 82edf2d (New md files from RunPod) #### B. Улучшения обработчика экспорта @@ -631,17 +639,29 @@ async def test_export_no_message_loss(): ## План внедрения +<<<<<<< HEAD ### Фаза 1: Критические исправления (Неделя 1) +======= +### Этап 1: Критические исправления (Неделя 1) +>>>>>>> 82edf2d (New md files from RunPod) Исправить время подтверждения подписки (предотвратить потерю сообщений) Добавить очистку очереди издателя Развернуть в тестовой среде +<<<<<<< HEAD ### Фаза 2: Плавное завершение работы (Неделя 2) +======= +### Этап 2: Плавное завершение работы (Неделя 2) +>>>>>>> 82edf2d (New md files from RunPod) Реализовать координацию завершения работы Добавить стратегии обратной связи Тестирование производительности +<<<<<<< HEAD ### Фаза 3: Мониторинг и настройка (Неделя 3) +======= +### Этап 3: Мониторинг и настройка (Неделя 3) +>>>>>>> 82edf2d (New md files from RunPod) Добавить метрики для глубины очередей Добавить оповещения о потере сообщений Настроить значения тайм-аутов на основе данных производственной среды @@ -663,10 +683,17 @@ async def test_export_no_message_loss(): ## Обратная совместимость +<<<<<<< HEAD Все изменения сохраняют обратную совместимость: Поведение по умолчанию не изменено без конфигурации Существующие развертывания продолжают работать Плавное снижение производительности в случае недоступности новых функций +======= +Все изменения поддерживают обратную совместимость: +Поведение по умолчанию не изменено без конфигурации +Существующие развертывания продолжают работать +Плавное снижение функциональности в случае недоступности новых функций +>>>>>>> 82edf2d (New md files from RunPod) ## Вопросы безопасности diff --git a/docs/tech-specs/import-export-graceful-shutdown.sw.md b/docs/tech-specs/import-export-graceful-shutdown.sw.md index cbb1b54f..229d1eca 100644 --- a/docs/tech-specs/import-export-graceful-shutdown.sw.md +++ b/docs/tech-specs/import-export-graceful-shutdown.sw.md @@ -7,12 +7,21 @@ Hivi sasa, mlango wa TrustGraph unapoteza ujumbe wakati wa kufunga muunganisho w ### 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. +<<<<<<< HEAD 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. +======= +3. Hakuna mfumo wa utambuzi kwa uwasilishaji wa ujumbe unaofanikiwa. + +### Masuala ya Upande wa Kukomesha Kazi +1. Ujumbe hutambuliwa 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) kwa kushughulikia watumiaji (consumers) ambao ni polepole. +>>>>>>> 82edf2d (New md files from RunPod) 4. Vituo vingi vya kuhifadhi ambapo data inaweza kupotea. ## Muhtasari wa Muundo @@ -142,10 +151,17 @@ class Publisher: **Manufaa Muhimu ya Ubunifu:** **Eneo Moja la Kutuma:** Wito wote wa `producer.send()` hutokea katika sehemu moja ndani ya mbinu ya `run()`. +<<<<<<< HEAD **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. +======= +**Mashine ya Hali Safi:** Hali tatu wazi - inafanya kazi, inachosha, imesimama. +**Ulinzi wa Muda:** Haitemei kwa muda usio na kikomo wakati wa kuchosha. +**Ufuatiliaji Bora:** Uandikaji wazi wa maendeleo ya kuchosha na mabadiliko ya hali. +**Kukataa Ujumbe wa Hiari:** Inaweza kukataa ujumbe mpya wakati wa awamu ya kuzima. +>>>>>>> 82edf2d (New md files from RunPod) #### B. Mpangilio Ulioboreshwa wa Kuzima @@ -363,9 +379,15 @@ class Subscriber: **Manufaa Muhimu ya Ubunifu (kulingana na mtindo wa Mchapishaji):** **Eneo Moja la Ufuatiliaji**: Ufuatiliaji wote wa ujumbe hutokea katika njia ya `run()` +<<<<<<< HEAD **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 +======= +**Mashine ya Hali Safi**: Hali tatu wazi - inafanya kazi, inatakatishwa, imesimama +**Kusitisha Wakati wa Kufyatua**: Inasimamisha kupokea ujumbe mpya kutoka Pulsar wakati wa kufyatua folyo zilizopo +**Ulinzi wa Muda**: Haingii katika hali ya kukamatwa kwa muda usio na kikomo wakati wa kufyatua +>>>>>>> 82edf2d (New md files from RunPod) **Usafi Sawa**: Inatambua vibaya ujumbe wowote usiofikishwa wakati wa kuzima #### B. Maboresho ya Kidhibiti cha Uhamisho @@ -629,16 +651,28 @@ async def test_export_no_message_loss(): assert len(received) >= 50 ``` +<<<<<<< HEAD ## Mpango wa Utendaji +======= +## Mpango wa Utumizaji +>>>>>>> 82edf2d (New md files from RunPod) ### 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 +<<<<<<< HEAD Tuma kwenye mazingira ya majaribio ### Awamu ya 2: Kusitisha kwa Ufasaha (Wiki ya 2) Lenga kusitisha kwa ufasaha Ongeza mikakati ya shinikizo nyuma +======= +Toa toleo kwenye mazingira ya majaribio + +### Awamu ya 2: Kusitisha kwa Ufasaha (Wiki ya 2) +Lenga utaratibu wa usitishaji +Ongeza mikakati ya kupunguza mzigo +>>>>>>> 82edf2d (New md files from RunPod) Vipimo vya utendaji ### Awamu ya 3: Ufuatiliaji na Urekebishaji (Wiki ya 3) @@ -652,14 +686,23 @@ Rekebisha maadili ya muda wa kusubiri kulingana na data ya uzalishaji `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 +<<<<<<< HEAD `websocket.graceful_shutdowns` - Kusitisha kwa ufasaha ambavyo vimefanikiwa `websocket.forced_shutdowns` - Kusitisha kwa nguvu/kwa muda mrefu +======= +`websocket.graceful_shutdowns` - Usitishaji wa ufasaha ambao umefanikiwa +`websocket.forced_shutdowns` - Usitishaji wa lazima/wa muda +>>>>>>> 82edf2d (New md files from RunPod) ### Arifa Kina cha folyo ya mchapishaji > 80% ya uwezo Upotevu wowote wa ujumbe wakati wa kusitisha Kiwango cha kukataa cha mshabiki > 1% +<<<<<<< HEAD Muda wa kusitisha umepita +======= +Muda wa kusitisha ambao umevuka +>>>>>>> 82edf2d (New md files from RunPod) ## Ulinganifu na Mifumo ya Zamani @@ -671,8 +714,13 @@ Kupungua kwa utendaji ikiwa vipengele vipya havipatikani ## Masuala ya Usalama Vipengele vipya vya mashambulizi haviongezwi +<<<<<<< HEAD Shinikizo nyuma huzuia mashambulizi ya kutumia kumbukumbu nyingi Mipaka inayoweza kusanidiwa huzuia matumizi mabaya ya rasilimali +======= +Kupunguza mzigo huzuia mashambulizi ya kutokwa na kumbukumbu +Mipaka inayoweza kusanidiwa inazuia unyonyaji wa rasilimali +>>>>>>> 82edf2d (New md files from RunPod) ## Athari za Utendaji diff --git a/docs/tech-specs/import-export-graceful-shutdown.tr.md b/docs/tech-specs/import-export-graceful-shutdown.tr.md index 6dc2e997..29cac7aa 100644 --- a/docs/tech-specs/import-export-graceful-shutdown.tr.md +++ b/docs/tech-specs/import-export-graceful-shutdown.tr.md @@ -2,10 +2,17 @@ ## Problem Tanımı +<<<<<<< HEAD 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. +======= +TrustGraph geçidi, hem içe hem de dışa aktarma işlemlerinde websocket kapanması 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, kapanmada boşaltılmamaktadır. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -13,7 +20,11 @@ TrustGraph ağ geçidi, hem içe aktarma hem de dışa aktarma işlemlerinde web 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. +<<<<<<< HEAD 4. Verilerin kaybolabileceği birden fazla tampon noktası bulunmaktadır. +======= +4. Verilerin kaybolabileceği birden fazla tamponlama noktası bulunmaktadır. +>>>>>>> 82edf2d (New md files from RunPod) ## Mimari Genel Bakış @@ -145,7 +156,11 @@ class Publisher: **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. +<<<<<<< HEAD **İsteğe Bağlı Mesaj Reddi**: Kapatma aşamasında yeni mesajları reddedebilir. +======= +**İsteğe Bağlı Mesaj Reddi**: Kapatma aşamasında yeni mesajları reddetme imkanı. +>>>>>>> 82edf2d (New md files from RunPod) #### B. İyileştirilmiş Kapatma Sırası @@ -363,10 +378,17 @@ class Subscriber: **Temel Tasarım Avantajları (Yayıncı modeline uygun):** **Tek İşlem Konumu**: Tüm mesaj işleme, `run()` metodu içinde gerçekleşir. +<<<<<<< HEAD **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. +======= +**Temiz Durum Makinesi**: Üç açık durum - çalışıyor, boşaltılıyor, 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ş herhangi bir mesaj için olumsuz onay gönderir. +>>>>>>> 82edf2d (New md files from RunPod) #### B. Dışa Aktarma İşleyici İyileştirmeleri @@ -656,14 +678,22 @@ Mesaj kayıpları için uyarılar eklendi `websocket.forced_shutdowns` - Zorlanmış/zaman aşımı kapanışları ### Uyarılar +<<<<<<< HEAD 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ı +======= +Yayıncı kuyruğu derinliği %80 kapasiteyi aştığında +Kapanma sırasında herhangi bir mesaj kaybı olduğunda +Abonelik olumsuz onay oranı > %1 olduğunda +Kapanış zaman aşımı aşıldığında +>>>>>>> 82edf2d (New md files from RunPod) ## Geriye Dönük Uyumluluk Tüm değişiklikler geriye dönük uyumluluğu korur: +<<<<<<< HEAD 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 @@ -671,6 +701,15 @@ Yeni özellikler kullanılamıyorsa, kademeli bozulma ## Güvenlik Hususları Herhangi bir yeni saldırı vektörü tanıtılmadı +======= +Yapılandırma olmadan varsayılan davranış değişmez +Mevcut dağıtımlar çalışmaya devam eder +Yeni özellikler kullanılamadığında, düzgün bir şekilde performans düşüşü olur + +## Güvenlik Hususları + +Herhangi bir yeni saldırı vektörü tanıtılmamıştır +>>>>>>> 82edf2d (New md files from RunPod) 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 diff --git a/docs/tech-specs/import-export-graceful-shutdown.zh-cn.md b/docs/tech-specs/import-export-graceful-shutdown.zh-cn.md index f1dbd9f0..26bf16ab 100644 --- a/docs/tech-specs/import-export-graceful-shutdown.zh-cn.md +++ b/docs/tech-specs/import-export-graceful-shutdown.zh-cn.md @@ -2,11 +2,19 @@ ## 问题陈述 +<<<<<<< HEAD TrustGraph 网关在导入和导出操作中,在 WebSocket 连接关闭时,目前存在消息丢失的问题。 这是由于存在竞争条件,导致正在传输的消息在到达目的地之前被丢弃(对于导入,是丢弃到 Pulsar 队列的消息;对于导出,是丢弃到 WebSocket 客户端的消息)。 ### 导入端问题 1. 发布者的 asyncio.Queue 缓冲区在关闭时未被清空 2. 在确保所有排队的消息到达 Pulsar 之前,WebSocket 连接关闭 +======= +TrustGraph 网关在导入和导出操作的 WebSocket 关闭过程中,目前存在消息丢失的问题。 这是由于存在竞争条件,导致正在传输的消息在到达目的地之前被丢弃(对于导入,是丢弃到 Pulsar 队列的消息;对于导出,是丢弃到 WebSocket 客户端的消息)。 + +### 导入端问题 +1. 发布者的 asyncio.Queue 缓冲区在关闭时未被清空 +2. 在确保所有排队的消息到达 Pulsar 之前,WebSocket 被关闭 +>>>>>>> 82edf2d (New md files from RunPod) 3. 没有用于确认消息成功传递的机制 ### 导出端问题 @@ -362,7 +370,11 @@ class Subscriber: ``` **主要设计优势(与发布者模式匹配):** +<<<<<<< HEAD **单一处理位置:** 所有消息处理都在 `run()` 方法中进行。 +======= +**单一处理位置:** 所有消息处理都发生在 `run()` 方法中。 +>>>>>>> 82edf2d (New md files from RunPod) **清晰的状态机:** 三个明确的状态 - 运行中、正在排空、已停止。 **排空期间暂停:** 在排空现有队列时,停止从 Pulsar 接收新消息。 **超时保护:** 在排空过程中不会无限期挂起。 @@ -631,17 +643,30 @@ async def test_export_no_message_loss(): ## 部署计划 +<<<<<<< HEAD ### 第一阶段:关键修复(第一周) 修复订阅者确认时序问题(防止消息丢失) 添加发布者队列排空功能 部署到测试环境 ### 第二阶段:平滑关闭(第二周) +======= +### 第一阶段:关键修复 (第一周) +修复订阅者确认时序问题 (防止消息丢失) +添加发布者队列排空功能 +部署到测试环境 + +### 第二阶段:平滑关闭 (第二周) +>>>>>>> 82edf2d (New md files from RunPod) 实施关闭协调 添加反压策略 性能测试 +<<<<<<< HEAD ### 第三阶段:监控与调优(第三周) +======= +### 第三阶段:监控与调优 (第三周) +>>>>>>> 82edf2d (New md files from RunPod) 添加队列深度的指标 添加消息丢失的告警 根据生产数据调整超时值 @@ -656,7 +681,11 @@ async def test_export_no_message_loss(): `websocket.forced_shutdowns` - 强制/超时关闭 ### 告警 +<<<<<<< HEAD 发布者队列深度超过 80% 的容量 +======= +发布者队列深度超过 80% 容量 +>>>>>>> 82edf2d (New md files from RunPod) 关闭期间出现任何消息丢失 订阅者否定确认率 > 1% 关闭超时 @@ -677,6 +706,12 @@ async def test_export_no_message_loss(): ## 性能影响 正常运行期间的开销很小 +<<<<<<< HEAD 关闭可能需要长达 5 秒(可配置) 内存使用量受队列大小限制 -CPU 影响可以忽略不计(<1% 的增加) \ No newline at end of file +CPU 影响可以忽略不计(<1% 的增加) +======= +关闭可能需要长达 5 秒钟 (可配置) +内存使用量受队列大小限制 +CPU 影响可以忽略不计 (<1% 的增长) +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/jsonl-prompt-output.ar.md b/docs/tech-specs/jsonl-prompt-output.ar.md index d61dc67a..e4e0d949 100644 --- a/docs/tech-specs/jsonl-prompt-output.ar.md +++ b/docs/tech-specs/jsonl-prompt-output.ar.md @@ -2,13 +2,21 @@ ## نظرة عامة +<<<<<<< HEAD تصف هذه المواصفات تطبيق تنسيق JSONL (JSON Lines) للإخراج +======= +تصف هذه المواصفات تنفيذ تنسيق JSONL (JSON Lines) للإخراج +>>>>>>> 82edf2d (New md files from RunPod) في TrustGraph. يتيح JSONL استخراجًا مقاومًا للتقطيع للبيانات المنظمة من استجابات نماذج اللغة الكبيرة (LLM)، مما يعالج المشكلات الهامة المتعلقة بتلف مخرجات JSON array عندما تصل استجابات نماذج اللغة الكبيرة إلى حدود الرموز المميزة للإخراج. +<<<<<<< HEAD يدعم هذا التطبيق حالات الاستخدام التالية: +======= +يدعم هذا التنفيذ حالات الاستخدام التالية: +>>>>>>> 82edf2d (New md files from RunPod) 1. **الاستخراج المقاوم للتقطيع**: استخراج نتائج جزئية صالحة حتى عندما يتم اقتطاع إخراج نموذج اللغة الكبيرة في منتصف الاستجابة. @@ -23,6 +31,7 @@ **التوافق مع الإصدارات السابقة**: تظل الطلبات الحالية التي تستخدم `response-type: "text"` و `response-type: "json"` تعمل دون تعديل. +<<<<<<< HEAD **مقاومة التقطيع**: تؤدي مخرجات نماذج اللغة الكبيرة الجزئية إلى نتائج جزئية صالحة بدلاً من الفشل التام. **التحقق من المخطط**: دعم التحقق من مخطط JSON للكائنات الفردية. @@ -30,6 +39,15 @@ مميز. **تغييرات API الحد الأدنى**: توسيع تكوين الطلب الحالي بنوع استجابة جديد ومفتاح مخطط. +======= +**مقاومة التقطيع**: تؤدي المخرجات الجزئية لنماذج اللغة الكبيرة إلى نتائج + جزئية صالحة بدلاً من الفشل التام. +**التحقق من المخطط**: دعم التحقق من مخطط JSON للكائنات الفردية. +**الاتحادات المميزة**: دعم المخرجات بأنواع متعددة باستخدام حقل `type` + كـ "مميّز". +**تغييرات API قليلة**: توسيع تكوين الطلب الحالي بنوع استجابة جديد ومفتاح + مخطط. +>>>>>>> 82edf2d (New md files from RunPod) ## الخلفية @@ -63,10 +81,17 @@ class Prompt: **غير موثوق به للاستخراج الكبير**: كلما زاد عدد العناصر المستخرجة، زاد خطر الفشل. تعالج هذه المواصفات هذه القيود من خلال تقديم تنسيق JSONL لمطالبات +<<<<<<< HEAD الاستخراج، حيث يكون كل عنصر مستخرج كائن JSON كامل في سطر منفصل. ## التصميم الفني +======= +الاستخراج، حيث يكون كل عنصر مستخرج كائن JSON كامل على سطر منفصل. + + +## التصميم التقني +>>>>>>> 82edf2d (New md files from RunPod) ### إضافة نوع استجابة جديد @@ -74,7 +99,11 @@ class Prompt: #### تغييرات التكوين +<<<<<<< HEAD **قيمة نوع الاستجابة الجديدة:** +======= +**قيمة نوع الاستجابة الجديد:** +>>>>>>> 82edf2d (New md files from RunPod) ``` "response-type": "jsonl" @@ -128,6 +157,7 @@ class Prompt: ``` إذا قام نموذج اللغة الكبير بقطع النص بعد السطر الثاني، فإن تنسيق مصفوفة JSON ينتج عنه JSON غير صالح، +<<<<<<< HEAD بينما ينتج عن JSONL كائنان صالحان. #### استخراج أنواع مختلطة (الاتحادات المميزة) @@ -135,6 +165,15 @@ class Prompt: بالنسبة إلى التعليمات التي تستخرج أنواعًا متعددة من الكائنات (مثل التعريفات والأمثلة). العلاقات، أو الكيانات، والعلاقات، والخصائص)، استخدم `"type"` الحقل كعامل تمييز: +======= +بينما ينتج عن JSONL كائني JSON صالحين. + +#### استخراج الأنواع المختلطة (الاتحادات المميزة) + +بالنسبة إلى التعليمات التي تستخرج أنواعًا متعددة من الكائنات (مثل التعريفات والأمثلة). +العلاقات، أو الكيانات، والعلاقات، والخصائص)، استخدم `"type"` +الحقل كمعرّف: +>>>>>>> 82edf2d (New md files from RunPod) **تنسيق إخراج التعليمات:** ``` @@ -205,7 +244,11 @@ class Prompt: #### PromptManager.load_config +<<<<<<< HEAD لا توجد تغييرات مطلوبة - عملية تحميل التكوين الحالية تتعامل بالفعل مع +======= +لا توجد تغييرات مطلوبة - فإن عملية تحميل التكوين الحالية تتعامل بالفعل مع +>>>>>>> 82edf2d (New md files from RunPod) `schema`. #### تحليل JSONL @@ -324,7 +367,11 @@ async def invoke(self, id, input, llm): من جانب الخادم في خدمة المطالبات، ويتم إرجاع الاستجابة عبر الحقل القياسي `PromptResponse.object` كمصفوفة JSON مسلسلة. +<<<<<<< HEAD عندما يستدعي العملاء خدمة المطالبات (عبر `PromptClient.prompt()` أو ما شابه): +======= +عندما يستدعي العملاء خدمة المطالبات (عبر `PromptClient.prompt()` أو ما شابه ذلك): +>>>>>>> 82edf2d (New md files from RunPod) **`response-type: "json"`** مع مخطط المصفوفة → يتلقى العميل كائن Python `list` **`response-type: "jsonl"`** → يتلقى العميل كائن Python `list` @@ -333,7 +380,11 @@ async def invoke(self, id, input, llm): الفرق يكمن بالكامل في كيفية تحليل مخرجات نموذج اللغة الكبير (LLM) من جهة الخادم: تنسيق مصفوفة JSON: استدعاء واحد لـ `json.loads()`؛ يفشل تمامًا إذا تم اقتطاعه. +<<<<<<< HEAD تنسيق JSONL: تحليل سطريًا؛ ينتج عنه نتائج جزئية إذا تم اقتطاعه. +======= +تنسيق JSONL: تحليل سطرًا بسطر؛ ينتج عنه نتائج جزئية إذا تم اقتطاعه. +>>>>>>> 82edf2d (New md files from RunPod) هذا يعني أن التعليمات البرمجية للعميل الحالية التي تتوقع قائمة من مطالبات الاستخراج لا تتطلب أي تغييرات عند ترحيل المطالبات من تنسيق JSON إلى تنسيق JSONL. @@ -385,7 +436,11 @@ async def invoke(self, id, input, llm): **التحقق من صحة الإدخال**: يستخدم تحليل JSON معيار `json.loads()` وهو آمن ضد هجمات الحقن. **التحقق من صحة المخطط**: يستخدم `jsonschema.validate()` لفرض المخطط. +<<<<<<< HEAD **لا توجد مساحة هجومية جديدة**: تحليل JSONL أكثر أمانًا بشكل صارم من تحليل مصفوفة JSON +======= +**لا توجد نقاط ضعف جديدة**: تحليل JSONL أكثر أمانًا بشكل صارم من تحليل مصفوفة JSON +>>>>>>> 82edf2d (New md files from RunPod) بسبب المعالجة سطرًا بسطر. ## اعتبارات الأداء @@ -393,7 +448,11 @@ async def invoke(self, id, input, llm): **الذاكرة**: يستخدم التحليل سطرًا بسطر ذاكرة قصوى أقل من تحميل مصفوفات JSON كاملة. **زمن الوصول**: أداء التحليل مماثل لأداء تحليل مصفوفة JSON. **التحقق من الصحة**: يتم تشغيل التحقق من صحة المخطط لكل كائن، مما يضيف حملًا إضافيًا ولكنه +<<<<<<< HEAD يمكّن النتائج الجزئية في حالة فشل التحقق من الصحة. +======= +يتيح الحصول على نتائج جزئية في حالة فشل التحقق من الصحة. +>>>>>>> 82edf2d (New md files from RunPod) ## استراتيجية الاختبار @@ -406,7 +465,11 @@ async def invoke(self, id, input, llm): تحليل JSONL مع سطر نهائي مقطوع. تحليل JSONL مع أسطر JSON غير صالحة متداخلة. التحقق من صحة المخطط مع اتحاد `oneOf` المميّز. +<<<<<<< HEAD التوافق مع الإصدارات السابقة: تظل المطالبات `"text"` و `"json"` الحالية دون تغيير. +======= +التوافق مع الإصدارات السابقة: تظل المطالبات الحالية `"text"` و `"json"` دون تغيير. +>>>>>>> 82edf2d (New md files from RunPod) ### اختبارات التكامل @@ -415,7 +478,11 @@ async def invoke(self, id, input, llm): الاستخراج المختلط الأنواع مع مميز النوع. استخراج علم الوجود مع الأنواع الثلاثة. +<<<<<<< HEAD ### اختبارات جودة الاستخراج. +======= +### اختبارات جودة الاستخراج +>>>>>>> 82edf2d (New md files from RunPod) مقارنة نتائج الاستخراج: تنسيق JSONL مقابل تنسيق مصفوفة JSON. التحقق من قدرة تحمل التقصير: ينتج عن تنسيق JSONL نتائج جزئية في الحالات التي يفشل فيها تنسيق JSON. @@ -425,7 +492,11 @@ async def invoke(self, id, input, llm): ### المرحلة الأولى: التنفيذ 1. تنفيذ الطريقة `parse_jsonl()` في `PromptManager`. +<<<<<<< HEAD 2. توسيع `invoke()` للتعامل مع `response-type: "jsonl"`. +======= +2. توسيع نطاق `invoke()` للتعامل مع `response-type: "jsonl"`. +>>>>>>> 82edf2d (New md files from RunPod) 3. إضافة اختبارات الوحدة. ### المرحلة الثانية: ترحيل المطالبات @@ -439,9 +510,15 @@ async def invoke(self, id, input, llm): ### المرحلة الثالثة: التحديثات اللاحقة +<<<<<<< HEAD 1. تحديث أي كود يستهلك نتائج الاستخراج للتعامل مع نوع الإرجاع القائمة. 2. تحديث الكود الذي يصنف الاستخراجات ذات الأنواع المختلطة باستخدام الحقل `type`. 3. تحديث الاختبارات التي تؤكد على تنسيق إخراج الاستخراج. +======= +1. تحديث أي كود يستخدم نتائج الاستخراج للتعامل مع نوع الإرجاع القائمة. +2. تحديث الكود الذي يصنف الاستخراجات ذات الأنواع المختلطة باستخدام الحقل `type`. +3. تحديث الاختبارات التي تتحقق من تنسيق إخراج الاستخراج. +>>>>>>> 82edf2d (New md files from RunPod) ## أسئلة مفتوحة diff --git a/docs/tech-specs/jsonl-prompt-output.es.md b/docs/tech-specs/jsonl-prompt-output.es.md index 60eefbd2..1f2e0adc 100644 --- a/docs/tech-specs/jsonl-prompt-output.es.md +++ b/docs/tech-specs/jsonl-prompt-output.es.md @@ -23,7 +23,11 @@ Esta implementación admite los siguientes casos de uso: **Compatibilidad con versiones anteriores**: Las indicaciones existentes que utilizan `response-type: "text"` y `response-type: "json"` siguen funcionando sin modificaciones. +<<<<<<< HEAD **Resiliencia a la truncación**: Las salidas parciales del LLM producen resultados válidos parciales +======= +**Resiliencia ante la truncación**: Las salidas parciales del LLM producen resultados válidos parciales +>>>>>>> 82edf2d (New md files from RunPod) 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` @@ -31,7 +35,11 @@ Esta implementación admite los siguientes casos de uso: **Cambios mínimos en la API**: Extiende la configuración de indicaciones existente con un nuevo tipo de respuesta y clave de esquema. +<<<<<<< HEAD ## Contexto +======= +## Antecedentes +>>>>>>> 82edf2d (New md files from RunPod) ### Arquitectura actual @@ -62,7 +70,11 @@ Cuando las indicaciones de extracción solicitan una salida en formato de matric **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. +<<<<<<< HEAD Esta especificación aborda estas limitaciones introduciendo el formato JSONL para +======= +Esta especificación aborda estas limitaciones mediante la introducción del formato JSONL para +>>>>>>> 82edf2d (New md files from RunPod) las indicaciones de extracción, donde cada elemento extraído es un objeto JSON completo en su propia línea. @@ -108,10 +120,17 @@ Esto evita cambios en las herramientas de configuración y los editores. #### Extracción simple +<<<<<<< HEAD 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:** +======= +Para las indicaciones 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 de la indicación:** +>>>>>>> 82edf2d (New md files from RunPod) ``` {"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"} {"entity": "chlorophyll", "definition": "Green pigment in plants"} @@ -132,7 +151,11 @@ mientras que JSONL produce dos objetos válidos. #### Extracción de Tipos Mixtos (Uniones Discriminadas) +<<<<<<< HEAD Para las indicaciones que extraen múltiples tipos de objetos (por ejemplo, tanto definiciones como +======= +Para indicaciones que extraen múltiples tipos de objetos (por ejemplo, tanto definiciones como +>>>>>>> 82edf2d (New md files from RunPod) relaciones, o entidades, relaciones y atributos), utilice un campo `"type"` como discriminador: @@ -330,6 +353,7 @@ Cuando los clientes llaman al servicio de prompts (a través de `PromptClient.pr **`response-type: "jsonl"`** → el cliente recibe Python `list` Desde la perspectiva del cliente, ambos devuelven estructuras de datos idénticas. La +<<<<<<< HEAD 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 @@ -337,6 +361,15 @@ Formato JSONL: Análisis línea por línea; produce resultados parciales si se t 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. +======= +diferencia radica completamente en cómo se analiza la salida del LLM en el servidor: + +Formato de matriz JSON: Una sola llamada a `json.loads()`; falla por completo 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 del formato JSON al formato JSONL. +>>>>>>> 82edf2d (New md files from RunPod) #### Valor de Retorno del Servidor @@ -351,7 +384,11 @@ Fallo parcial de análisis: Devuelve una lista de objetos analizados correctamen registros de advertencia para los fallos Fallo completo de análisis: Devuelve una lista vacía `[]` con registros de advertencia +<<<<<<< HEAD Esto difiere de `response-type: "json"` que lanza `RuntimeError` en +======= +Esto difiere de `response-type: "json"`, que lanza `RuntimeError` en +>>>>>>> 82edf2d (New md files from RunPod) caso de fallo de análisis. El comportamiento permisivo para JSONL es intencional para proporcionar resistencia a la truncación. @@ -391,6 +428,7 @@ Ejemplo completo de configuración de prompt: ## Consideraciones de rendimiento **Memoria**: El análisis línea por línea utiliza menos memoria máxima que la carga de matrices JSON completas. +<<<<<<< HEAD **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 @@ -398,15 +436,31 @@ Ejemplo completo de configuración de prompt: ## Estrategia de pruebas +======= + **Latencia**: El rendimiento del análisis es comparable al análisis de matrices JSON. +**Validación**: La validación de esquemas se ejecuta por objeto, lo que añade sobrecarga, pero +permite resultados parciales en caso de fallo de la validación. + +## Estrategia de pruebas + + +>>>>>>> 82edf2d (New md files from RunPod) ### 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 +<<<<<<< HEAD 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 +======= +Análisis de JSONL con líneas finales truncadas +Análisis de JSONL con líneas JSON inválidas intercaladas +Validación de esquema con uniones discriminadas `oneOf` +Compatibilidad con versiones anteriores: las indicaciones `"text"` y `"json"` existentes no se modifican +>>>>>>> 82edf2d (New md files from RunPod) ### Pruebas de Integración @@ -449,7 +503,14 @@ Ninguna por el momento. ## Referencias +<<<<<<< HEAD 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`). +======= +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`) +>>>>>>> 82edf2d (New md files from RunPod) diff --git a/docs/tech-specs/jsonl-prompt-output.he.md b/docs/tech-specs/jsonl-prompt-output.he.md index 2573e562..d28b6510 100644 --- a/docs/tech-specs/jsonl-prompt-output.he.md +++ b/docs/tech-specs/jsonl-prompt-output.he.md @@ -5,15 +5,24 @@ מפרט זה מתאר את יישום פורמט הפלט JSONL (JSON Lines) עבור תשובות לשאילתות ב-TrustGraph. JSONL מאפשר חילוץ עמיד לקיטוע של נתונים מובנים מתשובות של מודלי שפה גדולים (LLM), תוך התמודדות עם בעיות +<<<<<<< HEAD קריטיות שבהן פלט מערך JSON נפגע כאשר תשובות ה-LLM מגיעות למגבלות של מספר הטוקנים. +======= +קריטיות שבהן מערכי JSON יוצאים מכלל שימוש כאשר תשובות ה-LLM מגיעות +למגבלות מספר הטוקנים. +>>>>>>> 82edf2d (New md files from RunPod) יישום זה תומך בתרחישי שימוש הבאים: 1. **חילוץ עמיד לקיטוע**: חילוץ תוצאות חלקיות ותקינות גם כאשר פלט ה-LLM מקוטע באמצע התגובה. 2. **חילוץ בקנה מידה גדול**: טיפול בחילוץ של פריטים רבים מבלי +<<<<<<< HEAD להסתכן בכשל מוחלט עקב מגבלות טוקנים. +======= + להסתכן בכשל מוחלט עקב מגבלות מספר הטוקנים. +>>>>>>> 82edf2d (New md files from RunPod) 3. **חילוץ מסוגים מעורבים**: תמיכה בחילוץ של סוגי ישויות מרובים (הגדרות, קשרים, ישויות, תכונות) בשאילתה אחת. 4. **פלט תואם לסטרימינג**: אפשור עיבוד עתידי של תוצאות החילוץ @@ -35,10 +44,17 @@ ### ארכיטקטורה נוכחית +<<<<<<< HEAD שירות השאילתות תומך בשני סוגי תגובה: 1. `response-type: "text"` - תגובה טקסטואלית גולמית המוחזרת כפי שהיא. 2. `response-type: "json"` - JSON המנותח מהתגובה, ומאומת כנגד +======= +שירות השאילתות תומך בשני סוגי תגובות: + +1. `response-type: "text"` - תגובה טקסטואלית גולמית המוחזרת כפי שהיא. +2. `response-type: "json"` - JSON המנותח מהתגובה, ומאומת מול +>>>>>>> 82edf2d (New md files from RunPod) `schema` אופציונלי. יישום נוכחי ב-`trustgraph-flow/trustgraph/template/prompt_manager.py`: @@ -56,7 +72,11 @@ class Prompt: כאשר הנחיות החילוץ מבקשות פלט כמערכים מסוג JSON (`[{...}, {...}, ...]`): +<<<<<<< HEAD **שחיתות עקב קיטום**: אם מודל השפה (LLM) מגיע למגבלת מספר הטוקנים במהלך יצירת המערך, +======= +**שחיתות עקב קיטוע:** אם מודל השפה (LLM) מגיע למגבלת מספר הטוקנים במהלך יצירת המערך, +>>>>>>> 82edf2d (New md files from RunPod) התגובה כולה הופכת ל-JSON לא חוקי ואי אפשר לנתח אותה. **ניתוח "הכל או כלום":** יש לקבל את הפלט השלם לפני הניתוח. **אין תוצאות חלקיות:** תגובה מקוטעת מניבה אפס נתונים שניתן להשתמש בהם. @@ -74,7 +94,11 @@ class Prompt: #### שינויי תצורה +<<<<<<< HEAD **ערך חדש עבור סוג התגובה:** +======= +**ערך סוג תגובה חדש:** +>>>>>>> 82edf2d (New md files from RunPod) ``` "response-type": "jsonl" @@ -118,7 +142,11 @@ class Prompt: {"entity": "mitochondria", "definition": "Powerhouse of the cell"} ``` +<<<<<<< HEAD **ניגוד לפורמט מערך JSON הקודם:** +======= +**השוואה לפורמט מערך JSON הקודם:** +>>>>>>> 82edf2d (New md files from RunPod) ```json [ {"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"}, @@ -130,10 +158,17 @@ class Prompt: אם מודל השפה הגדול (LLM) מקצר אחרי השורה 2, פורמט מערך ה-JSON ייתן JSON לא תקין, בעוד ש-JSONL ייתן שני אובייקטים תקינים. +<<<<<<< HEAD #### חילוץ של טיפוסים מעורבים (איחודים מובחנים) עבור הנחיות המפיקות מספר סוגים של אובייקטים (לדוגמה, גם הגדרות וגם קשרים, או ישויות, קשרים ומאפיינים), השתמש בשדה `"type"` +======= +#### חילוץ מסוגים מעורבים (איחודים מובחנים) + +עבור הנחיות המפיקות סוגים מרובים של אובייקטים (לדוגמה, גם הגדרות וגם +קשרים, או ישויות, קשרים ומאפיינים), השתמשו בשדה `"type"` +>>>>>>> 82edf2d (New md files from RunPod) כמבחין: **פורמט פלט של ההנחיה:** @@ -245,7 +280,11 @@ def parse_jsonl(self, text): #### שינויים ב-PromptManager.invoke +<<<<<<< HEAD הרחב את השיטה invoke כדי לטפל בסוג התגובה החדש: +======= +הרחב את המיפעל invoke כדי לטפל בסוג התגובה החדש: +>>>>>>> 82edf2d (New md files from RunPod) ```python async def invoke(self, id, input, llm): @@ -321,7 +360,11 @@ async def invoke(self, id, input, llm): #### נקודת מבט של הלקוח ניתוח JSONL שקוף למשתמשי ה-API של שירות ההנחיות. הניתוח מתבצע +<<<<<<< HEAD בצד השרת בשירות ההנחיות, והתגובה מוחזרת באמצעות השדה הסטנדרטי +======= +בצד השרת בשירות ההנחיות, והתגובה מוחזרת דרך השדה הסטנדרטי +>>>>>>> 82edf2d (New md files from RunPod) `PromptResponse.object` כמערך JSON מוסרי. כאשר לקוחות קוראים לשירות ההנחיות (דרך `PromptClient.prompt()` או דומה): @@ -330,10 +373,17 @@ async def invoke(self, id, input, llm): **`response-type: "jsonl"`** → הלקוח מקבל `list` בפייתון מנקודת מבטו של הלקוח, שתי השיטות מחזירות מבני נתונים זהים. ההבדל +<<<<<<< HEAD הוא אך ורק באופן שבו פלט ה-LLM מנותח בצד השרת: פורמט מערך JSON: קריאה אחת ל-`json.loads()`; נכשל לחלוטין אם הוא חתוך פורמט JSONL: ניתוח שורה אחר שורה; מייצר תוצאות חלקיות אם הוא חתוך +======= +הוא אך ורק באופן שבו הפלט של מודל השפה הגדול (LLM) מנותח בצד השרת: + +פורמט מערך JSON: קריאה אחת ל-`json.loads()`; נכשל לחלוטין אם הוא חתוך. +פורמט JSONL: ניתוח שורה אחר שורה; מייצר תוצאות חלקיות אם הוא חתוך. +>>>>>>> 82edf2d (New md files from RunPod) המשמעות היא שקוד לקוח קיים שמצפה לרשימה מהנחיות חילוץ אינו דורש שינויים בעת העברת הנחיות מפורמט JSON לפורמט JSONL. @@ -346,10 +396,17 @@ async def invoke(self, id, input, llm): #### טיפול בשגיאות +<<<<<<< HEAD תוצאות ריקות: מחזיר רשימה ריקה `[]` עם רישום אזהרה כשל חלקי בניתוח: מחזיר רשימה של אובייקטים שנותחו בהצלחה עם רישומי אזהרה עבור כשלים כשל מוחלט בניתוח: מחזיר רשימה ריקה `[]` עם רישומי אזהרה +======= +תוצאות ריקות: מחזיר רשימה ריקה `[]` עם רישום אזהרה. +כשל חלקי בניתוח: מחזיר רשימה של אובייקטים שנותחו בהצלחה עם + רישומי אזהרה עבור כשלים. +כשל מוחלט בניתוח: מחזיר רשימה ריקה `[]` עם רישומי אזהרה. +>>>>>>> 82edf2d (New md files from RunPod) זה שונה מ-`response-type: "json"` שמגביר `RuntimeError` בעת כשל בניתוח. ההתנהגות הסלחנית עבור JSONL היא מכוונת כדי לספק @@ -382,19 +439,34 @@ async def invoke(self, id, input, llm): ## שיקולי אבטחה +<<<<<<< HEAD **בדיקת תקינות קלט**: ניתוח JSON משתמש ב-`json.loads()` הסטנדרטי, שהוא בטוח מפני התקפות הזרקה. **בדיקת תאימות סכימה**: משתמש ב-`jsonschema.validate()` לאכיפת סכימה. **ללא משטח תקיפה חדש**: ניתוח JSONL בטוח יותר מניתוח מערך JSON +======= +**בדיקת קלט**: ניתוח JSON משתמש ב-`json.loads()` הסטנדרטי, שהוא בטוח + מפני התקפות הזרקה. +**בדיקת סכימה**: משתמש ב-`jsonschema.validate()` לאכיפת סכימה. +**ללא נקודות תורפה חדשות**: ניתוח JSONL בטוח יותר מניתוח מערך JSON +>>>>>>> 82edf2d (New md files from RunPod) בשל עיבוד שורה אחר שורה. ## שיקולי ביצועים +<<<<<<< HEAD **זיכרון**: ניתוח שורה אחר שורה משתמש בפחות זיכרון שיא בהשוואה לטעינת מערכי JSON שלמים. **השהיה**: ביצועי הניתוח דומים לניתוח מערך JSON. **בדיקת תאימות**: בדיקת תאימות סכימה מתבצעת עבור כל אובייקט, מה שמוסיף תקורה אך מאפשר תוצאות חלקיות במקרה של כשל בבדיקת התאימות. +======= +**זיכרון**: ניתוח שורה אחר שורה משתמש בפחות זיכרון שיא בהשוואה לטעינת + מערכי JSON שלמים. +**השהיה**: ביצועי הניתוח דומים לניתוח מערך JSON. +**בדיקה**: בדיקת סכימה מתבצעת עבור כל אובייקט, מה שמוסיף תקורה אך + מאפשר תוצאות חלקיות במקרה של כשל בבדיקה. +>>>>>>> 82edf2d (New md files from RunPod) ## אסטרטגיית בדיקות @@ -405,7 +477,11 @@ async def invoke(self, id, input, llm): ניתוח JSONL עם גדרות קוד Markdown. ניתוח JSONL עם שורה אחרונה חתוכה. ניתוח JSONL עם שורות JSON לא תקינות המפוזרות. +<<<<<<< HEAD בדיקת תאימות סכימה עם איחודים מובחנים של `oneOf`. +======= +בדיקת סכימה עם איחודים מובחנים של `oneOf`. +>>>>>>> 82edf2d (New md files from RunPod) תאימות לאחור: הנחיות `"text"` ו-`"json"` קיימות אינן משתנות. ### בדיקות אינטגרציה @@ -418,7 +494,11 @@ async def invoke(self, id, input, llm): ### בדיקות איכות חילוץ השוואת תוצאות חילוץ: פורמט JSONL לעומת מערך JSON. +<<<<<<< HEAD בדיקת עמידות בפני קיטוע: JSONL מניב תוצאות חלקיות כאשר JSON נכשל. +======= +בדיקת עמידות בפני קיטוע: פורמט JSONL מספק תוצאות חלקיות כאשר פורמט JSON נכשל. +>>>>>>> 82edf2d (New md files from RunPod) ## תוכנית מעבר @@ -439,8 +519,13 @@ async def invoke(self, id, input, llm): ### שלב 3: עדכונים במערכות משימתיות +<<<<<<< HEAD 1. עדכון כל קוד המשתמש בתוצאות החילוץ כדי לטפל בסוג החזרה של רשימה. 2. עדכון קוד המקטלג חילוצים מסוגים מעורבים לפי שדה `type`. +======= +1. עדכון כל קוד הצורך בתוצאות החילוץ כדי לטפל בסוג החזרה של רשימה. +2. עדכון קוד שמקטלג חילוצים מסוגים מעורבים לפי שדה `type`. +>>>>>>> 82edf2d (New md files from RunPod) 3. עדכון בדיקות המאמתות את פורמט הפלט של החילוץ. ## שאלות פתוחות diff --git a/docs/tech-specs/jsonl-prompt-output.hi.md b/docs/tech-specs/jsonl-prompt-output.hi.md index 72310ff2..3d6f6ca5 100644 --- a/docs/tech-specs/jsonl-prompt-output.hi.md +++ b/docs/tech-specs/jsonl-prompt-output.hi.md @@ -2,14 +2,18 @@ ## अवलोकन +<<<<<<< HEAD यह विनिर्देश ट्रस्टग्राफ में प्रॉम्प्ट प्रतिक्रियाओं के लिए JSONL (JSON लाइन्स) आउटपुट प्रारूप के कार्यान्वयन का वर्णन करता है। JSONL, LLM प्रतिक्रियाओं से संरचित डेटा को निकालने में सक्षम बनाता है, जो कि LLM प्रतिक्रियाओं के आउटपुट टोकन सीमाओं तक पहुंचने पर JSON सरणी आउटपुट के दूषित होने जैसी महत्वपूर्ण समस्याओं को हल करता है। +======= +यह विनिर्देश ट्रस्टग्राफ में प्रॉम्प्ट प्रतिक्रियाओं के लिए JSONL (JSON लाइन्स) आउटपुट प्रारूप के कार्यान्वयन का वर्णन करता है। JSONL, LLM प्रतिक्रियाओं से संरचित डेटा को निकालने में सक्षम बनाता है, जो कि LLM प्रतिक्रियाओं के आउटपुट टोकन सीमाओं तक पहुंचने पर JSON सरणी आउटपुट के दूषित होने जैसी महत्वपूर्ण समस्याओं का समाधान करता है। +>>>>>>> 82edf2d (New md files from RunPod) -यह कार्यान्वयन निम्नलिखित उपयोग मामलों का समर्थन करता है: +<<<<<<< HEAD 1. **ट्रंकेशन-रेज़िलिएंट एक्सट्रैक्शन (Truncation-Resilient Extraction)**: वैध आंशिक परिणाम निकालें, भले ही एलएलएम (LLM) आउटपुट प्रतिक्रिया के बीच में ही काट दिया गया हो। 2. **बड़े पैमाने पर एक्सट्रैक्शन (Large-Scale Extraction)**: टोकन सीमाओं के कारण पूर्ण विफलता के जोखिम के बिना, कई वस्तुओं के निष्कर्षण को संभालें। @@ -18,14 +22,36 @@ प्रसंस्करण को सक्षम करें। +======= + + + +यह कार्यान्वयन निम्नलिखित उपयोग परिदृश्यों का समर्थन करता है: + +1. **ट्रंकेशन-प्रतिरोधी निष्कर्षण**: भले ही एलएलएम आउटपुट प्रतिक्रिया के बीच में काट दिया गया हो, फिर भी मान्य आंशिक परिणाम निकालें। + एलएलएम आउटपुट प्रतिक्रिया के बीच में काट दिया गया हो, फिर भी मान्य आंशिक परिणाम निकालें। +2. **बड़ी-पैमाने पर निष्कर्षण**: टोकन सीमाओं के कारण पूर्ण विफलता के जोखिम के बिना, कई वस्तुओं के निष्कर्षण को संभालें। + टोकन सीमाओं के कारण पूर्ण विफलता के जोखिम के बिना, कई वस्तुओं के निष्कर्षण को संभालें। +3. **मिश्रित-प्रकार निष्कर्षण**: एक ही प्रॉम्प्ट में कई इकाई प्रकारों (परिभाषाएँ, संबंध, इकाइयाँ, विशेषताएँ) के निष्कर्षण का समर्थन करें। + एक ही प्रॉम्प्ट में कई इकाई प्रकारों (परिभाषाएँ, संबंध, इकाइयाँ, विशेषताएँ) के निष्कर्षण का समर्थन करें। +4. **स्ट्रीमिंग-संगत आउटपुट**: निष्कर्षण परिणामों की भविष्य की स्ट्रीमिंग/क्रमिक प्रसंस्करण को सक्षम करें। + निष्कर्षण परिणामों की भविष्य की स्ट्रीमिंग/क्रमिक प्रसंस्करण को सक्षम करें। +>>>>>>> 82edf2d (New md files from RunPod) ## लक्ष्य **पिछड़ा संगतता (Backward Compatibility)**: मौजूदा प्रॉम्प्ट जो `response-type: "text"` और का उपयोग करते हैं, +<<<<<<< HEAD `response-type: "json"` बिना किसी बदलाव के काम करना जारी रखते हैं। **अतिसंयमी लचीलापन (Truncation Resilience)**: आंशिक एलएलएम आउटपुट आंशिक, मान्य परिणाम देते हैं, पूर्ण विफलता के बजाय। **स्कीमा सत्यापन (Schema Validation)**: व्यक्तिगत ऑब्जेक्ट के लिए JSON स्कीमा सत्यापन का समर्थन। +======= + `response-type: "json"`, बिना किसी बदलाव के काम करना जारी रखते हैं। +**अतिसंयमी लचीलापन (Truncation Resilience)**: आंशिक एलएलएम आउटपुट आंशिक, मान्य परिणाम देते हैं, + पूर्ण विफलता के बजाय। +**स्कीमा सत्यापन (Schema Validation)**: व्यक्तिगत वस्तुओं के लिए JSON स्कीमा सत्यापन का समर्थन। +>>>>>>> 82edf2d (New md files from RunPod) **विभेदक संघ (Discriminated Unions)**: `type` फ़ील्ड का उपयोग करके मिश्रित-प्रकार के आउटपुट का समर्थन। विभेदक। **न्यूनतम एपीआई परिवर्तन (Minimal API Changes)**: नए प्रतिक्रिया प्रकार और स्कीमा कुंजी के साथ मौजूदा प्रॉम्प्ट कॉन्फ़िगरेशन का विस्तार। @@ -38,10 +64,17 @@ प्रॉम्प्ट सेवा दो प्रकार के प्रतिक्रियाओं का समर्थन करती है: 1. `response-type: "text"` - बिना किसी बदलाव के वापस की गई कच्ची टेक्स्ट प्रतिक्रिया +<<<<<<< HEAD 2. `response-type: "json"` - प्रतिक्रिया से पार्स किया गया JSON, जिसकी जाँच `response-type: "json"` के विरुद्ध की जाती है वैकल्पिक `schema` `trustgraph-flow/trustgraph/template/prompt_manager.py` में वर्तमान कार्यान्वयन: +======= +2. `response-type: "json"` - प्रतिक्रिया से पार्स किया गया JSON, जिसकी तुलना + वैकल्पिक `schema` से की जाती है + +वर्तमान कार्यान्वयन `trustgraph-flow/trustgraph/template/prompt_manager.py` में: +>>>>>>> 82edf2d (New md files from RunPod) ```python class Prompt: @@ -52,6 +85,7 @@ class Prompt: self.schema = schema ``` +<<<<<<< HEAD ### वर्तमान सीमाएँ जब निष्कर्षण प्रॉम्प्ट आउटपुट को JSON सरणियों (`[{...}, {...}, ...]`) के रूप में मांगते हैं: @@ -63,6 +97,19 @@ class Prompt: **बड़े निष्कर्षणों के लिए अविश्वसनीय**: अधिक निकाले गए आइटम = उच्च विफलता जोखिम। यह विनिर्देश इन सीमाओं को JSONL प्रारूप को पेश करके संबोधित करता है, जहाँ प्रत्येक निकाले गए आइटम को अपनी +======= +### वर्तमान सीमाएं + +जब निष्कर्षण प्रॉम्प्ट आउटपुट को JSON सरणियों (`[{...}, {...}, ...]`) के रूप में मांगते हैं: + +**अतिसंयोजन भ्रष्टाचार**: यदि LLM आउटपुट टोकन सीमाओं को सरणी के बीच में पार करता है, तो + संपूर्ण प्रतिक्रिया अमान्य JSON बन जाती है और इसे पार्स नहीं किया जा सकता है। +**सब कुछ या कुछ नहीं पार्सिंग**: पार्स करने से पहले पूर्ण आउटपुट प्राप्त करना आवश्यक है। +**कोई आंशिक परिणाम नहीं**: एकtruncated प्रतिक्रिया शून्य उपयोगी डेटा उत्पन्न करती है। +**बड़े निष्कर्षणों के लिए अविश्वसनीय**: अधिक निकाले गए आइटम = उच्च विफलता जोखिम। + +यह विनिर्देश इन सीमाओं को JSONL प्रारूप को पेश करके संबोधित करता है, जहां प्रत्येक निकाले गए आइटम को अपनी +>>>>>>> 82edf2d (New md files from RunPod) पंक्ति पर एक पूर्ण JSON ऑब्जेक्ट के रूप में दर्शाया जाता है। @@ -109,7 +156,11 @@ class Prompt: #### सरल निष्कर्षण उन प्रॉम्प्ट के लिए जो केवल एक प्रकार की वस्तु (परिभाषाएँ, संबंध, +<<<<<<< HEAD विषय, पंक्तियाँ) निकालते हैं, आउटपुट में बिना किसी अतिरिक्त आवरण के प्रति पंक्ति एक JSON ऑब्जेक्ट होता है: +======= +विषय, पंक्तियाँ) निकालते हैं, आउटपुट में बिना किसी अतिरिक्त आवरण के, प्रति पंक्ति एक JSON ऑब्जेक्ट होता है: +>>>>>>> 82edf2d (New md files from RunPod) **प्रॉम्प्ट आउटपुट प्रारूप:** ``` @@ -132,9 +183,15 @@ class Prompt: #### मिश्रित-प्रकार निष्कर्षण (भेदभावपूर्ण संघ) +<<<<<<< HEAD उन प्रॉम्प्ट के लिए जो ऑब्जेक्ट के कई प्रकारों को निकालते हैं (उदाहरण के लिए, परिभाषाएँ और संबंध, या इकाइयाँ, संबंध और विशेषताएँ), एक `"type"` फ़ील्ड को विभेदक के रूप में उपयोग करें: +======= +उन प्रॉम्प्ट के लिए जो कई प्रकार की वस्तुओं को निकालते हैं (उदाहरण के लिए, परिभाषाएँ और +संबंध, या इकाइयाँ, संबंध और विशेषताएँ), एक `"type"` +फ़ील्ड का उपयोग विभेदक के रूप में करें: +>>>>>>> 82edf2d (New md files from RunPod) **प्रॉम्प्ट आउटपुट प्रारूप:** ``` @@ -203,7 +260,11 @@ class Prompt: self.schema = schema # Interpretation depends on response_type ``` +<<<<<<< HEAD #### प्रॉम्प्टमैनेजर.लोड_कॉन्फ़िगरेशन +======= +#### PromptManager.load_config +>>>>>>> 82edf2d (New md files from RunPod) कोई बदलाव आवश्यक नहीं है - मौजूदा कॉन्फ़िगरेशन लोड करने की प्रक्रिया पहले से ही `schema` कुंजी को संभालती है। @@ -329,11 +390,19 @@ JSONL पार्सिंग, प्रॉम्प्ट सर्विस **`response-type: "json"`** जिसमें एरे स्कीमा है → ग्राहक को पायथन `list` प्राप्त होता है। **`response-type: "jsonl"`** → ग्राहक को पायथन `list` प्राप्त होता है। +<<<<<<< HEAD ग्राहक के दृष्टिकोण से, दोनों समान डेटा संरचनाएं लौटाते हैं। अंतर पूरी तरह से इस बात में है कि सर्वर-साइड पर एलएलएम आउटपुट को कैसे पार्स किया जाता है: JSON सरणी प्रारूप: एक `json.loads()` कॉल; यदि छोटा किया गया तो पूरी तरह से विफल हो जाता है। JSONL प्रारूप: लाइन-दर-लाइन पार्सिंग; यदि छोटा किया गया तो आंशिक परिणाम देता है। +======= +ग्राहक के दृष्टिकोण से, दोनों समान डेटा संरचनाएँ लौटाते हैं। +अंतर पूरी तरह से इस बात में है कि सर्वर-साइड पर एलएलएम आउटपुट को कैसे पार्स किया जाता है: + +JSON सरणी प्रारूप: एक `json.loads()` कॉल; यदि छोटा किया गया तो पूरी तरह विफल हो जाता है। +JSONL प्रारूप: पंक्ति-दर-पंक्ति पार्सिंग; यदि छोटा किया गया तो आंशिक परिणाम देता है। +>>>>>>> 82edf2d (New md files from RunPod) इसका मतलब है कि मौजूदा क्लाइंट कोड जो एक्सट्रैक्शन प्रॉम्प्ट से एक सूची की अपेक्षा करता है, को JSON से JSONL प्रारूप में प्रॉम्प्ट माइग्रेट करते समय किसी भी बदलाव की आवश्यकता नहीं होती है। @@ -341,17 +410,30 @@ JSONL प्रारूप: लाइन-दर-लाइन पार्सि #### सर्वर रिटर्न वैल्यू `response-type: "jsonl"` के लिए, `PromptManager.invoke()` विधि एक +<<<<<<< HEAD `list[dict]` लौटाती है जिसमें सभी सफलतापूर्वक पार्स और मान्य किए गए ऑब्जेक्ट शामिल होते हैं। इस +======= +`list[dict]` लौटाती है जिसमें सभी सफलतापूर्वक पार्स किए गए और मान्य ऑब्जेक्ट शामिल हैं। इस +>>>>>>> 82edf2d (New md files from RunPod) सूची को तब `PromptResponse.object` फ़ील्ड के लिए JSON में क्रमबद्ध किया जाता है। #### त्रुटि प्रबंधन +<<<<<<< HEAD खाली परिणाम: खाली सूची `[]` लौटाता है चेतावनी लॉग के साथ। आंशिक पार्स विफलता: सफलतापूर्वक पार्स किए गए ऑब्जेक्ट की सूची लौटाता है, विफलताओं के लिए चेतावनी लॉग के साथ। पूर्ण पार्स विफलता: खाली सूची `[]` लौटाता है, चेतावनी लॉग के साथ। यह `response-type: "json"` से अलग है, जो पार्स विफलता पर `RuntimeError` उत्पन्न करता है। +======= +खाली परिणाम: खाली सूची `[]` लौटाता है, साथ में चेतावनी लॉग। +आंशिक पार्स विफलता: सफलतापूर्वक पार्स किए गए ऑब्जेक्ट की सूची लौटाता है, + विफलताओं के लिए चेतावनी लॉग के साथ। +पूर्ण पार्स विफलता: खाली सूची `[]` लौटाता है, साथ में चेतावनी लॉग। + +यह `response-type: "json"` से भिन्न है, जो पार्स विफलता पर `RuntimeError` उत्पन्न करता है। +>>>>>>> 82edf2d (New md files from RunPod) JSONL के लिए उदार व्यवहार जानबूझकर प्रदान किया गया है ताकि ट्रंकेशन के प्रति लचीलापन मिल सके। @@ -390,7 +472,11 @@ JSONL के लिए उदार व्यवहार जानबूझक ## प्रदर्शन संबंधी विचार +<<<<<<< HEAD **मेमोरी**: पंक्ति-दर-पंक्ति पार्सिंग, पूरे JSON सरणियों को लोड करने की तुलना में कम चरम मेमोरी का उपयोग करती है। +======= +**मेमोरी**: लाइन-दर-लाइन पार्सिंग, पूरे JSON सरणियों को लोड करने की तुलना में कम चरम मेमोरी का उपयोग करती है। +>>>>>>> 82edf2d (New md files from RunPod) **विलंबता**: पार्सिंग प्रदर्शन, JSON सरणी पार्सिंग के समान है। **सत्यापन**: स्कीमा सत्यापन प्रत्येक ऑब्जेक्ट के लिए किया जाता है, जिससे ओवरहेड बढ़ता है, लेकिन सत्यापन विफलता पर आंशिक परिणाम प्राप्त करने की अनुमति मिलती है। @@ -403,7 +489,11 @@ JSONL के लिए उदार व्यवहार जानबूझक मान्य इनपुट के साथ JSONL पार्सिंग खाली पंक्तियों के साथ JSONL पार्सिंग मार्कडाउन कोड फ़ेंस के साथ JSONL पार्सिंग +<<<<<<< HEAD कटे हुए अंतिम पंक्ति के साथ JSONL पार्सिंग +======= +truncated अंतिम पंक्ति के साथ JSONL पार्सिंग +>>>>>>> 82edf2d (New md files from RunPod) अमान्य JSON पंक्तियों के साथ JSONL पार्सिंग `oneOf` विभेदक संघों के साथ स्कीमा सत्यापन पिछली अनुकूलता: मौजूदा `"text"` और `"json"` प्रॉम्प्ट अपरिवर्तित @@ -411,7 +501,11 @@ JSONL के लिए उदार व्यवहार जानबूझक ### एकीकरण परीक्षण (Integration Tests) JSONL प्रॉम्प्ट के साथ एंड-टू-एंड निष्कर्षण +<<<<<<< HEAD अनुकरणित कटाई के साथ निष्कर्षण (कृत्रिम रूप से सीमित प्रतिक्रिया) +======= +अनुकरणित ट्रंकेशन के साथ निष्कर्षण (कृत्रिम रूप से सीमित प्रतिक्रिया) +>>>>>>> 82edf2d (New md files from RunPod) टाइप डिस्क्रिमिनेटर के साथ मिश्रित-प्रकार निष्कर्षण सभी तीन प्रकारों के साथ ऑन्टोलॉजी निष्कर्षण @@ -441,7 +535,11 @@ JSONL प्रॉम्प्ट के साथ एंड-टू-एंड 1. निष्कर्षण परिणामों का उपयोग करने वाले किसी भी कोड को सूची रिटर्न प्रकार को संभालने के लिए अपडेट करें 2. `type` फ़ील्ड द्वारा मिश्रित-प्रकार के निष्कर्षणों को वर्गीकृत करने वाले कोड को अपडेट करें +<<<<<<< HEAD 3. निष्कर्षण आउटपुट प्रारूप पर दावा करने वाले परीक्षणों को अपडेट करें +======= +3. निष्कर्षण आउटपुट प्रारूप पर जोर देने वाले परीक्षणों को अपडेट करें +>>>>>>> 82edf2d (New md files from RunPod) ## खुले प्रश्न diff --git a/docs/tech-specs/jsonl-prompt-output.pt.md b/docs/tech-specs/jsonl-prompt-output.pt.md index f80cf765..5152c18d 100644 --- a/docs/tech-specs/jsonl-prompt-output.pt.md +++ b/docs/tech-specs/jsonl-prompt-output.pt.md @@ -1,11 +1,21 @@ +<<<<<<< HEAD # Especificação Técnica de Saída de Prompt JSONL +======= +# Especificação Técnica da Saída de Prompt JSONL +>>>>>>> 82edf2d (New md files from RunPod) ## Visão Geral Esta especificação descreve a implementação do formato de saída JSONL (JSON Lines) +<<<<<<< HEAD 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 +======= +para respostas de prompt no TrustGraph. O JSONL permite a extração de dados estruturados +de forma resistente a truncamentos das respostas de LLM, abordando problemas críticos +relacionados à corrupção de saídas de matrizes JSON quando as respostas de LLM atingem +>>>>>>> 82edf2d (New md files from RunPod) os limites de tokens de saída. Esta implementação suporta os seguintes casos de uso: @@ -62,7 +72,11 @@ Quando os prompts de extração solicitam a saída como arrays JSON (`[{...}, {. **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. +<<<<<<< HEAD Esta especificação aborda essas limitações introduzindo o formato JSONL para +======= +Esta especificação aborda essas limitações, introduzindo o formato JSONL para +>>>>>>> 82edf2d (New md files from RunPod) prompts de extração, onde cada item extraído é um objeto JSON completo em sua própria linha. @@ -118,7 +132,11 @@ tópicos, linhas), a saída é um objeto JSON por linha, sem wrapper: {"entity": "mitochondria", "definition": "Powerhouse of the cell"} ``` +<<<<<<< HEAD **Contraste com o formato anterior de array JSON:** +======= +**Contraste com o formato de array JSON anterior:** +>>>>>>> 82edf2d (New md files from RunPod) ```json [ {"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"}, @@ -128,7 +146,11 @@ tópicos, linhas), a saída é um objeto JSON por linha, sem wrapper: ``` Se o LLM truncar após a linha 2, o formato de array JSON resulta em JSON inválido, +<<<<<<< HEAD enquanto o JSONL produz dois objetos válidos. +======= +enquanto o JSONL gera dois objetos válidos. +>>>>>>> 82edf2d (New md files from RunPod) #### Extração de Tipos Mistos (Uniões Discriminadas) @@ -205,8 +227,13 @@ class Prompt: #### PromptManager.load_config +<<<<<<< HEAD Nenhuma alteração necessária - o carregamento da configuração existente já lida com a `schema` chave. +======= +Nenhuma alteração necessária - o carregamento da configuração existente já trata da +chave `schema`. +>>>>>>> 82edf2d (New md files from RunPod) #### Análise de JSONL @@ -385,7 +412,11 @@ Exemplo completo de configuração de prompt: **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. +<<<<<<< HEAD **Sem Nova Superfície de Ataque**: A análise de JSONL é estritamente mais segura do que a análise de arrays JSON +======= +**Sem Nova Superfície de Ataque**: A análise JSONL é estritamente mais segura do que a análise de arrays JSON +>>>>>>> 82edf2d (New md files from RunPod) devido ao processamento linha por linha. ## Considerações de Desempenho @@ -395,9 +426,15 @@ Exemplo completo de configuração de prompt: **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. +<<<<<<< HEAD ## Estratégia de Testes +======= +## Estratégia de Testes + + +>>>>>>> 82edf2d (New md files from RunPod) ### Testes Unitários Análise de JSONL com entrada válida @@ -441,7 +478,11 @@ Verifique a resiliência à truncagem: o JSONL produz resultados parciais onde o 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`. +<<<<<<< HEAD 3. Atualize os testes que afirmam o formato da saída da extração. +======= +3. Atualize os testes que afirmam o formato de saída da extração. +>>>>>>> 82edf2d (New md files from RunPod) ## Perguntas Abertas diff --git a/docs/tech-specs/jsonl-prompt-output.ru.md b/docs/tech-specs/jsonl-prompt-output.ru.md index ee0ad0f8..7a220437 100644 --- a/docs/tech-specs/jsonl-prompt-output.ru.md +++ b/docs/tech-specs/jsonl-prompt-output.ru.md @@ -12,7 +12,11 @@ 1. **Извлечение, устойчивое к усечению**: Извлекайте допустимые частичные результаты, даже когда вывод LLM усекается в середине ответа. +<<<<<<< HEAD 2. **Извлечение в больших масштабах**: Обрабатывайте извлечение большого количества элементов без риска +======= +2. **Масштабное извлечение**: Обрабатывайте извлечение большого количества элементов без риска +>>>>>>> 82edf2d (New md files from RunPod) полной сбоя из-за ограничений на количество токенов. 3. **Извлечение данных разных типов**: Поддерживайте извлечение нескольких типов сущностей (определения, отношения, сущности, атрибуты) в одном запросе. @@ -28,10 +32,17 @@ **Проверка схемы**: Поддержка проверки JSON-схемы для отдельных объектов. **Дискриминированные объединения**: Поддержка выходных данных смешанных типов с использованием поля `type` в качестве дискриминатора. +<<<<<<< HEAD **Минимальные изменения API**: Расширение существующей конфигурации запросов с добавлением нового типа ответа и ключа схемы. ## Обзор +======= +**Минимальные изменения API**: Расширение существующей конфигурации запросов с помощью нового + типа ответа и ключа схемы. + +## Контекст +>>>>>>> 82edf2d (New md files from RunPod) ### Текущая архитектура @@ -192,7 +203,11 @@ class Prompt: #### Класс Prompt Существующий класс `Prompt` не требует изменений. Поле `schema` используется повторно +<<<<<<< HEAD для JSONL, а его интерпретация определяется `response_type`: +======= +для JSONL, и его интерпретация определяется `response_type`: +>>>>>>> 82edf2d (New md files from RunPod) ```python class Prompt: @@ -402,7 +417,11 @@ async def invoke(self, id, input, llm): Разбор JSONL с допустимыми входными данными. Разбор JSONL с пустыми строками. +<<<<<<< HEAD Разбор JSONL с блоками форматированного текста Markdown. +======= +Разбор JSONL с блоками кода Markdown. +>>>>>>> 82edf2d (New md files from RunPod) Разбор JSONL с обрезанной последней строкой. Разбор JSONL со строками, содержащими недопустимый JSON. Проверка схемы с использованием `oneOf` для дискриминируемых объединений. @@ -410,12 +429,21 @@ async def invoke(self, id, input, llm): ### Интеграционные тесты +<<<<<<< HEAD Комплексная извлечение данных с использованием подсказок JSONL. Извлечение данных с имитацией усечения (искусственно ограниченный ответ). Извлечение данных смешанных типов с использованием дискриминатора типов. Извлечение данных онтологии со всеми тремя типами. ### Тесты качества извлечения данных. +======= +Комплексная извлечение с подсказками JSONL. +Извлечение с имитацией усечения (искусственно ограниченный ответ). +Извлечение смешанных типов с использованием дискриминатора типа. +Извлечение онтологии со всеми тремя типами. + +### Тесты качества извлечения. +>>>>>>> 82edf2d (New md files from RunPod) Сравнение результатов извлечения: формат JSONL против массива JSON. Проверка устойчивости к усечению: JSONL возвращает частичные результаты, в то время как JSON - нет. diff --git a/docs/tech-specs/jsonl-prompt-output.tr.md b/docs/tech-specs/jsonl-prompt-output.tr.md index 92eef3a0..0b86ae8e 100644 --- a/docs/tech-specs/jsonl-prompt-output.tr.md +++ b/docs/tech-specs/jsonl-prompt-output.tr.md @@ -21,6 +21,7 @@ Bu uygulama, aşağıdaki kullanım senaryolarını destekler: ## Hedefler +<<<<<<< HEAD **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. @@ -30,6 +31,17 @@ Bu uygulama, aşağıdaki kullanım senaryolarını destekler: **Minimum API Değişiklikleri**: Mevcut istem yapılandırmasını, yeni yanıt türü ve şema anahtarıyla genişletir. +======= +**Geriye Dönük Uyumluluk**: `response-type: "text"` ve + `response-type: "json"` kullanan mevcut istemler, herhangi bir değişiklik yapılmadan çalışmaya devam eder. +**Kesme Direnci**: 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ı destekleyin. +**Ayırıcı Birleşimler**: `type` alanı kullanılarak farklı türlerde çıktıları destekleyin. + ayırıcı. +**Minimum API Değişiklikleri**: Mevcut istem yapılandırmasını yeni + yanıt türü ve şema anahtarıyla genişletin. +>>>>>>> 82edf2d (New md files from RunPod) ## Arka Plan @@ -41,7 +53,11 @@ Bu uygulama, aşağıdaki kullanım senaryolarını destekler: 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` +<<<<<<< HEAD `trustgraph-flow/trustgraph/template/prompt_manager.py`'daki mevcut uygulama: +======= +Mevcut uygulama `trustgraph-flow/trustgraph/template/prompt_manager.py` içinde: +>>>>>>> 82edf2d (New md files from RunPod) ```python class Prompt: @@ -56,11 +72,19 @@ class Prompt: Çıkarma komutları, çıktıyı JSON dizileri (`[{...}, {...}, ...]`) olarak istediğinde: +<<<<<<< HEAD **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. +======= +**Kesme bozulması**: 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 veya hiçbir işleme**: İşlemeye başlamadan önce tam çıktının alınması 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 artar. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -72,9 +96,15 @@ Bu özellik, her çıkarılan öğenin kendi satırında bulunan tam bir JSON ne Mevcut `"text"` ve `"json"` türlerinin yanı sıra yeni bir yanıt türü `"jsonl"` ekleyin. +<<<<<<< HEAD #### Yapılandırma Değişiklikleri +======= +#### Yapılandırma Değişiklikleri + +**Yeni yanıt türü değeri:** +>>>>>>> 82edf2d (New md files from RunPod) ``` "response-type": "jsonl" @@ -127,6 +157,7 @@ konular, satırlar) çıkaran istemler için, çıktı her satırda bir JSON nes ] ``` +<<<<<<< HEAD Eğer LLM, 2. satırdan sonra kesilirse, JSON dizisi formatı geçersiz bir JSON oluşturur, ancak JSONL iki geçerli nesne üretir. @@ -134,6 +165,15 @@ ancak JSONL iki geçerli nesne üretir. 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"` +======= +Eğer LLM, 2. satırdan sonra kesilirse, JSON dizisi formatı geçersiz bir JSON oluştururken, +JSONL ise 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ı ve +ilişkiler veya varlıklar, ilişkiler ve özellikler) istemler için, bir `"type"` +>>>>>>> 82edf2d (New md files from RunPod) alanını ayırıcı olarak kullanın: **İstem çıktısı formatı:** @@ -320,6 +360,7 @@ Aşağıdaki istekler JSONL formatına aktarılmalıdır: #### Müşteri Perspektifi +<<<<<<< HEAD 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. @@ -353,11 +394,50 @@ Tam ayrıştırma hatası: Uyarı günlükleriyle boş bir liste `[]` döndü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. +======= +JSONL ayrıştırması, istek hizmeti API kullanıcıları için şeffaftır. Ayrıştırma, isteğin +sunucu tarafında gerçekleşir ve yanıt, standart +`PromptResponse.object` alanı aracılığıyla seri hale getirilmiş bir JSON dizisi olarak döndürülür. + +Müşteriler, istek hizmetini (`PromptClient.prompt()` veya benzeri aracılığıyla) çağırdığında: + +**`response-type: "json"`** dizi şeması ile → müşteri, Python `list` alır +**`response-type: "jsonl"`** → müşteri, Python `list` alır + +Müşteri açısından, her iki yöntem de aynı veri yapılarını döndürür. Fark, yalnızca LLM çıktısının +sunucu tarafında nasıl ayrıştırıldığıdır: + +JSON dizisi formatı: Tek `json.loads()` çağrısı; kesintiye uğratılırsa tamamen başarısız olur +JSONL formatı: Satır satır ayrıştırma; kesintiye uğratılırsa kısmi sonuçlar verir + +Bu, çıkarma isteklerinden gelen listeleri bekleyen mevcut müşteri kodunun, +istekleri 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()` yöntemi bir +`list[dict]` döndürür ve bu, başarıyla ayrıştırılmış ve doğrulanmış tüm nesneleri içerir. +Bu liste daha sonra `PromptResponse.object` alanı için JSON'a seri hale getirilir. + +#### Hata Yönetimi + +Boş sonuçlar: Uyarı günlüğü ile boş bir liste `[]` döndürülür +Kısmi ayrıştırma hatası: Başarıyla ayrıştırılmış nesnelerin listesi, hatalar için + uyarı günlükleriyle birlikte döndürülür +Tam ayrıştırma hatası: Uyarı günlükleriyle boş bir liste `[]` döndürülür + +Bu, ayrıştırma hatası durumunda `RuntimeError`'i yükselten `response-type: "json"`'dan farklıdır. +JSONL için esnek davranış, kesintiye karşı dayanıklılık sağlamak için kasıtlıdır. +>>>>>>> 82edf2d (New md files from RunPod) ### Yapılandırma Örneği +<<<<<<< HEAD Tam istem yapılandırma örneği: +======= +Tam istek yapılandırma örneği: +>>>>>>> 82edf2d (New md files from RunPod) ```json { @@ -391,12 +471,21 @@ Tam istem yapılandırma örneği: ## Performans Hususları **Bellek**: Satır satır ayrıştırma, tam JSON dizilerini yüklemekten daha az bellek kullanır. +<<<<<<< HEAD **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 +======= + +**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 +>>>>>>> 82edf2d (New md files from RunPod) ### Birim Testleri @@ -440,7 +529,11 @@ Kesme dayanıklılığını doğrulayın: JSONL, JSON'un başarısız olduğu du ### 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 +<<<<<<< HEAD 2. `type` alanına göre karma türdeki çıkarma sonuçlarını kategorize eden kodu güncelleyin +======= +2. `type` alanıyla karma türdeki çıkarma türlerini sınıflandıran kodu güncelleyin +>>>>>>> 82edf2d (New md files from RunPod) 3. Çıkarma çıktısı formatı hakkında doğrulama yapan testleri güncelleyin ## Açık Sorular diff --git a/docs/tech-specs/jsonl-prompt-output.zh-cn.md b/docs/tech-specs/jsonl-prompt-output.zh-cn.md index 14d86082..03d3acea 100644 --- a/docs/tech-specs/jsonl-prompt-output.zh-cn.md +++ b/docs/tech-specs/jsonl-prompt-output.zh-cn.md @@ -2,12 +2,20 @@ ## 概述 +<<<<<<< HEAD 本规范描述了在 TrustGraph 中,用于提示响应的 JSONL(JSON Lines)输出格式的实现。JSONL 允许在大型语言模型(LLM)的响应中,以一种能够抵抗截断的方式提取结构化数据,从而解决了当 LLM 响应达到输出令牌限制时,JSON 数组输出可能被损坏的关键问题。 +======= +本规范描述了在 TrustGraph 中,用于提示响应的 JSONL(JSON Lines)输出格式的实现。JSONL 允许在大型语言模型 (LLM) 响应中提取结构化数据,即使在响应达到输出令牌限制时,也能保持数据的完整性。 +JSONL 能够实现对结构化数据的截断鲁棒性提取,解决了当 LLM 响应达到输出令牌限制时,JSON 数组输出可能被破坏的关键问题。 +>>>>>>> 82edf2d (New md files from RunPod) +<<<<<<< HEAD +======= +>>>>>>> 82edf2d (New md files from RunPod) 本实现支持以下用例: 1. **抗截断提取**: 即使当 @@ -23,11 +31,19 @@ **向后兼容性**: 仍然可以使用 `response-type: "text"` 和 `response-type: "json"` 的现有提示,无需修改即可继续工作。 +<<<<<<< HEAD **截断恢复能力**: 即使是部分 LLM 输出,也能产生部分有效的结果, 而不是完全失败。 **模式验证**: 支持对单个对象进行 JSON 模式验证。 **区分联合类型**: 支持使用 `type` 字段作为区分器的混合类型输出。 **最小的 API 变更**: 通过新的 +======= +**截断鲁棒性**: 即使是部分 LLM 输出,也能产生部分有效的结果, + 而不是完全失败。 +**模式验证**: 支持对单个对象进行 JSON 模式验证。 +**区分联合**: 支持使用 `type` 字段作为区分器的混合类型输出。 + **最小的 API 更改**: 通过新的 +>>>>>>> 82edf2d (New md files from RunPod) 响应类型和模式键来扩展现有的提示配置。 @@ -102,7 +118,11 @@ class Prompt: } ``` +<<<<<<< HEAD 这避免了对提示配置工具和编辑器的修改。 +======= +这避免了对提示配置工具和编辑器的更改。 +>>>>>>> 82edf2d (New md files from RunPod) ### JSONL 格式规范 @@ -127,8 +147,13 @@ class Prompt: ] ``` +<<<<<<< HEAD 如果大型语言模型在第2行之后截断,JSON数组格式会产生无效的JSON, 而JSONL会产生两个有效的对象。 +======= +如果大型语言模型在第2行之后截断,JSON数组格式将产生无效的JSON, +而JSONL格式将产生两个有效的对象。 +>>>>>>> 82edf2d (New md files from RunPod) #### 混合类型提取(区分联合) @@ -144,7 +169,11 @@ class Prompt: {"type": "relationship", "subject": "RNA", "predicate": "transcribed_from", "object": "DNA", "object-entity": true} ``` +<<<<<<< HEAD **区分联合的模式使用 `oneOf`:** +======= +**区分联合的模式使用 `oneOf`:** +>>>>>>> 82edf2d (New md files from RunPod) ```json { "response-type": "jsonl", @@ -175,9 +204,15 @@ class Prompt: } ``` +<<<<<<< HEAD #### 本体抽取 对于基于本体的抽取,涉及实体、关系和属性: +======= +#### 本体提取 + +对于基于本体的实体、关系和属性提取: +>>>>>>> 82edf2d (New md files from RunPod) **提示输出格式:** ``` @@ -326,10 +361,17 @@ JSONL 解析对提示服务 API 的调用者是透明的。解析过程 当客户端调用提示服务(通过 `PromptClient.prompt()` 或类似方式时): +<<<<<<< HEAD **`response-type: "json"`**(带有数组模式)→ 客户端接收 Python `list` **`response-type: "jsonl"`** → 客户端接收 Python `list` 从客户端的角度来看,两者都返回相同的的数据结构。 +======= +**`response-type: "json"`** (带有数组模式) → 客户端接收 Python `list` +**`response-type: "jsonl"`** → 客户端接收 Python `list` + +从客户端的角度来看,两者都返回相同的数据结构。 +>>>>>>> 82edf2d (New md files from RunPod) 区别完全在于服务器端如何解析 LLM 的输出: JSON 数组格式:单个 `json.loads()` 调用;如果被截断,则完全失败。 @@ -385,7 +427,11 @@ JSONL 格式:逐行解析;如果被截断,则产生部分结果。 **输入验证**: JSON 解析使用标准的 `json.loads()`,这可以防止注入攻击。 **模式验证**: 使用 ⟦CODE_0⟧ 来强制执行模式。 **模式验证**: 使用 `jsonschema.validate()` 进行模式强制。 +<<<<<<< HEAD **没有新的攻击面:** JSONL 解析比 JSON 数组解析更安全,因为它采用逐行处理的方式。 +======= +**无新的攻击面**: JSONL 解析比 JSON 数组解析更安全,因为采用逐行处理的方式。 +>>>>>>> 82edf2d (New md files from RunPod) parsing due to line-by-line processing ## 性能考量 @@ -406,11 +452,19 @@ JSONL 格式:逐行解析;如果被截断,则产生部分结果。 使用截断的最终行的 JSONL 解析 包含穿插无效 JSON 行的 JSONL 解析 使用 `oneOf` 区分联合的模式验证 +<<<<<<< HEAD 向后兼容性:现有的 `"text"` 和 `"json"` 提示词保持不变 ### 集成测试 使用 JSONL 提示词的端到端提取 +======= +向后兼容性:现有的 `"text"` 和 `"json"` 提示保持不变 + +### 集成测试 + +使用 JSONL 提示的端到端提取 +>>>>>>> 82edf2d (New md files from RunPod) 使用模拟截断的提取(人为限制响应) 使用类型区分器的混合类型提取 使用所有三种类型的本体提取 @@ -428,6 +482,7 @@ JSONL 格式:逐行解析;如果被截断,则产生部分结果。 2. 扩展 `invoke()` 以处理 `response-type: "jsonl"` 3. 添加单元测试 +<<<<<<< HEAD ### 第二阶段:提示词迁移 1. 更新 `extract-definitions` 提示词和配置 @@ -436,12 +491,26 @@ JSONL 格式:逐行解析;如果被截断,则产生部分结果。 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` 提示和配置 +>>>>>>> 82edf2d (New md files from RunPod) ### 第三阶段:下游更新 1. 更新任何使用提取结果的代码,使其能够处理列表返回类型。 2. 更新根据 `type` 字段对混合类型提取进行分类的代码。 +<<<<<<< HEAD 3. 更新用于断言提取输出格式的测试。 +======= +3. 更新断言提取输出格式的测试。 +>>>>>>> 82edf2d (New md files from RunPod) ## 待解决问题 diff --git a/docs/tech-specs/large-document-loading.ar.md b/docs/tech-specs/large-document-loading.ar.md new file mode 100644 index 00000000..21f74b70 --- /dev/null +++ b/docs/tech-specs/large-document-loading.ar.md @@ -0,0 +1,984 @@ +# المواصفات الفنية لتحميل المستندات الكبيرة + +## نظرة عامة + +تتناول هذه المواصفات مشكلات قابلية التوسع وتجربة المستخدم عند تحميل +المستندات الكبيرة في TrustGraph. تعالج البنية الحالية تحميل المستندات +كعملية ذرية واحدة، مما يتسبب في ضغط الذاكرة في نقاط متعددة في +المسار ولا يوفر أي ملاحظات أو خيارات استرداد للمستخدمين. + +تستهدف هذه التنفيذ حالات الاستخدام التالية: + +1. **معالجة ملفات PDF الكبيرة**: تحميل ومعالجة ملفات PDF متعددة الميجابايت + دون استنفاد الذاكرة +2. **التحميل القابل للاستئناف**: السماح للتحميلات المتقطعة بمواصلة من حيث + توقفت بدلاً من إعادة البدء +3. **ملاحظات التقدم**: تزويد المستخدمين برؤية في الوقت الفعلي لعملية التحميل + والمعالجة +4. **معالجة فعالة للذاكرة**: معالجة المستندات بطريقة متدفقة + دون الاحتفاظ بملفات كاملة في الذاكرة + +## الأهداف + +**التحميل التدريجي**: دعم تحميل المستندات على شكل أجزاء عبر REST و WebSocket +**التحويلات القابلة للاستئناف**: تمكين الاسترداد من التحميلات المتقطعة +**رؤية التقدم**: توفير ملاحظات حول تقدم التحميل/المعالجة للعملاء +**كفاءة الذاكرة**: القضاء على التخزين المؤقت للمستند بأكمله في جميع أنحاء المسار +**التوافق مع الإصدارات السابقة**: تظل سير العمل الحالية للمستندات الصغيرة دون تغيير +**المعالجة المتدفقة**: تعمل فك ترميز PDF وتقطيع النص على التدفقات + +## الخلفية + +### البنية الحالية + +يمر تدفق إرسال المستندات عبر المسار التالي: + +1. يرسل **العميل** المستند عبر REST (`POST /api/v1/librarian`) أو WebSocket +2. يتلقى **بوابة API** الطلب الكامل مع محتوى المستند المشفر بـ base64 +3. يترجم **LibrarianRequestor** الطلب إلى رسالة Pulsar +4. يتلقى **خدمة Librarian** الرسالة، ويفك تشفير المستند في الذاكرة +5. يقوم **BlobStore** بتحميل المستند إلى Garage/S3 +6. تخزن **Cassandra** البيانات الوصفية مع مرجع الكائن +7. للمعالجة: يتم استرداد المستند من S3، وفك ترميزه، وتقطيعه - كل ذلك في الذاكرة + +الملفات الرئيسية: +نقطة الدخول REST/WebSocket: `trustgraph-flow/trustgraph/gateway/service.py` +النواة الأساسية لـ Librarian: `trustgraph-flow/trustgraph/librarian/librarian.py` +تخزين الكائنات الثنائية: `trustgraph-flow/trustgraph/librarian/blob_store.py` +جداول Cassandra: `trustgraph-flow/trustgraph/tables/library.py` +مخطط API: `trustgraph-base/trustgraph/schema/services/library.py` + +### القيود الحالية + +تحتوي التصميم الحالي على عدة مشكلات مركبة في الذاكرة وتجربة المستخدم: + +1. **عملية تحميل ذرية**: يجب إرسال المستند بأكمله في + طلب واحد. تتطلب المستندات الكبيرة طلبات طويلة الأمد بدون + مؤشر للتقدم ولا توجد آلية لإعادة المحاولة في حالة فشل الاتصال. + +2. **تصميم API**: تتوقع كل من واجهات برمجة تطبيقات REST و WebSocket المستند + بأكمله في رسالة واحدة. يحتوي المخطط (`LibrarianRequest`) على `content` + حقل واحد يحتوي على المستند المشفر بـ base64 بأكمله. + +3. **ذاكرة Librarian**: تقوم خدمة Librarian بفك تشفير المستند بأكمله + في الذاكرة قبل تحميله إلى S3. بالنسبة لملف PDF بحجم 500 ميجابايت، هذا يعني + الاحتفاظ بـ 500 ميجابايت + في ذاكرة العملية. + +4. **ذاكرة فك ترميز PDF**: عند بدء المعالجة، يقوم فك ترميز PDF بتحميل + ملف PDF بأكمله في الذاكرة لاستخراج النص. تتطلب مكتبات PyPDF وما شابه ذلك + عادةً الوصول إلى المستند بأكمله. + +5. **ذاكرة القطع**: يتلقى برنامج القطع النص المستخرج بالكامل + ويحتفظ به في الذاكرة أثناء إنتاج الأجزاء. + +**مثال على تأثير الذاكرة** (ملف PDF بحجم 500 ميجابايت): +البوابة: ~700 ميجابايت (نفقات ترميز base64) +Librarian: ~500 ميجابايت (بايت مُفككة) +فك ترميز PDF: ~500 ميجابايت + مخازن مؤقتة للاستخراج +القطع: نص مستخرج (متغير، قد يصل إلى 100 ميجابايت +) + +يمكن أن تتجاوز الذاكرة القصوى لملف مستند كبير واحد 2 جيجابايت. + +## التصميم الفني + +### مبادئ التصميم + +1. **واجهة API**: يمر كل تفاعل عميل من خلال واجهة برمجة تطبيقات Librarian. العملاء + ليس لديهم وصول مباشر أو معرفة بالتخزين الأساسي S3/Garage. + +2. **تحميل متعدد الأجزاء لـ S3**: استخدم تحميل متعدد الأجزاء قياسي لـ S3. + هذا مدعوم على نطاق واسع في الأنظمة المتوافقة مع S3 (AWS S3، MinIO، Garage، + Ceph، DigitalOcean Spaces، Backblaze B2، إلخ) مما يضمن إمكانية النقل. + +3. **الإكمال الذري**: عمليات تحميل متعددة الأجزاء لـ S3 ذرية بطبيعتها - يتم تحميل + الأجزاء التي تم تحميلها والتي لا تظهر حتى يتم استدعاء `CompleteMultipartUpload`. لا توجد + ملفات مؤقتة أو عمليات إعادة تسمية مطلوبة. + +4. **حالة قابلة للتتبع**: يتم تتبع جلسات التحميل في Cassandra، مما يوفر + رؤية للتحميلات غير المكتملة ويمكنه تمكين إمكانية الاستئناف. + +### تدفق التحميل المقسم + +``` +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) │ +``` + +العميل لا يتفاعل أبدًا مع S3 مباشرةً. يقوم المكتبار بترجمة البيانات بين +واجهة برمجة التطبيقات الخاصة بنا لتحميل البيانات على أجزاء و عمليات S3 متعددة الأجزاء داخليًا. + +### عمليات واجهة برمجة التطبيقات الخاصة بالمكتبار + +#### `begin-upload` + +تهيئة جلسة تحميل بيانات على أجزاء. + +الطلب: +```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 +} +``` + +الرد: +```json +{ + "upload-id": "upload-abc-123", + "chunk-size": 5242880, + "total-chunks": 100 +} +``` + +أمين المكتبة: +1. يقوم بإنشاء رمز فريد `upload_id` و `object_id` (معرف فريد لتخزين الكائنات) +2. يستدعي S3 `CreateMultipartUpload`، ويتلقى `s3_upload_id` +3. يقوم بإنشاء سجل جلسة في Cassandra +4. يعيد `upload_id` إلى العميل + +#### `upload-chunk` + +تحميل جزء واحد. + +الطلب: +```json +{ + "operation": "upload-chunk", + "upload-id": "upload-abc-123", + "chunk-index": 0, + "content": "" +} +``` + +الرد: +```json +{ + "upload-id": "upload-abc-123", + "chunk-index": 0, + "chunks-received": 1, + "total-chunks": 100, + "bytes-received": 5242880, + "total-bytes": 524288000 +} +``` + +أمين المكتبة: +1. البحث عن الجلسة باستخدام `upload_id` +2. التحقق من الملكية (يجب أن يتطابق المستخدم مع منشئ الجلسة) +3. استدعاء S3 `UploadPart` مع بيانات الجزء، وتلقي `etag` +4. تحديث سجل الجلسة بفهرس الجزء وعلامة etag +5. إرجاع التقدم إلى العميل + +يمكن إعادة محاولة الأجزاء الفاشلة - فقط أرسل `chunk-index` مرة أخرى. + +#### `complete-upload` + +إنهاء التحميل وإنشاء المستند. + +الطلب: +```json +{ + "operation": "complete-upload", + "upload-id": "upload-abc-123" +} +``` + +الرد: +```json +{ + "document-id": "doc-123", + "object-id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +أمين المكتبة: +1. يبحث عن الجلسة، ويتحقق من استلام جميع الأجزاء. +2. يستدعي S3 `CompleteMultipartUpload` مع علامات الجزء (S3 تدمج الأجزاء داخليًا - لا توجد تكلفة ذاكرة لأمين المكتبة). + 3. ينشئ سجل مستند في Cassandra مع البيانات الوصفية وإشارة الكائن. +4. يحذف سجل جلسة التحميل. +5. يعيد معرف المستند إلى العميل. +6. + +#### `abort-upload` + +إلغاء عملية تحميل قيد التقدم. + +الطلب: +```json +{ + "operation": "abort-upload", + "upload-id": "upload-abc-123" +} +``` + +أمين المكتبة: +1. يستدعي `AbortMultipartUpload` لتنظيف الأجزاء. +2. يحذف سجل الجلسة من Cassandra. + +#### `get-upload-status` + +حالة استعلام عن عملية تحميل (لإمكانية الاستئناف). + +الطلب: +```json +{ + "operation": "get-upload-status", + "upload-id": "upload-abc-123" +} +``` + +الرد: +```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` + +عرض قائمة التحميلات غير المكتملة لمستخدم. + +الطلب: +```json +{ + "operation": "list-uploads" +} +``` + +الرد: +```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" + } + ] +} +``` + +### تخزين جلسات التحميل + +تتبع عمليات التحميل الجارية في 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); +``` + +**سلوك TTL:** +تنتهي الجلسات بعد 24 ساعة إذا لم تكتمل. +عندما تنتهي صلاحية TTL في Cassandra، يتم حذف سجل الجلسة. +يتم تنظيف أجزاء S3 المهجورة بواسطة سياسة دورة حياة S3 (يتم التكوين على الحاوية). + +### معالجة الأخطاء والتماسك + +**فشل تحميل الأجزاء:** +يحاول العميل إعادة تحميل الجزء الذي فشل (بنفس `upload_id` و `chunk-index`). +عملية S3 `UploadPart` متسقة لنفس رقم الجزء. +تتتبع الجلسة الأجزاء التي نجحت. + +**انقطاع اتصال العميل أثناء التحميل:** +تظل الجلسة موجودة في Cassandra مع تسجيل الأجزاء المستلمة. +يمكن للعميل استدعاء `get-upload-status` لمعرفة ما هو مفقود. +يمكن استئناف التحميل عن طريق تحميل الأجزاء المفقودة فقط، ثم `complete-upload`. + +**فشل التحميل الكامل:** +عملية S3 `CompleteMultipartUpload` ذرية - إما أنها تنجح بالكامل أو تفشل. +في حالة الفشل، تظل الأجزاء موجودة ويمكن للعميل إعادة محاولة `complete-upload`. +لا يمكن رؤية أي مستند جزئي على الإطلاق. + +**انتهاء صلاحية الجلسة:** +تحذف Cassandra سجل الجلسة بعد 24 ساعة. +تقوم سياسة دورة حياة حاوية S3 بتنظيف عمليات التحميل متعددة الأجزاء غير المكتملة. +لا يلزم أي تنظيف يدوي. + +### تماسك S3 متعدد الأجزاء + +توفر عمليات تحميل S3 متعددة الأجزاء تماسكًا مدمجًا: + +1. **الأجزاء غير مرئية**: لا يمكن الوصول إلى الأجزاء التي تم تحميلها ككائنات. + إنها موجودة فقط كأجزاء من عملية تحميل متعددة الأجزاء غير مكتملة. + +2. **الإكمال الذري**: `CompleteMultipartUpload` إما أنها تنجح (يظهر الكائن بشكل ذري) أو تفشل (لا يتم إنشاء كائن). لا توجد حالة جزئية. + + +3. **لا حاجة لإعادة التسمية**: يتم تحديد مفتاح الكائن النهائي في وقت + `CreateMultipartUpload`. يتم دمج الأجزاء مباشرة في هذا المفتاح. + +4. **الدمج من جانب الخادم**: تقوم S3 بدمج الأجزاء داخليًا. لا يقرأ أمين المكتبة + الأجزاء مرة أخرى - لا توجد تكلفة إضافية للذاكرة بغض النظر عن حجم المستند. + +### امتدادات BlobStore + +**الملف:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +أضف طرق التحميل متعددة الأجزاء: + +```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() +``` + +### اعتبارات حجم الجزء + +**الحد الأدنى لـ S3**: 5 ميجابايت لكل جزء (باستثناء الجزء الأخير) +**الحد الأقصى لـ S3**: 10,000 جزء لكل عملية تحميل +**الإعداد الافتراضي العملي**: أجزاء بحجم 5 ميجابايت + مستند بحجم 500 ميجابايت = 100 جزء + مستند بحجم 5 جيجابايت = 1,000 جزء +**دقة التقدم**: أجزاء أصغر = تحديثات تقدم أكثر دقة +**كفاءة الشبكة**: أجزاء أكبر = عدد أقل من عمليات الإرسال + +يمكن تكوين حجم الجزء من قبل العميل ضمن الحدود (5 ميجابايت - 100 ميجابايت). + +### معالجة المستندات: الاسترجاع المتدفق + +يهدف سير عمل التحميل إلى إدخال المستندات إلى التخزين بكفاءة. يهدف سير عمل المعالجة إلى استخراج وتقسيم المستندات دون تحميلها بالكامل في الذاكرة. + + +#### مبدأ التصميم: المعرف، وليس المحتوى + + +حاليًا، عند بدء المعالجة، يتدفق محتوى المستند عبر رسائل Pulsar. يؤدي هذا إلى تحميل المستندات بأكملها في الذاكرة. بدلاً من ذلك: + + +تحمل رسائل Pulsar فقط **معرف المستند** +تقوم المعالجات باسترداد محتوى المستند مباشرة من المكتبة +يتم الاسترداد كـ **تدفق إلى ملف مؤقت** +يعمل التحليل الخاص بالمستند (PDF، نص، إلخ) مع الملفات، وليس مخازن الذاكرة + +هذا يجعل المكتبة غير معتمدة على هيكل المستند. يظل تحليل PDF واستخراج النص ومنطق محدد التنسيق الأخرى في فك التشفير الخاص بها. + + +#### سير المعالجة + +``` +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) لخدمة أمين المكتبة. + +إضافة عملية استرجاع مستندات متدفقة: + +**`stream-document`** + +الطلب: +```json +{ + "operation": "stream-document", + "document-id": "doc-123" +} +``` + +الاستجابة: أجزاء ثنائية متدفقة (وليست استجابة واحدة). + +بالنسبة لواجهة برمجة التطبيقات REST، فإن هذا يُرجع استجابة متدفقة مع `Transfer-Encoding: chunked`. + +بالنسبة للمكالمات الداخلية بين الخدمات (من المعالج إلى أمين المكتبة)، يمكن أن يكون ذلك: +بث مباشر من S3 عبر عنوان URL مسبق التوقيع (إذا سمحت الشبكة الداخلية بذلك). +استجابات مقسمة عبر بروتوكول الخدمة. +نقطة نهاية مخصصة للبث. + +المتطلب الأساسي: تتدفق البيانات في أجزاء، ولا يتم تخزينها بالكامل مؤقتًا في أمين المكتبة. + +#### تغييرات في فك ترميز PDF. + +**التنفيذ الحالي** (يستهلك الكثير من الذاكرة): + +```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 +``` + +**تنفيذ جديد** (ملف مؤقت، تدريجي): + +```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 +``` + +ملف تعريف الذاكرة: +ملف مؤقت على القرص: حجم ملف PDF (القرص رخيص). +في الذاكرة: صفحة واحدة من النص في كل مرة. +أقصى استخدام للذاكرة: محدود، ولا يعتمد على حجم المستند. + +#### تغييرات في وحدة فك ترميز المستندات النصية. + +بالنسبة للمستندات النصية العادية، الأمر أبسط حتى - لا حاجة لملف مؤقت: + +```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 +``` + +يمكن لملفات النصوص أن تُرسل مباشرةً دون الحاجة إلى ملف مؤقت نظرًا لأنها +مُنظمة بشكل خطي. + +#### تكامل وحدة تقسيم البيانات (Chunker). + +تتلقى وحدة تقسيم البيانات مُكررًا للنصوص (صفحات أو فقرات) وتُنتج +أجزاء بشكل تدريجي: + +```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 +``` + +#### خط أنابيب المعالجة الشاملة + +```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) +``` + +في أي نقطة، لا يتم الاحتفاظ بالمستند الكامل أو النص المستخرج بالكامل في الذاكرة. + +#### اعتبارات ملفات مؤقتة + +**الموقع**: استخدم دليل النظام المؤقت (`/tmp` أو ما يعادله). بالنسبة إلى +عمليات النشر في حاويات، تأكد من أن الدليل المؤقت لديه مساحة كافية +وأنه موجود على مساحة تخزين سريعة (وليس مثبتًا على الشبكة إن أمكن). + +**التنظيف**: استخدم مديري السياق (`with tempfile...`) لضمان التنظيف +حتى في حالة حدوث استثناءات. + +**المعالجة المتزامنة**: تحصل كل مهمة معالجة على ملف مؤقت خاص بها. +لا توجد تعارضات بين معالجة المستندات المتوازية. + +**مساحة القرص**: الملفات المؤقتة قصيرة الأجل (مدة المعالجة). بالنسبة إلى +ملف PDF بحجم 500 ميجابايت، يلزم وجود مساحة مؤقتة تبلغ 500 ميجابايت أثناء المعالجة. يمكن +تطبيق حد الحجم في وقت التحميل إذا كانت مساحة القرص محدودة. + +### واجهة المعالجة الموحدة: المستندات الفرعية + +يجب أن تساهم عملية استخراج PDF ومعالجة المستندات النصية في نفس +خط المعالجة اللاحق (تقسيم إلى أجزاء → تضمينات → تخزين). لتحقيق ذلك باستخدام +واجهة "جلب حسب المعرف" متسقة، يتم تخزين كتل النص المستخرجة مرة أخرى +في المكتبة كمستندات فرعية. + +#### سير العمل مع المستندات الفرعية + +``` +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] +``` + +تمتلك وحدة التقسيم واجهة موحدة واحدة: +استقبال معرف المستند (عبر Pulsar) +تدفق المحتوى من أمين المكتبة +تقسيم المحتوى + +لا تعرف أو تهتم ما إذا كان المعرف يشير إلى: +مستند نصي تم تحميله بواسطة المستخدم +جزء نصي مستخرج من صفحة PDF +أي نوع مستند مستقبلي + +#### بيانات وصفية للمستندات الفرعية + +قم بتوسيع مخطط المستند لتتبع العلاقات بين المستندات الرئيسية والفرعية: + +```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); +``` + +**أنواع المستندات:** + +| `document_type` | الوصف | +|-----------------|-------------| +| `source` | مستند تم تحميله بواسطة المستخدم (PDF، نص، إلخ) | +| `extracted` | مشتق من مستند مصدر (مثل نص صفحة PDF) | + +**حقول البيانات الوصفية:** + +| الحقل | المستند المصدر | المستند الفرعي المستخرج | +|-------|-----------------|-----------------| +| `id` | مقدم من المستخدم أو تم إنشاؤه | تم إنشاؤه (مثل `{parent-id}-page-{n}`) | +| `parent_id` | `NULL` | معرف المستند الأصل | +| `document_type` | `source` | `extracted` | +| `kind` | `application/pdf`، إلخ. | `text/plain` | +| `title` | مقدم من المستخدم | تم إنشاؤه (مثل "الصفحة 3 من Report.pdf") | +| `user` | مستخدم مصرح له | نفس المستند الأصل | + +#### واجهة برمجة تطبيقات أمين المكتبة للمستندات الفرعية + +**إنشاء المستندات الفرعية** (داخلي، يستخدم بواسطة 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": "" +} +``` + +بالنسبة للنصوص الصغيرة المستخرجة (عادةً ما يكون نص الصفحة أقل من 100 كيلوبايت)، فإن التحميل في عملية واحدة مقبول. بالنسبة لاستخراج النصوص الكبيرة جدًا، يمكن استخدام التحميل المقسم. + +**عرض المستندات الفرعية** (لأغراض التصحيح/الإدارة): + +**عرض المستندات الفرعية** (لأغراض التصحيح/الإدارة): + +```json +{ + "operation": "list-children", + "parent-id": "doc-123" +} +``` + +الرد: +```json +{ + "children": [ + { "id": "doc-123-page-1", "title": "Page 1", "kind": "text/plain" }, + { "id": "doc-123-page-2", "title": "Page 2", "kind": "text/plain" }, + ... + ] +} +``` + +#### السلوك الظاهر للمستخدم + +**السلوك الافتراضي `list-documents`:** + +```sql +SELECT * FROM document WHERE user = ? AND parent_id IS NULL; +``` + +تظهر فقط المستندات الرئيسية (المصدر) في قائمة المستندات الخاصة بالمستخدم. +يتم استبعاد المستندات الفرعية افتراضيًا. + +**علامة "include-children" اختيارية** (للمسؤولين/تصحيح الأخطاء): + +```json +{ + "operation": "list-documents", + "include-children": true +} +``` + +#### حذف متسلسل + +عندما يتم حذف مستند رئيسي، يجب حذف جميع العناصر التابعة له: + +```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) +``` + +#### اعتبارات التخزين + +النصوص المستخرجة قد تتضمن تكرارًا للمحتوى: +ملف PDF الأصلي مُخزن في "Garage". +النص المستخرج لكل صفحة مُخزن أيضًا في "Garage". + +هذا الحل يتيح: +**واجهة موحدة للتقطيع**: يقوم "Chunker" دائمًا باسترداد البيانات بمعرف (ID). +**الاستئناف/إعادة المحاولة**: يمكن إعادة تشغيل العملية في مرحلة "Chunker" دون إعادة استخراج ملف PDF. +**تصحيح الأخطاء**: يمكن فحص النص المستخرج. +**فصل المهام**: خدمة استخراج ملف PDF وخدمة "Chunker" هما خدمتان مستقلتان. + +بالنسبة لملف PDF بحجم 500 ميجابايت و200 صفحة بمتوسط 5 كيلوبايت من النص لكل صفحة: +تخزين ملف PDF: 500 ميجابايت. +تخزين النص المستخرج: حوالي 1 ميجابايت إجمالاً. +التكلفة الإضافية: ضئيلة. + +#### مخرجات مُستخرج ملف PDF + +يقوم مُستخرج ملف PDF (pdf-extractor)، بعد معالجة المستند: + +1. يقوم بتحميل ملف PDF من "librarian" إلى ملف مؤقت. +2. يستخرج النص صفحةً تلو الأخرى. +3. لكل صفحة، يقوم بتخزين النص المستخرج كمستند فرعي عبر "librarian". +4. يرسل معرفات المستندات الفرعية إلى قائمة انتظار "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) +``` + +يتلقى المعالج هذه المعرفات الفرعية ويقوم بمعالجتها بنفس الطريقة التي يعالج بها مستند نصي تم تحميله بواسطة المستخدم. +كيف كان سيعالجها. + +### تحديثات العميل + +#### حزمة تطوير البرمجيات (SDK) بلغة بايثون + +يجب أن تتعامل حزمة تطوير البرمجيات (SDK) بلغة بايثون (`trustgraph-base/trustgraph/api/library.py`) مع عمليات التحميل المقسمة بشفافية. يظل الواجهة العامة دون تغيير: + + +```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"] +) +``` + +داخليًا، يكتشف الـ SDK حجم المستند ويغير الاستراتيجية: + +```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) +``` + +**استدعاءات ردود الأفعال للتقدم** (تحسين اختياري): + +```python +def add_document(self, ..., on_progress=None): + """ + on_progress: Optional callback(bytes_sent, total_bytes) + """ +``` + +هذا يسمح لواجهات المستخدم بعرض تقدم التحميل دون تغيير واجهة برمجة التطبيقات الأساسية. + +#### أدوات سطر الأوامر + +**`tg-add-library-document`** يستمر في العمل دون تغيير: + +```bash +# Works transparently for any size - SDK handles chunking internally +tg-add-library-document --file large-report.pdf --title "Large Report" +``` + +يمكن إضافة عرض اختياري للتقدم: + +```bash +tg-add-library-document --file large-report.pdf --title "Large Report" --progress +# Output: +# Uploading: 45% (225MB / 500MB) +``` + +**تمت إزالة الأدوات القديمة:** + +`tg-load-pdf` - قديمة، استخدم `tg-add-library-document` +`tg-load-text` - قديمة، استخدم `tg-add-library-document` + +**أوامر الإدارة/التصحيح** (اختياري، أولوية منخفضة): + +```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 +``` + +قد تكون هذه خيارات في الأمر الحالي بدلاً من أدوات منفصلة. + +#### تحديثات مواصفات واجهة برمجة التطبيقات (API) + +تحتاج مواصفات OpenAPI (`specs/api/paths/librarian.yaml`) إلى تحديثات فيما يلي: + +**عمليات جديدة:** + +`begin-upload` - تهيئة جلسة تحميل مقسمة +`upload-chunk` - تحميل جزء فردي +`complete-upload` - إنهاء التحميل +`abort-upload` - إلغاء التحميل +`get-upload-status` - الاستعلام عن تقدم التحميل +`list-uploads` - قائمة بالتحميلات غير المكتملة للمستخدم +`stream-document` - استرجاع المستندات المتدفقة +`add-child-document` - تخزين النص المستخرج (داخلي) +`list-children` - قائمة بالمستندات الفرعية (للمسؤول) + +**عمليات معدلة:** + +`list-documents` - إضافة معلمة `include-children` + +**مخططات جديدة:** + +`ChunkedUploadBeginRequest` +`ChunkedUploadBeginResponse` +`ChunkedUploadChunkRequest` +`ChunkedUploadChunkResponse` +`UploadSession` +`UploadProgress` + +**تحديثات مواصفات WebSocket** (`specs/websocket/`): + +قم بمحاكاة العمليات REST لعملاء WebSocket، مما يتيح تحديثات التقدم في الوقت الفعلي +أثناء التحميل. + +#### اعتبارات تجربة المستخدم (UX) + +تتيح تحديثات مواصفات واجهة برمجة التطبيقات (API) تحسينات في الواجهة الأمامية: + +**واجهة مستخدم لتقدم التحميل:** +شريط تقدم يوضح الأجزاء التي تم تحميلها +الوقت المقدر المتبقي +إمكانية الإيقاف المؤقت/الاستئناف + +**استعادة الأخطاء:** +خيار "استئناف التحميل" للتحميلات المتقطعة +قائمة بالتحميلات المعلقة عند إعادة الاتصال + +**التعامل مع الملفات الكبيرة:** +اكتشاف حجم الملف من جانب العميل +تحميل مقسم تلقائي للملفات الكبيرة +ملاحظات واضحة أثناء عمليات التحميل الطويلة + +تتطلب هذه التحسينات في تجربة المستخدم (UX) عملًا في الواجهة الأمامية يتم توجيهه بواسطة مواصفات واجهة برمجة التطبيقات (API) المحدثة. diff --git a/docs/tech-specs/large-document-loading.es.md b/docs/tech-specs/large-document-loading.es.md index b55a61ed..70f55aa1 100644 --- a/docs/tech-specs/large-document-loading.es.md +++ b/docs/tech-specs/large-document-loading.es.md @@ -13,19 +13,32 @@ Esta implementación tiene como objetivo los siguientes casos de uso: sin agotar la memoria. 2. **Cargas Reanudables**: Permitir que las cargas interrumpidas continúen desde donde se detuvieron en lugar de reiniciarse. +<<<<<<< HEAD 3. **Indicación de Progreso**: Proporcionar a los usuarios visibilidad en tiempo real del +======= +3. **Retroalimentación de Progreso**: Proporcionar a los usuarios visibilidad en tiempo real del +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD **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. +======= +**Carga Incremental**: Soporte para la carga de documentos por partes a través de REST y WebSocket. +**Transferencias Reanudables**: Permitir la recuperación de cargas interrumpidas. +**Visibilidad del Progreso**: Proporcionar retroalimentación de progreso 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 Transmisión**: La decodificación de PDF y el fragmentado de texto operan en flujos. +>>>>>>> 82edf2d (New md files from RunPod) ## Antecedentes @@ -39,7 +52,11 @@ El flujo de envío de documentos sigue la siguiente ruta: 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. +<<<<<<< HEAD 7. Para el procesamiento: el documento se recupera de S3, se decodifica y se divide en fragmentos, todo en la memoria. +======= +7. Para el procesamiento: el documento se recupera de S3, se decodifica y se divide en partes, todo en la memoria. +>>>>>>> 82edf2d (New md files from RunPod) Archivos clave: Punto de entrada REST/WebSocket: `trustgraph-flow/trustgraph/gateway/service.py` @@ -50,7 +67,11 @@ Esquema de la API: `trustgraph-base/trustgraph/schema/services/library.py` ### Limitaciones Actuales +<<<<<<< HEAD El diseño actual tiene varios problemas de memoria y experiencia de usuario que se agravan: +======= +El diseño actual tiene varios problemas de memoria y experiencia de usuario: +>>>>>>> 82edf2d (New md files from RunPod) 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 @@ -61,12 +82,21 @@ El diseño actual tiene varios problemas de memoria y experiencia de usuario que que contiene todo el documento codificado en base64. 3. **Memoria del Librarian**: El servicio librarian decodifica todo el documento +<<<<<<< HEAD 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. +======= + en la memoria antes de cargarlo en S3. Para un archivo 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 normalmente + requieren acceso a todo el documento. +>>>>>>> 82edf2d (New md files from RunPod) 5. **Memoria del Fragmentador**: El fragmentador de texto recibe todo el texto extraído y lo mantiene en la memoria mientras produce fragmentos. @@ -91,13 +121,21 @@ El pico total de memoria puede exceder los 2 GB para un solo documento grande. 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 +<<<<<<< HEAD son invisibles hasta que se llama a `CompleteMultipartUpload`. No se necesitan archivos temporales ni +======= + no son visibles hasta que se llama a `CompleteMultipartUpload`. No se necesitan archivos temporales ni +>>>>>>> 82edf2d (New md files from RunPod) 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. +<<<<<<< HEAD ### Flujo de Carga Fragmentada +======= +### Flujo de Carga por Partes +>>>>>>> 82edf2d (New md files from RunPod) ``` Client Librarian API S3/Garage @@ -157,14 +195,22 @@ Respuesta: ``` El bibliotecario: +<<<<<<< HEAD 1. Genera un `upload_id` y un `object_id` únicos (UUID para almacenamiento de blobs). +======= +1. Genera un `upload_id` y un `object_id` únicos (UUID para el almacenamiento de blobs). +>>>>>>> 82edf2d (New md files from RunPod) 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` +<<<<<<< HEAD Cargar un único fragmento. +======= +Carga un único fragmento. +>>>>>>> 82edf2d (New md files from RunPod) Solicitud: ```json @@ -195,7 +241,11 @@ El bibliotecario: 4. Actualiza el registro de la sesión con el índice del fragmento y la etiqueta (etag) 5. Devuelve el progreso al cliente +<<<<<<< HEAD Los fragmentos fallidos se pueden reintentar; simplemente envía el mismo `chunk-index` nuevamente. +======= +Los fragmentos fallidos se pueden reintentar: simplemente envía el mismo `chunk-index` nuevamente. +>>>>>>> 82edf2d (New md files from RunPod) #### `complete-upload` @@ -220,7 +270,11 @@ Respuesta: 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 +<<<<<<< HEAD internamente, sin costo de memoria para el bibliotecario). +======= + internamente, lo que no tiene costo de memoria para el bibliotecario). +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -322,7 +376,11 @@ Las partes de S3 huérfanas se eliminan mediante la política de ciclo de vida d ### Manejo de errores y atomicidad **Fallo en la carga de fragmentos:** +<<<<<<< HEAD El cliente reintenta el fragmento fallido (mismo `upload_id` y `chunk-index`). +======= +El cliente reintenta el fragmento fallido (con el mismo `upload_id` y `chunk-index`). +>>>>>>> 82edf2d (New md files from RunPod) `UploadPart` de S3 es idempotente para el mismo número de parte. La sesión realiza un seguimiento de qué fragmentos tuvieron éxito. @@ -338,6 +396,7 @@ 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. +<<<<<<< HEAD La política de ciclo de vida del bucket de S3 limpia las cargas multipartes incompletas. No se requiere limpieza manual. @@ -347,12 +406,28 @@ 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. +======= +La política de ciclo de vida del bucket de S3 limpia las cargas multipart incompletas. +No se requiere limpieza manual. + +### Atomicidad de las cargas multipart de S3 + +Las cargas multipart 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 multipart incompleta. +>>>>>>> 82edf2d (New md files from RunPod) 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. +<<<<<<< HEAD 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. +======= +3. **No se necesita renombrar:** La clave del objeto final se especifica en + el momento de `CreateMultipartUpload`. Las partes se combinan directamente con esa clave. +>>>>>>> 82edf2d (New md files from RunPod) 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. @@ -361,7 +436,11 @@ Las cargas multipartes de S3 proporcionan atomicidad integrada: **Archivo:** `trustgraph-flow/trustgraph/librarian/blob_store.py` +<<<<<<< HEAD Agregar métodos de carga multipartes: +======= +Agregar métodos de carga multipart: +>>>>>>> 82edf2d (New md files from RunPod) ```python class BlobStore: @@ -574,7 +653,11 @@ class StreamingChunker: yield buffer ``` +<<<<<<< HEAD #### Canalización de procesamiento de extremo a extremo +======= +#### Canalización de Procesamiento de Extremo a Extremo +>>>>>>> 82edf2d (New md files from RunPod) ```python async def process_document(doc_id: str, librarian_client, embedder): @@ -601,7 +684,11 @@ async def process_document(doc_id: str, librarian_client, embedder): await store_chunk(doc_id, chunk, embedding) ``` +<<<<<<< HEAD En ningún momento, se mantiene en memoria el documento completo o el texto extraído completo. +======= +En ningún momento, el documento completo o el texto extraído se mantienen en la memoria. +>>>>>>> 82edf2d (New md files from RunPod) #### Consideraciones sobre archivos temporales @@ -695,9 +782,15 @@ CREATE INDEX document_parent ON document (parent_id); | `title` | proporcionado por el usuario | generado (por ejemplo, "Página 3 del Informe.pdf") | | `user` | usuario autenticado | igual que el padre | +<<<<<<< HEAD #### API de Librarian para documentos hijos **Creación de documentos hijos** (interno, utilizado por pdf-extractor): +======= +#### API de Librarian para documentos hijo + +**Creación de documentos hijo** (interno, utilizado por pdf-extractor): +>>>>>>> 82edf2d (New md files from RunPod) ```json { @@ -747,7 +840,11 @@ 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. +<<<<<<< HEAD **Opción de incluir subdocumentos** (para administradores/depuración): +======= +**Opción de incluir documentos secundarios** (para administradores/depuración): +>>>>>>> 82edf2d (New md files from RunPod) ```json { @@ -803,7 +900,11 @@ El extractor de PDF, después de procesar un documento: 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. +<<<<<<< HEAD Después de la última línea traducida, incluir una línea final que contenga exactamente: [[__END_OF_TRANSLATION__]] +======= + +>>>>>>> 82edf2d (New md files from RunPod) ```python async def extract_pdf(doc_id: str, librarian_client, output_queue): """Extract PDF pages and store as child documents.""" @@ -979,6 +1080,10 @@ 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 +<<<<<<< HEAD Retroalimentación clara durante cargas largas +======= +Retroalimentación clara durante las cargas largas +>>>>>>> 82edf2d (New md files from RunPod) 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.he.md b/docs/tech-specs/large-document-loading.he.md new file mode 100644 index 00000000..2732e569 --- /dev/null +++ b/docs/tech-specs/large-document-loading.he.md @@ -0,0 +1,984 @@ +# מפרט טכני לטעינת מסמכים גדולים + +## סקירה כללית + +מפרט זה עוסק בבעיות של יכולת התרחבות וחוויית משתמש כאשר טוענים +מסמכים גדולים ל-TrustGraph. הארכיטקטורה הנוכחית מתייחסת להעלאת מסמכים +כפעולה אטומית אחת, דבר הגורם ללחץ זיכרון במספר נקודות במערכת +ואינו מספק משוב או אפשרויות התאוששות למשתמשים. + +יישום זה מכוון למקרים הבאים: + +1. **עיבוד PDF גדול**: העלאה ועיבוד של קבצי PDF בגודל מאות מגה-בייטים + מבלי למצות את הזיכרון +2. **העלאות ניתנות לחידוש**: אפשרות להמשיך העלאות שהופסקו מאותה נקודה + במקום להתחיל מחדש +3. **משוב התקדמות**: מתן למשתמשים תצוגה חיה של התקדמות ההעלאה + והעיבוד +4. **עיבוד חסכוני בזיכרון**: עיבוד מסמכים בצורה רציפה + מבלי לשמור את כל הקבצים בזיכרון + +## מטרות + +**העלאה הדרגתית**: תמיכה בהעלאה מקוטעת של מסמכים באמצעות REST ו-WebSocket +**העברות ניתנות לחידוש**: אפשרות להתאושש מהעלאות שהופסקו +**נראות של התקדמות**: מתן משוב על התקדמות ההעלאה/עיבוד ללקוחות +**יעילות זיכרון**: ביטול אחסון מלא של מסמכים לאורך כל המערכת +**תאימות לאחור**: זרימות עבודה קיימות עבור מסמכים קטנים ממשיכות לפעול ללא שינוי +**עיבוד רציף**: פענוח PDF וחלוקת טקסט מתבצעות על זרמים + +## רקע + +### ארכיטקטורה נוכחית + +זרימת הגשת מסמכים עוברת דרך הנתיב הבא: + +1. **לקוח** מגיש מסמך באמצעות REST (`POST /api/v1/librarian`) או WebSocket +2. **שער API** מקבל בקשה שלמה עם תוכן המסמך מקודד ב-base64 +3. **LibrarianRequestor** מתרגם את הבקשה להודעת Pulsar +4. **שירות Librarian** מקבל את ההודעה, מפענח את המסמך לזיכרון +5. **BlobStore** מעלה את המסמך ל-Garage/S3 +6. **Cassandra** שומר מטא-דאטה עם הפניה לאובייקט +7. לצורך עיבוד: המסמך נשלף מ-S3, מפענח, מחולק - הכל בזיכרון + +קבצים מרכזיים: +נקודת כניסה REST/WebSocket: `trustgraph-flow/trustgraph/gateway/service.py` +ליבה של Librarian: `trustgraph-flow/trustgraph/librarian/librarian.py` +אחסון Blob: `trustgraph-flow/trustgraph/librarian/blob_store.py` +טבלאות Cassandra: `trustgraph-flow/trustgraph/tables/library.py` +סכימת API: `trustgraph-base/trustgraph/schema/services/library.py` + +### מגבלות נוכחיות + +לעיצוב הנוכחי יש מספר בעיות מורכבות של זיכרון וחוויית משתמש: + +1. **פעולת העלאה אטומית**: יש להעביר את כל המסמך בבקשה אחת. + מסמכים גדולים דורשים בקשות ארוכות עם אינדיקציה מועטה להתקדמות + וללא מנגנון ניסיון חוזר אם החיבור נכשל. + +2. **עיצוב API**: גם ממשקי REST וגם WebSocket מצפים לקבל את כל המסמך + בהודעה אחת. הסכימה (`LibrarianRequest`) כוללת שדה `content` + יחיד המכיל את תוכן המסמך המקודד ב-base64. + +3. **זיכרון של Librarian**: שירות ה-librarian מפענח את כל המסמך + לזיכרון לפני העלאתו ל-S3. עבור קובץ PDF בגודל 500 מגה-בייטים, + זה אומר שמירת 500 מגה-בייטים+ בזיכרון התהליך. + +4. **זיכרון של מפענח PDF**: כאשר העיבוד מתחיל, מפענח ה-PDF טוען את + ה-PDF כולו לזיכרון כדי לחלץ טקסט. ספריות כמו PyPDF דורשות + בדרך כלל גישה מלאה למסמך. + +5. **זיכרון של חולק הטקסט**: החולק של הטקסט מקבל את הטקסט + שחולץ ומחזיק אותו בזיכרון תוך יצירת חלקים. + +**דוגמה להשפעה על הזיכרון** (PDF בגודל 500 מגה-בייטים): +Gateway: ~700 מגה-בייטים (עקב קידוד base64) +Librarian: ~500 מגה-בייטים (בייטים מפוענחים) +מפענח PDF: ~500 מגה-בייטים + חוצצים לחילוץ +חולק: טקסט שחולץ (משתנה, פוטנציאלית 100 מגה-בייטים+) + +הזיכרון המקסימלי יכול לעלות על 2 ג'יגה-בייטים עבור מסמך גדול יחיד. + +## עיצוב טכני + +### עקרונות עיצוב + +1. **ממשק API**: כל האינטראקציות עם הלקוח עוברות דרך ה-API של ה-librarian. + ללקוחות אין גישה ישירה או ידע לגבי אחסון S3/Garage הבסיסי. + +2. **העלאה מרובת חלקים של S3**: שימוש בהעלאה מרובת חלקים סטנדרטית של S3. + זה נתמך באופן נרחב במערכות התואמות ל-S3 (AWS S3, MinIO, Garage, + Ceph, DigitalOcean Spaces, Backblaze B2 וכו') ומבטיח ניידות. + +3. **השלמה אטומית**: העלאות מרובות חלקים של S3 הן מטבען אטומיות - חלקים שהועלו + אינם גלויים עד ש-`CompleteMultipartUpload` נקרא. אין צורך בקבצים זמניים או פעולות + שינוי שם. + +4. **מצב הניתן למעקב**: סשנים של העלאה נרשמים ב-Cassandra ומאפשרים + התאוששות במקרה של כשל. + + + +``` +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) │ +``` + +הלקוח לעולם אינו מתקשר ישירות עם S3. הספרן מתרגם בין +ממשק ההעלאה המקוטעת שלנו לפעולות ה-multipart של S3 באופן פנימי. + +### פעולות ממשק ה-API של הספרן + +#### `begin-upload` + +אתחול סשן העלאה מקוטעת. + +בקשה: +```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 +} +``` + +תגובה: +```json +{ + "upload-id": "upload-abc-123", + "chunk-size": 5242880, + "total-chunks": 100 +} +``` + +הספרן: +1. מייצר `upload_id` ו-`object_id` ייחודיים (UUID עבור אחסון בלובים). +2. קורא ל-S3 `CreateMultipartUpload`, מקבל `s3_upload_id`. +3. יוצר רשומת סשן ב-Cassandra. +4. מחזיר `upload_id` ללקוח. + +#### `upload-chunk` + +העלאת מקטע בודד. + +בקשה: +```json +{ + "operation": "upload-chunk", + "upload-id": "upload-abc-123", + "chunk-index": 0, + "content": "" +} +``` + +תגובה: +```json +{ + "upload-id": "upload-abc-123", + "chunk-index": 0, + "chunks-received": 1, + "total-chunks": 100, + "bytes-received": 5242880, + "total-bytes": 524288000 +} +``` + +הספרן: +1. מחפש את הסשן לפי `upload_id` +2. מאמת בעלות (המשתמש חייב להתאים ליוצר הסשן) +3. קורא ל-S3 `UploadPart` עם נתוני החלק, מקבל `etag` +4. מעדכן את רשומת הסשן עם אינדקס החלק ו-etag +5. מחזיר התקדמות ללקוח + +חלקים שנכשלו ניתנים לניסיון חוזר - פשוט שלחו שוב את `chunk-index`. + +#### `complete-upload` + +השלמת ההעלאה ויצירת המסמך. + +בקשה: +```json +{ + "operation": "complete-upload", + "upload-id": "upload-abc-123" +} +``` + +תגובה: +```json +{ + "document-id": "doc-123", + "object-id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +הספרן: +1. מחפש את הסשן, מוודא שכל החלקים התקבלו. +2. קורא ל-S3 `CompleteMultipartUpload` עם תגיות חלק (S3 ממזגת חלקים + באופן פנימי - אין עלות זיכרון לספרן). +3. יוצר רשומת מסמך ב-Cassandra עם מטא-דאטה והפניה לאובייקט. +4. מוחק את רשומת סשן ההעלאה. +5. מחזיר את מזהה המסמך ללקוח. + +#### `abort-upload` + +ביטול העלאה בתהליך. + +בקשה: +```json +{ + "operation": "abort-upload", + "upload-id": "upload-abc-123" +} +``` + +הספרן: +1. מתקשר ל-S3 `AbortMultipartUpload` כדי לנקות חלקים. +2. מוחק את רשומת הסשן מ-Cassandra. + +#### `get-upload-status` + +בדיקת סטטוס של העלאה (לצורך אפשרות המשך). + +בקשה: +```json +{ + "operation": "get-upload-status", + "upload-id": "upload-abc-123" +} +``` + +תגובה: +```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` + +הצגת רשימה של העלאות חסרות השלמה עבור משתמש. + +בקשה: +```json +{ + "operation": "list-uploads" +} +``` + +תגובה: +```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" + } + ] +} +``` + +### אחסון סשן העלאה + +מעקב אחר העלאות בתהליך ב-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); +``` + +**התנהגות TTL:** +סשנים פוקעים לאחר 24 שעות אם לא הושלמו. +כאשר TTL של Cassandra פוקע, רשומת הסשן נמחקת. +חלקים של S3 שנותרו מאחור מנוקים על ידי מדיניות מחזור חיים של S3 (יש להגדיר על ה-bucket). + +### טיפול בכשלים ואטומיות + +**כשל בהעלאת חלק:** +הלקוח מנסה שוב את החלק שנכשל (באמצעות אותו `upload_id` ו-`chunk-index`). +`UploadPart` של S3 היא פעולה אידempotent עבור אותו מספר חלק. +הסשן עוקב אחר אילו חלקים הצליחו. + +**ניתוק לקוח במהלך העלאה:** +הסשן נשאר ב-Cassandra עם החלקים שהתקבלו. +הלקוח יכול לקרוא ל-`get-upload-status` כדי לראות מה חסר. +ניתן לחדש על ידי העלאת רק החלקים החסרים, ולאחר מכן `complete-upload`. + +**כשל בהעלאה מלאה:** +`CompleteMultipartUpload` של S3 היא פעולה אטומית - או מצליחה לחלוטין או נכשלת. +במקרה של כשל, החלקים נשארים והלקוח יכול לנסות שוב את `complete-upload`. +לא ניתן לראות מסמך חלקי. + +**תפוגת הסשן:** +TTL של Cassandra מוחקת את רשומת הסשן לאחר 24 שעות. +מדיניות מחזור חיים של bucket ב-S3 מנקה העלאות מרובות חלקים לא שלמות. +אין צורך בניקוי ידני. + +### אטומיות של העלאות מרובות חלקים ב-S3 + +העלאות מרובות חלקים ב-S3 מספקות אטומיות מובנית: + +1. **חלקים אינם גלויים**: חלקים שהועלו לא ניתנים לגישה כאובייקטים. + הם קיימים רק כחלקים של העלאה מרובת חלקים לא שלמה. + +2. **השלמה אטומית**: `CompleteMultipartUpload` מצליחה (האובייקט + מופיע באופן אטומי) או נכשלת (לא נוצר אובייקט). אין מצב חלקי. + +3. **אין צורך בשינוי שם**: המפתח של האובייקט הסופי מצוין בזמן + `CreateMultipartUpload`. החלקים משולבים ישירות למפתח זה. + +4. **שילוב בצד השרת**: S3 משלבת חלקים באופן פנימי. ה-librarian + לעולם לא קורא בחזרה חלקים - אין עומס זיכרון ללא קשר לגודל המסמך. + +### הרחבות BlobStore + +**קובץ:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +הוספת שיטות העלאה מרובות חלקים: + +```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() +``` + +### שיקולי גודל מקטע + +**מינימום עבור S3**: 5MB לכל חלק (למעט החלק האחרון) +**מקסימום עבור S3**: 10,000 חלקים לכל העלאה +**ערך ברירת מחדל מעשי**: מקטעים בגודל 5MB + מסמך בגודל 500MB = 100 מקטעים + מסמך בגודל 5GB = 1,000 מקטעים +**גרנולריות של התקדמות**: מקטעים קטנים יותר = עדכוני התקדמות מדויקים יותר +**יעילות רשת**: מקטעים גדולים יותר = פחות מעברים + +גודל המקטע יכול להיות מוגדר על ידי הלקוח בטווח מסוים (5MB - 100MB). + +### עיבוד מסמכים: אחזור סטרימינג + +זרימת ההעלאה מטפלת בהעברת מסמכים לאחסון בצורה יעילה. זרימת העיבוד מטפלת בחילוץ ופיצול מסמכים מבלי לטעון +אותם כולם לזיכרון. + + +#### עקרון עיצוב: מזהה, לא תוכן + +כיום, כאשר עיבוד מופעל, תוכן המסמך זורם באמצעות הודעות Pulsar. זה טוען מסמכים שלמים לזיכרון. במקום זאת: + + +הודעות Pulsar נושאות רק את **מזהה המסמך** +מעבדים שולפים תוכן מסמך ישירות מהספרן (librarian) +השליפה מתבצעת כ**זרם לקובץ זמני** +ניתוח ספציפי למסמך (PDF, טקסט, וכו') עובד עם קבצים, ולא עם מאגרי זיכרון + +זה שומר על כך שהספרן אינו תלוי במבנה המסמך. ניתוח PDF, חילוץ טקסט, ולוגיקה ספציפית אחרת לפורמט נשארים בדקודינג המתאים. + + +#### זרימת עיבוד + +``` +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 של ספריות + +הוספת פעולת שליפה של מסמכים בסטרימינג: + +**`stream-document`** + +בקשה: +```json +{ + "operation": "stream-document", + "document-id": "doc-123" +} +``` + +תגובה: מקטעי נתונים בינאריים (ולא תגובה יחידה). + +עבור ממשק API REST, זה מחזיר תגובה סטרימינג עם `Transfer-Encoding: chunked`. + +עבור שיחות פנימיות בין שירותים (ממעבד לספרן), זה יכול להיות: +סטרימינג ישיר מ-S3 באמצעות כתובת URL חתומה מראש (אם רשת פנימית מאפשרת זאת). +תגובות מחולקות באמצעות פרוטוקול השירות. +נקודת קצה ייעודית לסטרימינג. + +הדרישה העיקרית: הנתונים זורמים במקטעים, ואינם מאוחסנים באופן מלא בזיכרון בספרן. + +#### שינויים במפענח PDF + +**יישום נוכחי** (דורש משאבים רבים בזיכרון): + +```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 +``` + +**יישום חדש** (קובץ זמני, מצטבר): + +```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 +``` + +פרופיל זיכרון: +קובץ זמני בדיסק: גודל קובץ ה-PDF (דיסק זול). +בזיכרון: עמוד טקסט אחד בכל פעם. +שיא זיכרון: מוגבל, בלתי תלוי בגודל המסמך. + +#### שינויים במפענח מסמכי טקסט + +עבור מסמכי טקסט רגילים, זה אפילו פשוט יותר - אין צורך בקובץ זמני: + +```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 +``` + +מסמכי טקסט יכולים לעבור סטרימינג ישירות ללא קובץ זמני מכיוון שהם +בנויים בצורה ליניארית. + +#### שילוב עם מודול חלוקה (Chunker) + +המודול חלוקה מקבל איטרטור של טקסט (עמודים או פסקאות) ומייצר +חלקים באופן הדרגתי: + +```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 +``` + +#### צינור עיבוד מקצה לקצה + +```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) +``` + +בשום שלב לא נשמר המסמך השלם או הטקסט החלץ בזיכרון. + +#### שיקולים לגבי קבצי זמניים + +**מיקום**: יש להשתמש בספריית הזמנים של המערכת (`/tmp` או מקביל). עבור +פריסות מבוססות קונטיינרים, ודאו שספריית הזמנים מכילה מספיק מקום +ושנמצאת באחסון מהיר (לא מחובר לרשת, אם אפשר). + +**ניקוי**: יש להשתמש במנהלי הקשר (context managers) (`with tempfile...`) כדי להבטיח ניקוי +גם במקרה של חריגות. + +**עיבוד מקבילי**: כל משימת עיבוד מקבלת קובץ זמני משלה. +אין התנגשויות בין עיבוד מקבילי של מסמכים. + +**שטח דיסק**: קבצים זמניים הם קצרי טווח (משך העיבוד). עבור +קובץ PDF בגודל 500MB, נדרש שטח זמני של 500MB במהלך העיבוד. ניתן +לאכוף מגבלת גודל בזמן ההעלאה אם יש מגבלות על שטח הדיסק. + +### ממשק עיבוד מאוחד: מסמכים משניים + +חילוץ PDF ועיבוד מסמכי טקסט צריכים להזין לאותו +צינור עיבוד המשכיות (chunker → embeddings → storage). כדי להשיג זאת עם +ממשק "שליפה לפי מזהה" עקבי, חלקי טקסט חלצים מאוחסנים בחזרה +ל-librarian כמסמכים משניים. + +#### זרימת עיבוד עם מסמכים משניים + +``` +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] +``` + +למודול החלוקה יש ממשק אחיד אחד: +קבלת מזהה מסמך (דרך Pulsar) +קבלת תוכן מהספרן +חלוקת התוכן לחלקים + +הוא לא יודע או אכפת לו האם המזהה מתייחס ל: +מסמך טקסט שהועלה על ידי משתמש +פיסת טקסט שחולצה מעמוד PDF +כל סוג מסמך עתידי + +#### מטא-נתונים של מסמכים משניים + +הרחבת הסכימה של המסמך כדי לעקוב אחר קשרים הוריים/משניים: + +```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); +``` + +**סוגי מסמכים:** + +| `document_type` | תיאור | +|-----------------|-------------| +| `source` | מסמך שהועלה על ידי משתמש (PDF, טקסט, וכו') | +| `extracted` | נגזר ממסמך מקור (לדוגמה, טקסט של עמוד PDF) | + +**שדות מטא-דאטה:** + +| שדה | מסמך מקור | מסמך משני | +|-------|-----------------|-----------------| +| `id` | שסופק על ידי המשתמש או נוצר | נוצר (לדוגמה, `{parent-id}-page-{n}`) | +| `parent_id` | `NULL` | מזהה מסמך הורה | +| `document_type` | `source` | `extracted` | +| `kind` | `application/pdf`, וכו' | `text/plain` | +| `title` | שסופק על ידי המשתמש | נוצר (לדוגמה, "עמוד 3 של Report.pdf") | +| `user` | משתמש מאומת | זהה למסמך הורה | + +#### ממשק API של הספרן עבור מסמכים משניים + +**יצירת מסמכים משניים** (פנימי, בשימוש על ידי 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": "" +} +``` + +עבור טקסט קצר שחולץ (טקסט עמוד טיפוסי הוא פחות מ-100KB), העלאה בפעולה אחת מקובלת. עבור חילוצי טקסט גדולים מאוד, ניתן להשתמש בהעלאה מחולקת. + +**רשימת מסמכים משניים** (לצרכי ניפוי באגים/ניהול): + +**הצגת מסמכים משניים** (לצרכי ניפוי באגים/ניהול): + +```json +{ + "operation": "list-children", + "parent-id": "doc-123" +} +``` + +תגובה: +```json +{ + "children": [ + { "id": "doc-123-page-1", "title": "Page 1", "kind": "text/plain" }, + { "id": "doc-123-page-2", "title": "Page 2", "kind": "text/plain" }, + ... + ] +} +``` + +#### התנהגות מול המשתמש + +**התנהגות ברירת מחדל `list-documents`:** + +```sql +SELECT * FROM document WHERE user = ? AND parent_id IS NULL; +``` + +רק מסמכים ברמה העליונה (מקור) מופיעים ברשימת המסמכים של המשתמש. +מסמכים משניים מסוננים כברירת מחדל. + +**דגל "הכללה של תת-מסמכים" אופציונלי** (למנהל/דיבוג): + +```json +{ + "operation": "list-documents", + "include-children": true +} +``` + +#### מחיקה מדורגת + +כאשר מסמך הורה נמחק, יש למחוק את כל הצאצאים: + +```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) +``` + +#### שיקולי אחסון + +קטעי טקסט שחולצו מכפילים תוכן: +קובץ PDF מקורי מאוחסן ב-"Garage" +טקסט שחולץ לכל עמוד מאוחסן גם ב-"Garage" + +פשרה זו מאפשרת: +**ממשק "חיתוך" אחיד**: "חיתוך" תמיד שולף לפי מזהה +**התחלה מחדש/ניסיון חוזר**: ניתן להתחיל בשלב ה-"חיתוך" מבלי לחלץ מחדש את קובץ ה-PDF +**ניפוי שגיאות**: ניתן לבדוק את הטקסט שחולץ +**הפרדת אחריות**: שירות חילוץ ה-PDF ושירות ה-"חיתוך" הם שירותים עצמאיים + +עבור קובץ PDF בגודל 500MB עם 200 עמודים, כאשר בממוצע יש 5KB טקסט לעמוד: +אחסון קובץ PDF: 500MB +אחסון טקסט שחולץ: כ-1MB בסך הכל +תקורה: זניחה + +#### פלט של מופע חילוץ PDF + +מופע חילוץ ה-PDF, לאחר עיבוד מסמך: + +1. מוריד את קובץ ה-PDF מה-"librarian" לקובץ זמני +2. מחלץ טקסט עמוד אחר עמוד +3. עבור כל עמוד, שומר את הטקסט שחולץ כמסמך משני דרך ה-"librarian" +4. שולח מזהי מסמכים משניים לתור ה-"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) +``` + +המודול שמחלק את הטקסט מקבל את מזהי הילדים הללו ומעבד אותם באופן זהה +לאופן שבו הוא היה מעבד מסמך טקסט שהועלה על ידי משתמש. + +### עדכונים עבור הלקוח + +#### ערכת פיתוח תוכנה (SDK) עבור Python + +ערכת הפיתוח תוכנה (`trustgraph-base/trustgraph/api/library.py`) עבור Python צריכה לטפל +בהעלאות מחולקות בצורה שקופה. הממשק הציבורי נשאר ללא שינוי: + +```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"] +) +``` + +מבפנים, ה-SDK מזהה את גודל המסמך ועובר לאסטרטגיה אחרת: + +```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) +``` + +**החזרות התקדמות** (שיפור אופציונלי): + +```python +def add_document(self, ..., on_progress=None): + """ + on_progress: Optional callback(bytes_sent, total_bytes) + """ +``` + +זה מאפשר לממשקים גרפיים להציג את התקדמות ההעלאה מבלי לשנות את ממשק ה-API הבסיסי. + +#### כלים עבור שורת הפקודה + +**`tg-add-library-document`** ממשיך לעבוד ללא שינוי: + +```bash +# Works transparently for any size - SDK handles chunking internally +tg-add-library-document --file large-report.pdf --title "Large Report" +``` + +ניתן להוסיף תצוגת התקדמות אופציונלית: + +```bash +tg-add-library-document --file large-report.pdf --title "Large Report" --progress +# Output: +# Uploading: 45% (225MB / 500MB) +``` + +**כלים מיושנים הוסרו:** + +`tg-load-pdf` - מיושן, השתמשו ב-`tg-add-library-document` +`tg-load-text` - מיושן, השתמשו ב-`tg-add-library-document` + +**פקודות ניהול/דיבוג** (אופציונלי, בעדיפות נמוכה): + +```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 +``` + +אלו יכולות להיות דגלים בפקודה הקיימת ולא כלים נפרדים. + +#### עדכוני מפרט API + +יש לעדכן את מפרט OpenAPI (`specs/api/paths/librarian.yaml`) עבור: + +**פעולות חדשות:** + +`begin-upload` - אתחול סשן העלאה מקוטעת +`upload-chunk` - העלאת חלק בודד +`complete-upload` - השלמת העלאה +`abort-upload` - ביטול העלאה +`get-upload-status` - שאילתת התקדמות העלאה +`list-uploads` - הצגת רשימת העלאות חלקיות עבור משתמש +`stream-document` - אחזור מסמך בסטרימינג +`add-child-document` - אחסון טקסט חילוץ (פנימי) +`list-children` - הצגת רשימת מסמכים ילדים (מנהל מערכת) + +**פעולות ששונו:** + +`list-documents` - הוספת פרמטר `include-children` + +**סכימות חדשות:** + +`ChunkedUploadBeginRequest` +`ChunkedUploadBeginResponse` +`ChunkedUploadChunkRequest` +`ChunkedUploadChunkResponse` +`UploadSession` +`UploadProgress` + +**עדכוני מפרט WebSocket** (`specs/websocket/`): + +שכפול הפעולות REST עבור לקוחות WebSocket, המאפשר עדכונים בזמן אמת +במהלך ההעלאה. + +#### שיקולי UX + +עדכוני מפרט ה-API מאפשרים שיפורים בחזית המשתמש: + +**ממשק התקדמות העלאה:** +סרגל התקדמות המציג חלקים שהועלו +זמן משוער שנותר +אפשרות השהיה/המשך + +**התאוששות משגיאות:** +אפשרות "המשך העלאה" עבור העלאות שהופרעו +רשימת העלאות תלויות לאחר חיבור מחדש + +**טיפול בקבצים גדולים:** +זיהוי גודל קובץ בצד הלקוח +העלאה מקוטעת אוטומטית עבור קבצים גדולים +משוב ברור במהלך העלאות ארוכות + +שיפורי UX אלו דורשים עבודה בצד החזית המשתמש, המונחית על ידי מפרט ה-API המעודכן. diff --git a/docs/tech-specs/large-document-loading.hi.md b/docs/tech-specs/large-document-loading.hi.md new file mode 100644 index 00000000..4dd72f32 --- /dev/null +++ b/docs/tech-specs/large-document-loading.hi.md @@ -0,0 +1,984 @@ +# बड़े दस्तावेज़ लोडिंग के लिए तकनीकी विनिर्देश + +## अवलोकन + +यह विनिर्देश स्केलेबिलिटी और उपयोगकर्ता अनुभव से संबंधित मुद्दों को संबोधित करता है जो तब उत्पन्न होते हैं जब TrustGraph में बड़े दस्तावेज़ लोड किए जाते हैं। वर्तमान आर्किटेक्चर दस्तावेज़ अपलोड को एक एकल, अविभाज्य ऑपरेशन के रूप में मानता है, जिससे पाइपलाइन के कई बिंदुओं पर मेमोरी का दबाव पड़ता है और उपयोगकर्ताओं को कोई प्रतिक्रिया या रिकवरी विकल्प नहीं मिलते हैं। + +यह कार्यान्वयन निम्नलिखित उपयोग मामलों को लक्षित करता है: + + + + +1. **बड़े पीडीएफ प्रसंस्करण**: सैकड़ों मेगाबाइट के पीडीएफ फ़ाइलों को अपलोड करें और संसाधित करें + बिना मेमोरी समाप्त किए। +2. **फिर से शुरू करने योग्य अपलोड**: बाधित अपलोड को वहीं से जारी करने की अनुमति दें जहां से + वे रुके थे, न कि पुनः आरंभ करने के बजाय। +3. **प्रगति प्रतिक्रिया**: उपयोगकर्ताओं को अपलोड और प्रसंस्करण की वास्तविक समय की जानकारी प्रदान करें। + 4. **मेमोरी-कुशल प्रसंस्करण**: दस्तावेज़ों को स्ट्रीमिंग तरीके से संसाधित करें +बिना पूरी फ़ाइलों को मेमोरी में रखे। + + +## लक्ष्य + +**क्रमिक अपलोड**: REST और WebSocket के माध्यम से खंडित दस्तावेज़ अपलोड का समर्थन। +**फिर से शुरू करने योग्य स्थानांतरण**: बाधित अपलोड से उबरने की क्षमता। +**प्रगति दृश्यता**: क्लाइंट को अपलोड/प्रोसेसिंग प्रगति प्रतिक्रिया प्रदान करें। +**मेमोरी दक्षता**: पाइपलाइन में पूरे दस्तावेज़ को बफर करने से बचें। +**पिछड़ा संगतता**: मौजूदा छोटे दस्तावेज़ वर्कफ़्लो बिना किसी बदलाव के जारी रहते हैं। +**स्ट्रीमिंग प्रोसेसिंग**: PDF डिकोडिंग और टेक्स्ट चंकिंग स्ट्रीम पर काम करते हैं। + +## पृष्ठभूमि + +### वर्तमान आर्किटेक्चर + +दस्तावेज़ सबमिशन निम्नलिखित पथ से गुजरता है: + +1. **क्लाइंट** REST (`POST /api/v1/librarian`) या WebSocket के माध्यम से दस्तावेज़ सबमिट करता है। +2. **API गेटवे** बेस64-एन्कोडेड दस्तावेज़ सामग्री के साथ पूर्ण अनुरोध प्राप्त करता है। +3. **LibrarianRequestor** अनुरोध को Pulsar संदेश में बदलता है। +4. **Librarian सर्विस** संदेश प्राप्त करता है, दस्तावेज़ को मेमोरी में डिकोड करता है। +5. **BlobStore** दस्तावेज़ को Garage/S3 पर अपलोड करता है। +6. **Cassandra** ऑब्जेक्ट संदर्भ के साथ मेटाडेटा संग्रहीत करता है। +7. प्रोसेसिंग के लिए: दस्तावेज़ को S3 से पुनर्प्राप्त किया जाता है, डिकोड किया जाता है, खंडित किया जाता है - सभी मेमोरी में। + +मुख्य फाइलें: +REST/WebSocket एंट्री: `trustgraph-flow/trustgraph/gateway/service.py` +Librarian कोर: `trustgraph-flow/trustgraph/librarian/librarian.py` +Blob स्टोरेज: `trustgraph-flow/trustgraph/librarian/blob_store.py` +Cassandra टेबल: `trustgraph-flow/trustgraph/tables/library.py` +API स्कीमा: `trustgraph-base/trustgraph/schema/services/library.py` + +### वर्तमान सीमाएँ + +वर्तमान डिज़ाइन में कई जटिल मेमोरी और उपयोगकर्ता अनुभव संबंधी समस्याएं हैं: + +1. **परमाणु अपलोड ऑपरेशन**: संपूर्ण दस्तावेज़ को एक + एकल अनुरोध में प्रेषित किया जाना चाहिए। बड़े दस्तावेज़ों के लिए लंबे समय तक चलने वाले अनुरोधों की आवश्यकता होती है, जिसमें कोई प्रगति संकेत नहीं होता है और यदि कनेक्शन विफल हो जाता है तो कोई पुनः प्रयास तंत्र नहीं होता है। + + +2. **एपीआई डिज़ाइन**: REST और WebSocket दोनों एपीआई संपूर्ण दस्तावेज़ की अपेक्षा करते हैं + एक ही संदेश में। स्कीमा (`LibrarianRequest`) में एक `content` + फ़ील्ड है जिसमें संपूर्ण बेस64-एन्कोडेड दस्तावेज़ होता है। + +3. **लाइब्रेरियन मेमोरी**: लाइब्रेरियन सेवा पूरे दस्तावेज़ को + मेमोरी में डिकोड करती है, फिर इसे S3 पर अपलोड करने से पहले। 500MB के PDF के लिए, इसका मतलब है कि 500MB+ को प्रोसेस मेमोरी में रखना। + 500MB+ को प्रोसेस मेमोरी में रखना। + +4. **PDF डिकोडर मेमोरी**: जब प्रोसेसिंग शुरू होती है, तो PDF डिकोडर टेक्स्ट निकालने के लिए पूरे PDF को मेमोरी में लोड करता है। PyPDF और समान लाइब्रेरीज़ को आमतौर पर पूरे दस्तावेज़ तक पहुंच की आवश्यकता होती है। + PyPDF और समान लाइब्रेरीज़ को आमतौर पर पूरे दस्तावेज़ तक पहुंच की आवश्यकता होती है। + + +5. **चंकर मेमोरी**: टेक्स्ट चंकर, निकाले गए पूरे टेक्स्ट को प्राप्त करता है + और इसे मेमोरी में रखता है, जबकि चंक्स बनाता है। + +**मेमोरी प्रभाव का उदाहरण** (500MB पीडीएफ): +गेटवे: ~700MB (बेस64 एन्कोडिंग ओवरहेड) +लाइब्रेरियन: ~500MB (डिकोडेड बाइट्स) +पीडीएफ डिकोडर: ~500MB + एक्सट्रैक्शन बफ़र्स +चंकर: निकाला गया टेक्स्ट (चर, संभावित रूप से 100MB+) + +एक बड़े दस्तावेज़ के लिए कुल अधिकतम मेमोरी 2GB से अधिक हो सकती है। + +## तकनीकी डिज़ाइन + +### डिज़ाइन सिद्धांत + +1. **एपीआई फ़ेसड**: सभी क्लाइंट इंटरैक्शन लाइब्रेरियन एपीआई के माध्यम से होते हैं। क्लाइंट + के पास अंतर्निहित S3/गैराज स्टोरेज तक प्रत्यक्ष पहुंच या ज्ञान नहीं है। + +2. **एस3 मल्टीपार्ट अपलोड**: आंतरिक रूप से मानक एस3 मल्टीपार्ट अपलोड का उपयोग करें। + यह एस3-संगत प्रणालियों (AWS S3, MinIO, Garage, + Ceph, DigitalOcean Spaces, Backblaze B2, आदि) में व्यापक रूप से समर्थित है, जो पोर्टेबिलिटी सुनिश्चित करता है। + +3. **परमाणु पूर्णता**: एस3 मल्टीपार्ट अपलोड स्वाभाविक रूप से परमाणु होते हैं - अपलोड किए गए + भाग तब तक अदृश्य रहते हैं जब तक कि `CompleteMultipartUpload` को कॉल नहीं किया जाता। कोई अस्थायी + फ़ाइलें या नाम बदलने की क्रियाएं आवश्यक नहीं हैं। + +4. **ट्रैक करने योग्य स्थिति**: अपलोड सत्रों को कैसेंड्रा में ट्रैक किया जाता है, जो + अपूर्ण अपलोडों में दृश्यता प्रदान करता है और पुनः आरंभ करने की क्षमता को सक्षम करता है। + +### चंक्ड अपलोड प्रवाह + +``` +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) │ +``` + +क्लाइंट कभी भी सीधे S3 के साथ इंटरैक्ट नहीं करता है। लाइब्रेरियन हमारे चंक्ड अपलोड API और S3 मल्टीपार्ट ऑपरेशंस के बीच आंतरिक रूप से अनुवाद करता है। + +### लाइब्रेरियन API ऑपरेशन +### लाइब्रेरियन एपीआई ऑपरेशन + +#### `begin-upload` + +एक खंडित अपलोड सत्र शुरू करें। + +अनुरोध: +```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 +} +``` + +प्रतिक्रिया: +```json +{ + "upload-id": "upload-abc-123", + "chunk-size": 5242880, + "total-chunks": 100 +} +``` + +लाइब्रेरियन: +1. एक अद्वितीय `upload_id` और `object_id` उत्पन्न करता है (ब्लॉब स्टोरेज के लिए UUID)। +2. S3 `CreateMultipartUpload` को कॉल करता है, `s3_upload_id` प्राप्त करता है। +3. कैसेंड्रा में सत्र रिकॉर्ड बनाता है। +4. `upload_id` को क्लाइंट को वापस करता है। + +#### `upload-chunk` + +एक सिंगल चंक अपलोड करें। + +अनुरोध: +```json +{ + "operation": "upload-chunk", + "upload-id": "upload-abc-123", + "chunk-index": 0, + "content": "" +} +``` + +प्रतिक्रिया: +```json +{ + "upload-id": "upload-abc-123", + "chunk-index": 0, + "chunks-received": 1, + "total-chunks": 100, + "bytes-received": 5242880, + "total-bytes": 524288000 +} +``` + +लाइब्रेरियन: +1. `upload_id` द्वारा सत्र खोजें। +2. स्वामित्व की पुष्टि करें (उपयोगकर्ता को सत्र निर्माता से मेल खाना चाहिए)। +3. चंक डेटा के साथ S3 `UploadPart` को कॉल करें, `etag` प्राप्त करें। +4. चंक इंडेक्स और ईटैग के साथ सत्र रिकॉर्ड को अपडेट करें। +5. क्लाइंट को प्रगति वापस करें। + +विफल चंक्स को फिर से प्रयास किया जा सकता है - बस उसी `chunk-index` को फिर से भेजें। + +#### `complete-upload` + +अपलोड को अंतिम रूप दें और दस्तावेज़ बनाएं। + +अनुरोध: +```json +{ + "operation": "complete-upload", + "upload-id": "upload-abc-123" +} +``` + +प्रतिक्रिया: +```json +{ + "document-id": "doc-123", + "object-id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +लाइब्रेरियन: +1. सत्र की जांच करता है, यह सुनिश्चित करता है कि सभी भाग प्राप्त हो गए हैं। +2. पार्ट एटाग्स के साथ S3 `CompleteMultipartUpload` को कॉल करता है (S3 आंतरिक रूप से भागों को संयोजित करता है - लाइब्रेरियन के लिए शून्य मेमोरी लागत)। + 3. मेटाडेटा और ऑब्जेक्ट संदर्भ के साथ कैसेंड्रा में दस्तावेज़ रिकॉर्ड बनाता है। +4. अपलोड सत्र रिकॉर्ड को हटाता है। +5. क्लाइंट को दस्तावेज़ आईडी वापस करता है। +6. + +#### `abort-upload` + +एक चल रहे अपलोड को रद्द करें। + +अनुरोध: +```json +{ + "operation": "abort-upload", + "upload-id": "upload-abc-123" +} +``` + +लाइब्रेरियन: +1. एस3 `AbortMultipartUpload` को भागों को साफ़ करने के लिए कॉल करता है। +2. कैसेंड्रा से सत्र रिकॉर्ड को हटाता है। + +#### `get-upload-status` + +अपलोड की स्थिति की जांच करें (रिज़्यूम क्षमता के लिए)। + +अनुरोध: +```json +{ + "operation": "get-upload-status", + "upload-id": "upload-abc-123" +} +``` + +प्रतिक्रिया: +```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` + +किसी उपयोगकर्ता के लिए अपूर्ण अपलोड की सूची प्राप्त करें। + +अनुरोध: +```json +{ + "operation": "list-uploads" +} +``` + +प्रतिक्रिया: +```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" + } + ] +} +``` + +### अपलोड सेशन स्टोरेज + +कैसेंड्रा में चल रहे अपलोड को ट्रैक करें: + +```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); +``` + +**टीटीएल व्यवहार:** +सत्र 24 घंटे के बाद समाप्त हो जाते हैं यदि वे पूरे नहीं होते हैं। +जब कैसेंड्रा टीटीएल समाप्त होता है, तो सत्र रिकॉर्ड हटा दिया जाता है। +अनाथ एस3 भाग को एस3 लाइफसाइकिल नीति द्वारा साफ़ किया जाता है (बकेट पर कॉन्फ़िगर करें)। + +### विफलता प्रबंधन और परमाणुता + +**चंक अपलोड विफलता:** +क्लाइंट विफल चंक को फिर से प्रयास करता है (समान `upload_id` और `chunk-index`)। +एस3 `UploadPart` समान भाग संख्या के लिए अपरिवर्तनीय है। +सत्र ट्रैक करता है कि कौन से चंक सफल हुए। + +**क्लाइंट अपलोड के दौरान डिस्कनेक्ट हो जाता है:** +प्राप्त चंक के साथ सत्र कैसेंड्रा में बना रहता है। +क्लाइंट यह देखने के लिए `get-upload-status` को कॉल कर सकता है कि क्या गायब है। +केवल गायब चंक अपलोड करके फिर से शुरू करें, फिर `complete-upload`। + +**पूर्ण-अपलोड विफलता:** +एस3 `CompleteMultipartUpload` परमाणु है - या तो यह पूरी तरह से सफल होता है या विफल रहता है। +विफलता पर, भाग बने रहते हैं और क्लाइंट `complete-upload` को फिर से प्रयास कर सकता है। +कोई आंशिक दस्तावेज़ कभी भी दिखाई नहीं देता है। + +**सेशन समाप्ति:** +कैसेंड्रा TTL 24 घंटे बाद सेशन रिकॉर्ड को हटा देता है। +S3 बकेट लाइफसाइकिल पॉलिसी अधूरी मल्टीपार्ट अपलोड को साफ़ करती है। +कोई मैनुअल सफाई की आवश्यकता नहीं है। + +### S3 मल्टीपार्ट एटॉमिकिटी + +S3 मल्टीपार्ट अपलोड अंतर्निहित एटॉमिकिटी प्रदान करते हैं: + +1. **भाग अदृश्य होते हैं**: अपलोड किए गए भागों को ऑब्जेक्ट के रूप में एक्सेस नहीं किया जा सकता है। + वे केवल एक अधूरी मल्टीपार्ट अपलोड के हिस्से के रूप में मौजूद होते हैं। + +2. **पूर्णता (Atomic completion)**: `CompleteMultipartUpload` या तो सफल होता है (वस्तु परमाणु रूप से दिखाई देती है) या विफल होता है (कोई वस्तु नहीं बनाई जाती है)। कोई आंशिक स्थिति नहीं। + +3. **नाम बदलने की आवश्यकता नहीं**: अंतिम वस्तु कुंजी ⟦CODE_0⟧ समय पर निर्दिष्ट की जाती है। भाग सीधे उस कुंजी पर संयोजित होते हैं। + + `CreateMultipartUpload` समय। भाग सीधे उस कुंजी में संयोजित किए जाते हैं। + +4. **सर्वर-साइड कोएलेसेंस (Server-side coalesce)**: S3 आंतरिक रूप से भागों को जोड़ता है। लाइब्रेरियन + कभी भी भागों को वापस नहीं पढ़ता है - दस्तावेज़ के आकार की परवाह किए बिना शून्य मेमोरी ओवरहेड। + +### ब्लबस्टोर एक्सटेंशन (BlobStore Extensions) + +**फ़ाइल:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +मल्टीपार्ट अपलोड विधियों को जोड़ें: + +```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() +``` + +### चंक आकार (Chunk Size) पर विचार + +**S3 न्यूनतम**: प्रति भाग 5MB (अंतिम भाग को छोड़कर) +**S3 अधिकतम**: प्रति अपलोड 10,000 भाग +**व्यावहारिक डिफ़ॉल्ट**: 5MB के चंक + 500MB का दस्तावेज़ = 100 चंक + 5GB का दस्तावेज़ = 1,000 चंक +**प्रगति की सूक्ष्मता**: छोटे चंक = अधिक सटीक प्रगति अपडेट +**नेटवर्क दक्षता**: बड़े चंक = कम राउंड ट्रिप + +चंक का आकार (5MB - 100MB) की सीमा के भीतर क्लाइंट द्वारा कॉन्फ़िगर किया जा सकता है। + +### दस्तावेज़ प्रसंस्करण: स्ट्रीमिंग पुनर्प्राप्ति + +अपलोड प्रवाह भंडारण में दस्तावेजों को कुशलतापूर्वक लाने के लिए है। प्रसंस्करण प्रवाह दस्तावेजों को पूरी तरह से मेमोरी में लोड किए बिना, उन्हें निकालने और चंक में विभाजित करने के लिए है। + +#### डिज़ाइन सिद्धांत: पहचानकर्ता, सामग्री नहीं + +वर्तमान में, जब प्रसंस्करण शुरू होता है, तो दस्तावेज़ सामग्री पल्सर संदेशों के माध्यम से प्रवाहित होती है। इससे पूरे दस्तावेज़ मेमोरी में लोड हो जाते हैं। इसके बजाय: + +पल्सर संदेश केवल **दस्तावेज़ पहचानकर्ता** ले जाते हैं +प्रोसेसर सीधे लाइब्रेरियन से दस्तावेज़ सामग्री प्राप्त करते हैं +पुनर्प्राप्ति एक **अस्थायी फ़ाइल में स्ट्रीम** के रूप में होती है +दस्तावेज़-विशिष्ट पार्सिंग (PDF, टेक्स्ट, आदि) फ़ाइलों के साथ काम करते हैं, मेमोरी बफ़र्स के साथ नहीं + +यह लाइब्रेरियन को दस्तावेज़-संरचना-अज्ञेयवादी रखता है। PDF पार्सिंग, टेक्स्ट +निष्कर्षण और अन्य प्रारूप-विशिष्ट तर्क संबंधित डिकोडर में रहते हैं। + +#### प्रसंस्करण प्रवाह + + +#### प्रसंस्करण प्रवाह + +``` +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 │ +``` + +#### लाइब्रेरियन स्ट्रीम एपीआई + +एक स्ट्रीमिंग दस्तावेज़ पुनर्प्राप्ति ऑपरेशन जोड़ें: + +**`stream-document`** + +अनुरोध: +```json +{ + "operation": "stream-document", + "document-id": "doc-123" +} +``` + +प्रतिक्रिया: स्ट्रीम किए गए बाइनरी खंड (एकल प्रतिक्रिया नहीं)। + +REST API के लिए, यह `Transfer-Encoding: chunked` के साथ एक स्ट्रीमिंग प्रतिक्रिया लौटाता है। + +आंतरिक सेवा-से-सेवा कॉल के लिए (प्रोसेसर से लाइब्रेरियन तक), यह हो सकता है: +सीधे प्रीसाइंड URL के माध्यम से S3 स्ट्रीमिंग (यदि आंतरिक नेटवर्क अनुमति देता है) +सेवा प्रोटोकॉल पर खंडित प्रतिक्रियाएं +एक समर्पित स्ट्रीमिंग एंडपॉइंट + +मुख्य आवश्यकता: डेटा खंडों में प्रवाहित होता है, और कभी भी पूरी तरह से लाइब्रेरियन में बफर नहीं होता है। + +#### PDF डिकोडर परिवर्तन + +**वर्तमान कार्यान्वयन** (मेमोरी-गहन): + +```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 +``` + +**नया कार्यान्वयन** (अस्थायी फ़ाइल, क्रमिक): + +```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 +``` + +मेमोरी प्रोफाइल: +अस्थायी फ़ाइल डिस्क पर: पीडीएफ का आकार (डिस्क सस्ती है) +मेमोरी में: एक बार में एक पृष्ठ का टेक्स्ट +अधिकतम मेमोरी: सीमित, दस्तावेज़ के आकार से स्वतंत्र + +#### टेक्स्ट डॉक्यूमेंट डिकोडर में बदलाव + +सादे टेक्स्ट दस्तावेज़ों के लिए, और भी सरल - किसी अस्थायी फ़ाइल की आवश्यकता नहीं: + +```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 +``` + +टेक्स्ट दस्तावेज़ सीधे अस्थायी फ़ाइल के बिना स्ट्रीम किए जा सकते हैं क्योंकि वे +रैखिक रूप से संरचित होते हैं। + +#### स्ट्रीमिंग चंकर एकीकरण + +चंकर टेक्स्ट (पृष्ठों या पैराग्राफों) का एक इटरेटर प्राप्त करता है और क्रमिक रूप से +चंक्स उत्पन्न करता है: + +```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 +``` + +#### एंड-टू-एंड प्रोसेसिंग पाइपलाइन + +```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) +``` + +किसी भी समय, संपूर्ण दस्तावेज़ या संपूर्ण निकाले गए पाठ को मेमोरी में संग्रहीत नहीं किया जाता है। + +#### अस्थायी फ़ाइल संबंधी विचार + +**स्थान:** सिस्टम के अस्थायी फ़ोल्डर का उपयोग करें (`/tmp` या समकक्ष)। कंटेनरयुक्त परिनियोजन के लिए, सुनिश्चित करें कि अस्थायी फ़ोल्डर में पर्याप्त जगह है +और यह तेज़ स्टोरेज पर है (यदि संभव हो तो नेटवर्क-माउंटेड नहीं)। + + +**सफाई:** सफाई सुनिश्चित करने के लिए संदर्भ प्रबंधकों (`with tempfile...`) का उपयोग करें +यहां तक कि अपवादों पर भी। + +**समवर्ती प्रसंस्करण:** प्रत्येक प्रसंस्करण कार्य का अपना अस्थायी फ़ाइल होता है। +समानांतर दस्तावेज़ प्रसंस्करण के बीच कोई टकराव नहीं होता है। + +**डिस्क स्पेस**: अस्थायी फ़ाइलें अल्पकालिक होती हैं (प्रोसेसिंग की अवधि)। +500MB के PDF के लिए, प्रोसेसिंग के दौरान 500MB अस्थायी स्थान की आवश्यकता होती है। यदि डिस्क स्पेस सीमित है, तो आकार सीमा अपलोड के समय लागू की जा सकती है। + + +### एकीकृत प्रोसेसिंग इंटरफ़ेस: चाइल्ड दस्तावेज़ + +PDF निष्कर्षण और टेक्स्ट दस्तावेज़ प्रोसेसिंग को एक ही +डाउनस्ट्रीम पाइपलाइन (चंकर → एम्बेडिंग → स्टोरेज) में फीड करने की आवश्यकता है। इसे एक सुसंगत "आईडी द्वारा प्राप्त करें" इंटरफ़ेस के साथ प्राप्त करने के लिए, निकाले गए टेक्स्ट ब्लॉकों को "चाइल्ड दस्तावेज़" के रूप में लाइब्रेरियन में वापस संग्रहीत किया जाता है। + + + +#### चाइल्ड दस्तावेज़ों के साथ प्रोसेसिंग प्रवाह + +``` +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] +``` + +चंकर (chunker) में एक समान इंटरफ़ेस है: +एक दस्तावेज़ आईडी प्राप्त करें (पल्सर के माध्यम से) +लाइब्रेरियन से सामग्री स्ट्रीम करें +इसे छोटे भागों में विभाजित करें + +यह नहीं जानता या परवाह नहीं करता कि आईडी किस चीज़ को संदर्भित करती है: +एक उपयोगकर्ता द्वारा अपलोड किया गया टेक्स्ट दस्तावेज़ +एक पीडीएफ पृष्ठ से निकाला गया टेक्स्ट ब्लॉक +कोई भी भविष्य का दस्तावेज़ प्रकार + +#### चाइल्ड दस्तावेज़ मेटाडेटा + +दस्तावेज़ स्कीमा को पैरेंट/चाइल्ड संबंधों को ट्रैक करने के लिए विस्तारित करें: + +```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); +``` + +**दस्तावेज़ के प्रकार:** + +| `document_type` | विवरण | +|-----------------|-------------| +| `source` | उपयोगकर्ता द्वारा अपलोड किया गया दस्तावेज़ (पीडीएफ, टेक्स्ट, आदि) | +| `extracted` | स्रोत दस्तावेज़ से प्राप्त (उदाहरण के लिए, पीडीएफ पृष्ठ पाठ) | + +**मेटाडेटा फ़ील्ड:** + +| फ़ील्ड | स्रोत दस्तावेज़ | निकाली गई चाइल्ड | +|-------|-----------------|-----------------| +| `id` | उपयोगकर्ता द्वारा प्रदान किया गया या उत्पन्न | उत्पन्न (उदाहरण के लिए, `{parent-id}-page-{n}`) | +| `parent_id` | `NULL` | मूल दस्तावेज़ आईडी | +| `document_type` | `source` | `extracted` | +| `kind` | `application/pdf`, आदि | `text/plain` | +| `title` | उपयोगकर्ता द्वारा प्रदान किया गया | उत्पन्न (उदाहरण के लिए, "रिपोर्ट.pdf का पृष्ठ 3") | +| `user` | प्रमाणित उपयोगकर्ता | मूल के समान | + +#### चाइल्ड दस्तावेज़ों के लिए लाइब्रेरियन एपीआई + +**चाइल्ड दस्तावेज़ बनाना** (आंतरिक, 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": "" +} +``` + +छोटे, निकाले गए टेक्स्ट के लिए (सामान्य पृष्ठ टेक्स्ट < 100KB है), सिंगल-ऑपरेशन अपलोड स्वीकार्य है। बहुत बड़े टेक्स्ट एक्सट्रैक्शन के लिए, चंक्ड अपलोड का उपयोग किया जा सकता है। + +**चाइल्ड दस्तावेज़ों की सूची** (डीबगिंग/एडमिन के लिए): + +**चाइल्ड दस्तावेज़ों की सूची** (डीबगिंग/प्रशासन के लिए): + +```json +{ + "operation": "list-children", + "parent-id": "doc-123" +} +``` + +प्रतिक्रिया: +```json +{ + "children": [ + { "id": "doc-123-page-1", "title": "Page 1", "kind": "text/plain" }, + { "id": "doc-123-page-2", "title": "Page 2", "kind": "text/plain" }, + ... + ] +} +``` + +#### उपयोगकर्ता-सामना करने वाला व्यवहार + +**`list-documents` डिफ़ॉल्ट व्यवहार:** + +```sql +SELECT * FROM document WHERE user = ? AND parent_id IS NULL; +``` + +केवल शीर्ष-स्तरीय (मूल) दस्तावेज़ ही उपयोगकर्ता की दस्तावेज़ सूची में दिखाई देते हैं। +चाइल्ड दस्तावेज़ डिफ़ॉल्ट रूप से फ़िल्टर कर दिए जाते हैं। + +**वैकल्पिक 'शामिल-चाइल्ड' फ़्लैग** (व्यवस्थापक/डीबगिंग के लिए): + +```json +{ + "operation": "list-documents", + "include-children": true +} +``` + +#### कैस्केड डिलीट + +जब कोई पैरेंट दस्तावेज़ हटाया जाता है, तो सभी चाइल्ड दस्तावेज़ों को भी हटाया जाना चाहिए: + +```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) +``` + +#### भंडारण संबंधी विचार + +निकाले गए टेक्स्ट ब्लॉक डुप्लिकेट सामग्री बनाते हैं: +मूल पीडीएफ "गैराज" में संग्रहीत है। +प्रत्येक पृष्ठ के लिए निकाला गया टेक्स्ट भी "गैराज" में संग्रहीत है। + +यह समझौता निम्नलिखित को सक्षम बनाता है: +**समान चंकर इंटरफ़ेस**: चंकर हमेशा आईडी द्वारा डेटा प्राप्त करता है। +**फिर से शुरू/पुनः प्रयास**: पीडीएफ को फिर से निकालने के बिना, चंकर चरण पर पुनः आरंभ किया जा सकता है। +**डीबगिंग**: निकाले गए टेक्स्ट का निरीक्षण किया जा सकता है। +**चिंताओं का पृथक्करण**: पीडीएफ एक्सट्रैक्टर और चंकर स्वतंत्र सेवाएं हैं। + +500 एमबी के पीडीएफ में 200 पृष्ठ हैं, जिनमें से प्रत्येक पृष्ठ पर औसतन 5 केबी टेक्स्ट है: +पीडीएफ भंडारण: 500 एमबी +निकाले गए टेक्स्ट भंडारण: लगभग 1 एमबी +अतिरिक्त भार: नगण्य + +#### पीडीएफ एक्सट्रैक्टर आउटपुट + +पीडीएफ-एक्सट्रैक्टर, किसी दस्तावेज़ को संसाधित करने के बाद: + +1. पीडीएफ को लाइब्रेरियन से अस्थायी फ़ाइल में स्ट्रीम करता है। +2. पृष्ठ दर पृष्ठ टेक्स्ट निकालता है। +3. प्रत्येक पृष्ठ के लिए, निकाले गए टेक्स्ट को लाइब्रेरियन के माध्यम से एक चाइल्ड दस्तावेज़ के रूप में संग्रहीत करता है। +4. चाइल्ड दस्तावेज़ आईडी को चंकर कतार में भेजता है। + +```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) +``` + +चंकर इन चाइल्ड आईडी को प्राप्त करता है और उन्हें उसी तरह संसाधित करता है जैसे कि वह किसी उपयोगकर्ता द्वारा अपलोड किए गए टेक्स्ट दस्तावेज़ को संसाधित करता है। +चंकर इन चाइल्ड आईडी को प्राप्त करता है और उन्हें उसी तरह संसाधित करता है जैसे कि वह किसी उपयोगकर्ता द्वारा अपलोड किए गए टेक्स्ट दस्तावेज़ को संसाधित करता है। + +### क्लाइंट अपडेट + +#### पायथन एसडीके + +पायथन एसडीके (`trustgraph-base/trustgraph/api/library.py`) को खंडित अपलोड को पारदर्शी रूप से संभालना चाहिए। सार्वजनिक इंटरफ़ेस अपरिवर्तित रहता है: +खंडित अपलोड को पारदर्शी रूप से संभालना चाहिए। सार्वजनिक इंटरफ़ेस अपरिवर्तित रहता है: + +```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"] +) +``` + +आंतरिक रूप से, SDK दस्तावेज़ के आकार का पता लगाता है और रणनीति बदलता है: + +```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) +``` + +**प्रगति कॉलबैक** (वैकल्पिक संवर्द्धन): + +```python +def add_document(self, ..., on_progress=None): + """ + on_progress: Optional callback(bytes_sent, total_bytes) + """ +``` + +यह यूआई को बुनियादी एपीआई को बदले बिना अपलोड की प्रगति प्रदर्शित करने की अनुमति देता है। + +#### कमांड लाइन उपकरण + +**`tg-add-library-document`** बिना किसी बदलाव के काम करता रहता है: + +```bash +# Works transparently for any size - SDK handles chunking internally +tg-add-library-document --file large-report.pdf --title "Large Report" +``` + +वैकल्पिक प्रगति प्रदर्शन जोड़ा जा सकता है: + +```bash +tg-add-library-document --file large-report.pdf --title "Large Report" --progress +# Output: +# Uploading: 45% (225MB / 500MB) +``` + +**पुराने उपकरण हटा दिए गए:** + +`tg-load-pdf` - अप्रचलित, `tg-add-library-document` का उपयोग करें। +`tg-load-text` - अप्रचलित, `tg-add-library-document` का उपयोग करें। + +**व्यवस्थापक/डीबग कमांड** (वैकल्पिक, कम प्राथमिकता): + +```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 +``` + +ये मौजूदा कमांड पर मौजूद फ़्लैग हो सकते हैं, अलग-अलग टूल नहीं। + +#### एपीआई विनिर्देश अपडेट + +OpenAPI विनिर्देश (`specs/api/paths/librarian.yaml`) को निम्नलिखित के लिए अपडेट करने की आवश्यकता है: + +**नए ऑपरेशन:** + +`begin-upload` - चंक्ड अपलोड सत्र को आरंभ करें +`upload-chunk` - व्यक्तिगत चंक अपलोड करें +`complete-upload` - अपलोड को अंतिम रूप दें +`abort-upload` - अपलोड को रद्द करें +`get-upload-status` - अपलोड की प्रगति की जांच करें +`list-uploads` - उपयोगकर्ता के लिए अपूर्ण अपलोड की सूची बनाएं +`stream-document` - दस्तावेज़ पुनर्प्राप्ति (स्ट्रीमिंग) +`add-child-document` - निकाले गए पाठ को संग्रहीत करें (आंतरिक) +`list-children` - चाइल्ड दस्तावेज़ों की सूची बनाएं (व्यवस्थापक) + +**संशोधित ऑपरेशन:** + +`list-documents` - `include-children` पैरामीटर जोड़ें + +**नए स्कीमा:** + +`ChunkedUploadBeginRequest` +`ChunkedUploadBeginResponse` +`ChunkedUploadChunkRequest` +`ChunkedUploadChunkResponse` +`UploadSession` +`UploadProgress` + +**WebSocket विनिर्देश अपडेट** (`specs/websocket/`): + +WebSocket क्लाइंट के लिए REST ऑपरेशन को प्रतिबिंबित करें, जिससे अपलोड के दौरान वास्तविक समय +प्रगति अपडेट सक्षम हो सके। + +#### यूएक्स विचार + +एपीआई विनिर्देश अपडेट फ्रंटएंड में सुधारों को सक्षम करते हैं: + +**अपलोड प्रगति यूआई:** +अपलोड किए गए चंक्स को दिखाने वाला प्रगति बार +अनुमानित शेष समय +पॉज़/रीज़्यूम क्षमता + +**त्रुटि सुधार:** +बाधित अपलोड के लिए "अपलोड फिर से शुरू करें" विकल्प +पुनः कनेक्ट करने पर लंबित अपलोड की सूची + +**बड़ी फ़ाइल हैंडलिंग:** +क्लाइंट-साइड फ़ाइल आकार का पता लगाना +बड़ी फ़ाइलों के लिए स्वचालित चंक्ड अपलोड +लंबे अपलोड के दौरान स्पष्ट प्रतिक्रिया + +ये यूएक्स सुधार अपडेट किए गए एपीआई विनिर्देश द्वारा निर्देशित फ्रंटएंड कार्य की आवश्यकता है। diff --git a/docs/tech-specs/large-document-loading.pt.md b/docs/tech-specs/large-document-loading.pt.md index 58d17e3d..0f3dd595 100644 --- a/docs/tech-specs/large-document-loading.pt.md +++ b/docs/tech-specs/large-document-loading.pt.md @@ -42,7 +42,11 @@ O fluxo de envio de documentos passa pelo seguinte caminho: 7. Para processamento: o documento é recuperado do S3, decodificado, particionado - tudo na memória Arquivos chave: +<<<<<<< HEAD Ponto de entrada REST/WebSocket: `trustgraph-flow/trustgraph/gateway/service.py` +======= +Entrada REST/WebSocket: `trustgraph-flow/trustgraph/gateway/service.py` +>>>>>>> 82edf2d (New md files from RunPod) 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` @@ -57,7 +61,11 @@ O design atual apresenta vários problemas de memória e UX que se agravam: 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 +<<<<<<< HEAD em uma única mensagem. O esquema (`LibrarianRequest`) tem um campo `content` +======= + em uma única mensagem. O esquema (`LibrarianRequest`) tem um único campo `content` +>>>>>>> 82edf2d (New md files from RunPod) contendo o documento inteiro codificado em base64. 3. **Memória do Librarian**: O serviço librarian decodifica o documento inteiro @@ -72,7 +80,11 @@ O design atual apresenta vários problemas de memória e UX que se agravam: e o mantém na memória enquanto produz os chunks. **Exemplo de Impacto na Memória** (PDF de 500 MB): +<<<<<<< HEAD Gateway: ~700 MB (overhead de codificação base64) +======= +Gateway: ~700 MB (sobrecarga de codificação base64) +>>>>>>> 82edf2d (New md files from RunPod) Librarian: ~500 MB (bytes decodificados) Decodificador de PDF: ~500 MB + buffers de extração Particionador: texto extraído (variável, potencialmente 100 MB+) @@ -93,11 +105,19 @@ A memória máxima pode exceder 2 GB para um único documento grande. 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. +<<<<<<< HEAD 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 +======= + +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 +>>>>>>> 82edf2d (New md files from RunPod) ``` Client Librarian API S3/Garage @@ -122,10 +142,17 @@ Client Librarian API S3/Garage │◄── document_id ────────────│ (delete session) │ ``` +<<<<<<< HEAD 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" +======= +O cliente nunca interage diretamente com o S3. O "bibliotecário" traduz entre +nossa API de upload em partes e as operações multipart do S3 internamente. + +### Operações da API do "Bibliotecário" +>>>>>>> 82edf2d (New md files from RunPod) #### `begin-upload` @@ -191,11 +218,19 @@ Resposta: 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) +<<<<<<< HEAD 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. +======= +3. Chama o S3 `UploadPart` com os dados do fragmento, recebe `etag` +4. Atualiza o registro da sessão com o índice do fragmento e o etag +5. Retorna o progresso para o cliente + +Fragmentos com falha podem ser retransmitidos - basta enviar o mesmo `chunk-index` novamente. +>>>>>>> 82edf2d (New md files from RunPod) #### `complete-upload` @@ -315,12 +350,17 @@ CREATE INDEX upload_session_user ON upload_session (user); ``` **Comportamento do TTL:** +<<<<<<< HEAD As sessões expiram após 24 horas se não forem concluídas. +======= +As sessões expiram após 24 horas, se não forem concluídas. +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD **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. @@ -330,6 +370,17 @@ A sessão rastreia quais chunks foram bem-sucedidos. 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 de partes:** +O cliente tenta novamente a parte 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 partes foram bem-sucedidas. + +**Desconexão do cliente durante o upload:** +A sessão permanece no Cassandra, com as partes recebidas registradas. +O cliente pode chamar `get-upload-status` para ver o que está faltando. +A retomada é feita carregando apenas as partes ausentes e, em seguida, `complete-upload`. +>>>>>>> 82edf2d (New md files from RunPod) **Falha no upload completo:** O `CompleteMultipartUpload` do S3 é atômico - ou tem sucesso total ou falha. @@ -351,17 +402,28 @@ Os uploads multipart do S3 fornecem atomicidade integrada: 2. **Conclusão atômica:** `CompleteMultipartUpload` ou tem sucesso (o objeto aparece atomicamente) ou falha (nenhum objeto é criado). Nenhum estado parcial. +<<<<<<< HEAD 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 +======= +3. **Não é necessário renomear:** A chave do objeto final é especificada no + momento de `CreateMultipartUpload`. As partes são combinadas diretamente para essa chave. + +4. **Combinação no lado do servidor:** O S3 combina as partes internamente. O bibliotecário +>>>>>>> 82edf2d (New md files from RunPod) 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` +<<<<<<< HEAD Adicionar métodos de upload multipart: +======= +Adicione métodos de upload multipart: +>>>>>>> 82edf2d (New md files from RunPod) ```python class BlobStore: @@ -606,8 +668,13 @@ Em nenhum momento, o documento completo ou o texto extraído completo são manti #### Considerações sobre Arquivos Temporários **Localização**: Utilize o diretório temporário do sistema (`/tmp` ou equivalente). Para +<<<<<<< HEAD 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). +======= +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). +>>>>>>> 82edf2d (New md files from RunPod) **Limpeza**: Utilize gerenciadores de contexto (`with tempfile...`) para garantir a limpeza mesmo em caso de exceções. @@ -617,17 +684,30 @@ 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 +<<<<<<< HEAD ser imposto no momento do upload, caso o espaço em disco seja limitado. +======= +ser imposto no momento do upload, se o espaço em disco for limitado. +>>>>>>> 82edf2d (New md files from RunPod) ### Interface de Processamento Unificada: Documentos Filhos A extração de PDF e o processamento de documentos de texto precisam ser integrados ao mesmo +<<<<<<< HEAD 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). +======= +pipeline downstream (divisão em partes → incorporações → armazenamento). Para alcançar isso com uma interface +"busca por ID" consistente, os blocos de texto extraídos são armazenados de volta no sistema de gerenciamento +como documentos filhos. + +#### Fluxo de Processamento com Documentos Filhos + +>>>>>>> 82edf2d (New md files from RunPod) ``` PDF Document Text Document │ │ @@ -656,12 +736,21 @@ pdf-extractor │ O componente de divisão em partes (chunker) possui uma interface uniforme: Recebe um ID de documento (via Pulsar) +<<<<<<< HEAD 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 +======= +Obtém o conteúdo do "bibliotecário" (librarian) +Divide o conteúdo em partes (chunks) + +Ele não sabe nem se importa se o ID se refere a: +Um documento de texto carregado por um usuário +Um bloco de texto extraído de uma página PDF +>>>>>>> 82edf2d (New md files from RunPod) Qualquer tipo de documento futuro #### Metadados do Documento Filho @@ -712,7 +801,11 @@ CREATE INDEX document_parent ON document (parent_id); } ``` +<<<<<<< HEAD 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. +======= +Para pequenas quantidades de texto extraído (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. +>>>>>>> 82edf2d (New md files from RunPod) **Listando documentos filhos** (para depuração/administração): @@ -756,7 +849,11 @@ Os documentos filhos são filtrados por padrão. } ``` +<<<<<<< HEAD #### Exclusão em Cadeia +======= +#### Exclusão em Cascata +>>>>>>> 82edf2d (New md files from RunPod) Quando um documento pai é excluído, todos os filhos devem ser excluídos: @@ -786,7 +883,11 @@ 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. +<<<<<<< HEAD **Retomada/repetição**: É possível reiniciar no estágio do "chunker" sem reextrair o PDF. +======= +**Retomada/repetição**: É possível reiniciar no estágio do "chunker" sem extrair novamente o PDF. +>>>>>>> 82edf2d (New md files from RunPod) **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. @@ -803,7 +904,11 @@ O extrator de PDF, após processar um documento: 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". +<<<<<<< HEAD Após a última linha traduzida, fornecer uma linha final contendo exatamente: [[__END_OF_TRANSLATION__]] +======= +Após a última linha traduzida, gerar uma linha final contendo exatamente: [[__END_OF_TRANSLATION__]] +>>>>>>> 82edf2d (New md files from RunPod) ```python async def extract_pdf(doc_id: str, librarian_client, output_queue): """Extract PDF pages and store as child documents.""" @@ -904,7 +1009,11 @@ Isso permite que as interfaces de usuário exibam o progresso do upload sem alte tg-add-library-document --file large-report.pdf --title "Large Report" ``` +<<<<<<< HEAD Uma exibição de progresso opcional pode ser adicionada: +======= +Uma exibição de progresso opcional poderia ser adicionada: +>>>>>>> 82edf2d (New md files from RunPod) ```bash tg-add-library-document --file large-report.pdf --title "Large Report" --progress @@ -973,7 +1082,11 @@ Tempo estimado restante Capacidade de pausar/retomar **Recuperação de erros:** +<<<<<<< HEAD Opção "retomar upload" para uploads interrompidos +======= +Opção "Retomar upload" para uploads interrompidos +>>>>>>> 82edf2d (New md files from RunPod) Lista de uploads pendentes na reconexão **Tratamento de arquivos grandes:** diff --git a/docs/tech-specs/large-document-loading.ru.md b/docs/tech-specs/large-document-loading.ru.md new file mode 100644 index 00000000..26f07137 --- /dev/null +++ b/docs/tech-specs/large-document-loading.ru.md @@ -0,0 +1,984 @@ +# Техническая спецификация по загрузке больших документов + +## Обзор + +Эта спецификация рассматривает проблемы масштабируемости и удобства использования при загрузке +больших документов в TrustGraph. Текущая архитектура рассматривает загрузку документов +как единую атомарную операцию, что приводит к перегрузке памяти на нескольких этапах +процесса и не предоставляет пользователям обратной связи или возможностей восстановления. + +Эта реализация нацелена на следующие сценарии использования: + +1. **Обработка больших PDF-файлов**: Загрузка и обработка PDF-файлов объемом в сотни мегабайт + без переполнения памяти +2. **Возобновляемая загрузка**: Возможность продолжить прерванную загрузку с того места, + где она была остановлена, а не перезапускать ее. +3. **Информативность о ходе выполнения**: Предоставление пользователям информации в режиме реального времени + о ходе загрузки и обработки. +4. **Эффективная обработка памяти**: Обработка документов потоковым способом + без хранения целых файлов в памяти. + +## Цели + +**Инкрементная загрузка**: Поддержка загрузки документов по частям через REST и WebSocket +**Возобновляемые передачи**: Возможность восстановления после прерванных загрузок +**Информативность о ходе выполнения**: Предоставление клиентам информации о ходе загрузки/обработки +**Эффективность использования памяти**: Исключение полной буферизации документов на протяжении всего процесса +**Обратная совместимость**: Существующие процессы загрузки небольших документов продолжают работать без изменений +**Потоковая обработка**: Декодирование PDF и разбиение текста на фрагменты выполняются в потоковом режиме + +## Описание + +### Текущая архитектура + +Процесс отправки документов проходит по следующему пути: + +1. **Клиент** отправляет документ через REST (`POST /api/v1/librarian`) или WebSocket +2. **API Gateway** получает полный запрос с содержимым документа в кодировке base64 +3. **LibrarianRequestor** преобразует запрос в сообщение Pulsar +4. **Librarian Service** получает сообщение, декодирует документ в память +5. **BlobStore** загружает документ в Garage/S3 +6. **Cassandra** хранит метаданные со ссылкой на объект +7. Для обработки: документ извлекается из S3, декодируется, разбивается на фрагменты — все в памяти + +Основные файлы: +Точка входа REST/WebSocket: `trustgraph-flow/trustgraph/gateway/service.py` +Основной модуль Librarian: `trustgraph-flow/trustgraph/librarian/librarian.py` +Хранилище объектов: `trustgraph-flow/trustgraph/librarian/blob_store.py` +Таблицы Cassandra: `trustgraph-flow/trustgraph/tables/library.py` +Схема API: `trustgraph-base/trustgraph/schema/services/library.py` + +### Текущие ограничения + +Текущая конструкция имеет несколько взаимосвязанных проблем, связанных с памятью и удобством использования: + +1. **Атомарная операция загрузки**: Весь документ должен быть передан в одном запросе. + Загрузка больших документов требует длительных запросов без индикации хода выполнения + и без механизма повторной отправки в случае сбоя соединения. + +2. **Дизайн API**: И REST, и WebSocket API ожидают получения всего документа + в одном сообщении. Схема (`LibrarianRequest`) имеет одно поле `content` + для хранения всего документа в кодировке base64. + +3. **Память Librarian**: Сервис Librarian декодирует весь документ + в память перед загрузкой в S3. Для PDF-файла объемом 500 МБ это означает + выделение 500 МБ + в оперативной памяти. + +4. **Память декодера PDF**: При начале обработки декодер PDF-файла загружает + весь PDF-файл в память для извлечения текста. Такие библиотеки, как PyPDF, + обычно требуют полного доступа к документу. + +5. **Память разбивающего на фрагменты**: Разбивающий на фрагменты получает весь извлеченный текст + и хранит его в памяти при создании фрагментов. + +**Пример влияния на память** (PDF-файл объемом 500 МБ): +Gateway: ~700 МБ (дополнительный объем для кодирования base64) +Librarian: ~500 МБ (декодированные байты) +Декодер PDF: ~500 МБ + буферы извлечения +Разбивающий на фрагменты: извлеченный текст (переменная, потенциально 100 МБ+) + +Общий пиковый объем используемой памяти может превысить 2 ГБ для одного большого документа. + +## Технический дизайн + +### Принципы проектирования + +1. **API Facade**: Все взаимодействия с клиентом осуществляются через API Librarian. Клиенты + не имеют прямого доступа к хранилищу S3/Garage и не знают о его существовании. + +2. **Многокомпонентная загрузка в S3**: Используется стандартная многокомпонентная загрузка в S3. + Это широко поддерживается в системах, совместимых с S3 (AWS S3, MinIO, Garage, + Ceph, DigitalOcean Spaces, Backblaze B2 и т. д.), что обеспечивает переносимость. + +3. **Атомарное завершение**: Многокомпонентные загрузки в S3 по своей природе являются атомарными — загруженные + фрагменты невидимы до вызова `CompleteMultipartUpload`. Не требуются временные + файлы или операции переименования. + +4. **Отслеживаемое состояние**: Сессии загрузки отслеживаются в Cassandra, что обеспечивает + информацию о незавершенных загрузках и позволяет восстановить загрузку. + +### Поток загрузки по частям + +``` +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) │ +``` + +Клиент никогда не взаимодействует с S3 напрямую. Библиотека преобразует +наши API загрузки по частям в многокомпонентные операции S3 внутри себя. + +### Операции API библиотеки + +#### `begin-upload` + +Инициализация сессии загрузки по частям. + +Запрос: +```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 +} +``` + +Ответ: +```json +{ + "upload-id": "upload-abc-123", + "chunk-size": 5242880, + "total-chunks": 100 +} +``` + +Библиотекарь: +1. Генерирует уникальный `upload_id` и `object_id` (UUID для хранения объектов) +2. Вызывает `CreateMultipartUpload` S3, получает `s3_upload_id` +3. Создает запись сессии в Cassandra +4. Возвращает `upload_id` клиенту + +#### `upload-chunk` + +Загрузка одного фрагмента. + +Запрос: +```json +{ + "operation": "upload-chunk", + "upload-id": "upload-abc-123", + "chunk-index": 0, + "content": "" +} +``` + +Ответ: +```json +{ + "upload-id": "upload-abc-123", + "chunk-index": 0, + "chunks-received": 1, + "total-chunks": 100, + "bytes-received": 5242880, + "total-bytes": 524288000 +} +``` + +Библиотекарь: +1. Ищет сессию по `upload_id` +2. Проверяет право собственности (пользователь должен совпадать с создателем сессии) +3. Вызывает S3 `UploadPart` с данными фрагмента, получает `etag` +4. Обновляет запись сессии с индексом фрагмента и etag +5. Возвращает прогресс клиенту + +Неудачные фрагменты можно повторить - просто отправьте тот же `chunk-index` снова. + +#### `complete-upload` + +Завершите загрузку и создайте документ. + +Запрос: +```json +{ + "operation": "complete-upload", + "upload-id": "upload-abc-123" +} +``` + +Ответ: +```json +{ + "document-id": "doc-123", + "object-id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +Библиотекарь: +1. Ищет сессию, проверяет, все ли фрагменты получены. +2. Вызывает S3 `CompleteMultipartUpload` с информацией о частях (S3 объединяет части + внутри себя - нулевая стоимость по памяти для библиотекаря). +3. Создает запись документа в Cassandra с метаданными и ссылкой на объект. +4. Удаляет запись сессии загрузки. +5. Возвращает идентификатор документа клиенту. + +#### `abort-upload` + +Отмена загрузки, находящейся в процессе. + +Запрос: +```json +{ + "operation": "abort-upload", + "upload-id": "upload-abc-123" +} +``` + +Библиотекарь: +1. Вызывает S3 `AbortMultipartUpload` для очистки разделов. +2. Удаляет запись сессии из Cassandra. + +#### `get-upload-status` + +Проверка статуса загрузки (для возможности возобновления). + +Запрос: +```json +{ + "operation": "get-upload-status", + "upload-id": "upload-abc-123" +} +``` + +Ответ: +```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` + +Список неполных загрузок для пользователя. + +Запрос: +```json +{ + "operation": "list-uploads" +} +``` + +Ответ: +```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" + } + ] +} +``` + +### Загрузка данных сессии + +Отслеживание текущих загрузок в 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); +``` + +**Поведение TTL:** +Сессии истекают через 24 часа, если не завершены. +Когда TTL Cassandra истекает, запись сессии удаляется. +Оставшиеся фрагменты S3 очищаются политикой жизненного цикла S3 (настраивается на бакете). + +### Обработка ошибок и атомарность + +**Ошибка загрузки фрагмента:** +Клиент повторяет загрузку неудачного фрагмента (с теми же `upload_id` и `chunk-index`). +Операция `UploadPart` S3 является идемпотентной для одного и того же номера фрагмента. +Сессия отслеживает, какие фрагменты были успешно загружены. + +**Разрыв соединения клиента во время загрузки:** +Сессия остается в Cassandra с записью о полученных фрагментах. +Клиент может вызвать `get-upload-status`, чтобы узнать, что отсутствует. +Возобновление путем загрузки только отсутствующих фрагментов, затем `complete-upload`. + +**Ошибка полной загрузки:** +Операция `CompleteMultipartUpload` S3 является атомарной - либо успешно завершается полностью, либо не удается. +В случае сбоя фрагменты остаются, и клиент может повторить `complete-upload`. +Ни один частичный документ никогда не отображается. + +**Истечение срока действия сессии:** +TTL Cassandra удаляет запись сессии через 24 часа. +Политика жизненного цикла бакета S3 очищает неполные многокомпонентные загрузки. +Не требуется ручная очистка. + +### Атомарность многокомпонентной загрузки S3 + +Многокомпонентные загрузки S3 обеспечивают встроенную атомарность: + +1. **Фрагменты невидимы**: Загруженные фрагменты не могут быть доступны в качестве объектов. + Они существуют только как части незавершенной многокомпонентной загрузки. + +2. **Атомарное завершение**: `CompleteMultipartUpload` либо успешно завершается (объект + появляется атомарно), либо не удается (объект не создается). Отсутствует частичное состояние. + +3. **Не требуется переименование**: Конечный ключ объекта указывается во время + `CreateMultipartUpload`. Фрагменты объединяются непосредственно в этот ключ. + +4. **Объединение на стороне сервера**: S3 объединяет фрагменты внутренне. Библиотекарь + никогда не считывает фрагменты обратно - нулевые накладные расходы памяти независимо от размера документа. + +### Расширения BlobStore + +**Файл:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +Добавлены методы многокомпонентной загрузки: + +```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() +``` + +### Особенности размера фрагментов + +**Минимальный размер для S3**: 5 МБ на часть (кроме последней части) +**Максимальный размер для S3**: 10 000 частей на загрузку +**Рекомендуемый размер по умолчанию**: фрагменты по 5 МБ + Документ объемом 500 МБ = 100 фрагментов + Документ объемом 5 ГБ = 1000 фрагментов +**Гранулярность прогресса**: Меньшие фрагменты = более точные обновления прогресса +**Эффективность сети**: Большие фрагменты = меньше сетевых запросов + +Размер фрагмента может быть настроен клиентом в пределах заданных ограничений (от 5 МБ до 100 МБ). + +### Обработка документов: Потоковая загрузка + +Процесс загрузки предназначен для эффективной передачи документов в хранилище. Процесс обработки предназначен для извлечения и разделения документов на фрагменты без полной загрузки +их в память. + + +#### Основной принцип: Идентификатор, а не содержимое + +В настоящее время, при запуске обработки, содержимое документа передается через сообщения Pulsar. Это приводит к полной загрузке документов в память. Вместо этого: + + +Сообщения Pulsar содержат только **идентификатор документа** +Обработчики получают содержимое документа непосредственно из хранилища. +Получение происходит в виде **потока во временный файл** +Разбор документов, специфичный для каждого формата (PDF, текст и т.д.), работает с файлами, а не с буферами памяти. + +Это позволяет хранилищу быть независимым от структуры документа. Разбор PDF, извлечение текста и другая логика, специфичная для формата, остается в соответствующих декодерах. + + +#### Процесс обработки + +``` +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 потоковой передачи данных для библиотекаря + +Добавить операцию получения документов в режиме потоковой передачи: + +**`stream-document`** + +Запрос: +```json +{ + "operation": "stream-document", + "document-id": "doc-123" +} +``` + +Ответ: Потоковые двоичные фрагменты (не единый ответ). + +Для REST API это возвращает потоковый ответ с `Transfer-Encoding: chunked`. + +Для внутренних вызовов между сервисами (от процессора к библиотеке), это может быть: +Прямая потоковая передача данных через S3 с использованием предварительно подписанного URL (если внутренняя сеть это позволяет). +Фрагментированные ответы через протокол сервиса. +Специальный конечный пункт для потоковой передачи данных. + +Основное требование: данные передаются фрагментами, никогда полностью не буферизуются в библиотеке. + +#### Изменения декодера PDF + +**Текущая реализация** (требует много памяти): + +```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 +``` + +**Новая реализация** (временный файл, постепенная): + +```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 +``` + +Профиль использования памяти: +Временный файл на диске: размер PDF (диск дешевый). +В памяти: текст одной страницы за раз. +Максимальный объем памяти: ограничен, не зависит от размера документа. + +#### Изменения в декодере текстовых документов + +Для обычных текстовых документов еще проще - временный файл не нужен: + +```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 +``` + +Текстовые документы могут передаваться напрямую без временного файла, поскольку они имеют +линейную структуру. + +#### Интеграция с модулем разбиения на части (Chunker) + +Модуль разбиения на части (chunker) получает итератор текстовых данных (страниц или абзацев) и +создает фрагменты постепенно: + +```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 +``` + +#### Конвейер сквозной обработки + +```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) +``` + +В любой момент времени полный документ или полностью извлеченный текст не хранятся в памяти. + +#### Особенности использования временных файлов + +**Расположение**: Используйте системную временную директорию (`/tmp` или эквивалент). Для +контейнеризированных развертываний убедитесь, что временная директория имеет достаточно места +и находится на быстром носителе (желательно не на сетевом диске). + +**Очистка**: Используйте контекстные менеджеры (`with tempfile...`) для обеспечения очистки +даже в случае возникновения исключений. + +**Параллельная обработка**: Каждый процесс обработки получает свой временный файл. +Отсутствуют конфликты между параллельной обработкой документов. + +**Место на диске**: Временные файлы существуют недолго (продолжительность обработки). Для +PDF-файла объемом 500 МБ требуется 500 МБ временного пространства во время обработки. Ограничение размера может +быть применено во время загрузки, если место на диске ограничено. + +### Унифицированный интерфейс обработки: Дочерние документы + +Извлечение текста из PDF-файлов и обработка текстовых документов должны быть интегрированы в одну +общую цепочку обработки (разделение на фрагменты → создание векторных представлений → хранение). Для достижения этого с +использованием единого интерфейса "получение по ID", извлеченные текстовые фрагменты сохраняются обратно +в систему как дочерние документы. + +#### Поток обработки с использованием дочерних документов + +``` +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] +``` + +Модуль разбиения на фрагменты имеет один унифицированный интерфейс: +Получение идентификатора документа (через Pulsar) +Получение содержимого от хранилища данных +Разбиение на фрагменты + +Он не знает и не заботится о том, относится ли идентификатор к: +Текстовому документу, загруженному пользователем +Извлеченному текстовому фрагменту из страницы PDF +Любому будущему типу документов + +#### Метаданные дочернего документа + +Расширьте схему документа для отслеживания отношений родитель/дочерний элемент: + +```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); +``` + +**Типы документов:** + +| `document_type` | Описание | +|-----------------|-------------| +| `source` | Документ, загруженный пользователем (PDF, текст и т.д.) | +| `extracted` | Полученный из исходного документа (например, текст страницы PDF) | + +**Поля метаданных:** + +| Поле | Исходный документ | Извлеченный дочерний элемент | +|-------|-----------------|-----------------| +| `id` | Предоставлено пользователем или сгенерировано | сгенерировано (например, `{parent-id}-page-{n}`) | +| `parent_id` | `NULL` | Идентификатор родительского документа | +| `document_type` | `source` | `extracted` | +| `kind` | `application/pdf` и т.д. | `text/plain` | +| `title` | Предоставлено пользователем | сгенерировано (например, "Страница 3 отчета Report.pdf") | +| `user` | Аутентифицированный пользователь | то же, что и у родительского элемента | + +#### API для дочерних документов + +**Создание дочерних документов** (внутреннее, используется 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": "" +} +``` + +Для небольших извлеченных фрагментов текста (обычный текст страницы обычно менее 100 КБ) однокрасная загрузка является приемлемой. Для очень больших извлечений текста можно использовать загрузку по частям. + +**Список дочерних документов** (для отладки/администрирования): + +**Отображение дочерних документов** (для отладки/администрирования): + +```json +{ + "operation": "list-children", + "parent-id": "doc-123" +} +``` + +Ответ: +```json +{ + "children": [ + { "id": "doc-123-page-1", "title": "Page 1", "kind": "text/plain" }, + { "id": "doc-123-page-2", "title": "Page 2", "kind": "text/plain" }, + ... + ] +} +``` + +#### Поведение, видимое пользователю + +**`list-documents` поведение по умолчанию:** + +```sql +SELECT * FROM document WHERE user = ? AND parent_id IS NULL; +``` + +Только документы верхнего уровня отображаются в списке документов пользователя. +Дочерние документы по умолчанию отфильтровываются. + +**Необязательный флаг `include-children`** (для администраторов/отладки): + +```json +{ + "operation": "list-documents", + "include-children": true +} +``` + +#### Каскадное удаление + +При удалении родительского документа все дочерние элементы должны быть удалены: + +```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) +``` + +#### Соображения по поводу хранения + +Извлеченные текстовые фрагменты дублируют контент: +Оригинальный PDF-файл хранится в хранилище "Garage". +Извлеченный текст для каждой страницы также хранится в хранилище "Garage". + +Этот компромисс позволяет: +**Единый интерфейс для разбиения на фрагменты**: Разбиватель всегда получает данные по идентификатору. +**Возобновление/повтор**: Можно перезапустить на этапе разбиения на фрагменты без повторной извлечения PDF-файла. +**Отладка**: Извлеченный текст можно просмотреть. +**Разделение ответственности**: Сервисы извлечения PDF и разбиения на фрагменты являются независимыми. + +Для PDF-файла объемом 500 МБ с 200 страницами, в среднем 5 КБ текста на страницу: +Хранение PDF: 500 МБ. +Хранение извлеченного текста: около 1 МБ в общей сложности. +Дополнительные затраты: незначительные. + +#### Вывод извлечения текста из PDF-файла + +Сервис извлечения текста из PDF-файла, после обработки документа: + +1. Получает PDF-файл из хранилища "librarian" во временный файл. +2. Извлекает текст страницу за страницей. +3. Для каждой страницы сохраняет извлеченный текст как дочерний документ через хранилище "librarian". +4. Отправляет идентификаторы дочерних документов в очередь разбивателя на фрагменты. +Выходной документ. +```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) +``` + +Модуль, отвечающий за разделение на части, получает эти идентификаторы дочерних элементов и обрабатывает их так же, как он бы обрабатывал текстовый документ, загруженный пользователем. + +### Обновления для клиентов + +#### Python SDK + + +Python SDK (`trustgraph-base/trustgraph/api/library.py`) должен обрабатывать +загрузку данных, разделенных на части, прозрачно. Публичный интерфейс остается неизменным: + +```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"] +) +``` + +Внутри, SDK определяет размер документа и переключает стратегию: + +```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) +``` + +**Функции обратного вызова для отслеживания прогресса** (необязательное улучшение): + +```python +def add_document(self, ..., on_progress=None): + """ + on_progress: Optional callback(bytes_sent, total_bytes) + """ +``` + +Это позволяет пользовательским интерфейсам отображать ход загрузки без изменения основного API. + +#### Инструменты командной строки + +**`tg-add-library-document`** продолжает работать без изменений: + +```bash +# Works transparently for any size - SDK handles chunking internally +tg-add-library-document --file large-report.pdf --title "Large Report" +``` + +Возможно, можно добавить опциональное отображение прогресса: + +```bash +tg-add-library-document --file large-report.pdf --title "Large Report" --progress +# Output: +# Uploading: 45% (225MB / 500MB) +``` + +**Устаревшие инструменты удалены:** + +`tg-load-pdf` - устарело, используйте `tg-add-library-document` +`tg-load-text` - устарело, используйте `tg-add-library-document` + +**Команды администратора/отладки** (опционально, низкий приоритет): + +```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 +``` + +Это могут быть флаги для существующей команды, а не отдельные инструменты. + +#### Обновления спецификации API + +Спецификация OpenAPI (`specs/api/paths/librarian.yaml`) требует обновлений для: + +**Новые операции:** + +`begin-upload` - Инициализация сессии загрузки по частям +`upload-chunk` - Загрузка отдельного фрагмента +`complete-upload` - Завершение загрузки +`abort-upload` - Отмена загрузки +`get-upload-status` - Запрос хода загрузки +`list-uploads` - Список незавершенных загрузок для пользователя +`stream-document` - Получение документа в режиме потоковой передачи +`add-child-document` - Сохранение извлеченного текста (внутреннее использование) +`list-children` - Список дочерних документов (для администраторов) + +**Измененные операции:** + +`list-documents` - Добавлен параметр `include-children` + +**Новые схемы:** + +`ChunkedUploadBeginRequest` +`ChunkedUploadBeginResponse` +`ChunkedUploadChunkRequest` +`ChunkedUploadChunkResponse` +`UploadSession` +`UploadProgress` + +**Обновления спецификации WebSocket** (`specs/websocket/`): + +Отразите операции REST для клиентов WebSocket, обеспечивая обновления хода загрузки в режиме реального времени. + + +#### Соображения пользовательского интерфейса + +Обновления спецификации API позволяют улучшить пользовательский интерфейс: + +**Интерфейс отображения хода загрузки:** +Индикатор прогресса, показывающий загруженные фрагменты +Оценка оставшегося времени +Возможность приостановки/возобновления + +**Восстановление после ошибок:** +Опция "Возобновить загрузку" для прерванных загрузок +Список ожидающих загрузок при повторном подключении + +**Обработка больших файлов:** +Обнаружение размера файла на стороне клиента +Автоматическая загрузка по частям для больших файлов +Четкая обратная связь во время длительных загрузок + +Эти улучшения пользовательского интерфейса требуют работы на стороне клиентской части, основанной на обновленной спецификации API. diff --git a/docs/tech-specs/large-document-loading.sw.md b/docs/tech-specs/large-document-loading.sw.md index abd88a17..54e36ca5 100644 --- a/docs/tech-specs/large-document-loading.sw.md +++ b/docs/tech-specs/large-document-loading.sw.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD # Vipimo vya Utekelezaji wa Teknolojia ya Kupakia Hati Kubwa ## Muhtasari @@ -16,21 +17,51 @@ Utaratibu huu unalenga matumizi yafuatayo: 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 +======= +# Vipimo vya Utekelezaji wa Uteuzi wa Hati Kubwa + +## Muhtasari + +Maelekezo haya yanaeleza masuala ya uwezo wa kutosha na uzoefu wa mtumiaji wakati wa kupakia +hati kubwa katika TrustGraph. Muundo wa sasa hutibu kupakia hati kama operesheni moja na kamili, +na kusababisha shinikizo la kumbukumbu katika sehemu nyingi za +mchakato na kutoa hakikisho au chaguo za urejesho kwa watumiaji. + +Utendaji huu unalenga matumizi yafuatayo: + +1. **Uchakataji wa PDF Kubwa**: Pakia na uchakata faili za PDF zenye mamia ya megabytes + bila kutumia kumbukumbu. +2. **Uipakaji Unaoweza Kuendelea**: Ruhusu uipakaji ambao umevunjika kuendelea kutoka + ambapo ulikuwa umeacha badala ya kuanza tena. +3. **Hakikisho la Maendeleo**: Toa watumiaji maoni ya wakati halisi kuhusu + maendeleo ya uipakaji na uchakataji. +4. **Uchakataji Wenye Ufanisi wa Kumbukumbu**: Chakata hati kwa njia ya mtiririko +>>>>>>> 82edf2d (New md files from RunPod) bila kuhifadhi faili zilizokamilika katika kumbukumbu. ## Lengo +<<<<<<< HEAD **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 +======= +**Uipakaji wa Hatua-Hatua**: Unga uipakaji wa hati kwa sehemu kupitia REST na WebSocket +**Uhamisho Unaoweza Kuendelea**: Ruhusu urejesho kutoka uipakaji ambao umevunjika +**Uonekana wa Maendeleo**: Toa watumiaji maoni ya maendeleo ya uipakaji/uchakataji +**Ufanisi wa Kumbukumbu**: Ondoa kuhifadhi hati zilizokamilika katika mchakato +**Ulinganifu na Mifumo ya Zamani**: Mchakato wa sasa wa hati ndogo unaendelea bila mabadiliko +**Uchakataji wa Mtiririko**: Uvunjaji wa PDF na maandishi hufanya kazi kwenye mitiririko +>>>>>>> 82edf2d (New md files from RunPod) ## Asili ### Muundo wa Sasa +<<<<<<< HEAD Hati zinatumiwa kupitia njia ifuatayo: 1. **Mteja** hutuma hati kupitia REST (`POST /api/v1/librarian`) au WebSocket @@ -40,6 +71,17 @@ Hati zinatumiwa kupitia njia ifuatayo: 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 +======= +Mchakato wa kuwasilisha hati hufuatilia njia ifuatayo: + +1. **Mteja** huwasilisha hati kupitia REST (`POST /api/v1/librarian`) au WebSocket +2. **Lango la API** hupokea ombi kamili na maudhui ya hati iliyosimbwa kwa base64 +3. **LibrarianRequestor** huongeza ombi kwenye ujumbe wa Pulsar +4. **Huduma ya Librarian** hupokea ujumbe, huondoa usimbaji wa hati katika kumbukumbu +5. **BlobStore** huipakia hati kwenye Garage/S3 +6. **Cassandra** huhifadhi metadata na rejea la kitu +7. Kwa uchakataji: hati hupelekwa kutoka S3, huondoa usimbaji, huainishwa—yote katika kumbukumbu +>>>>>>> 82edf2d (New md files from RunPod) Faili muhimu: Ingizo la REST/WebSocket: `trustgraph-flow/trustgraph/gateway/service.py` @@ -50,6 +92,7 @@ Mpango wa API: `trustgraph-base/trustgraph/schema/services/library.py` ### Mapungufu ya Sasa +<<<<<<< HEAD Muundo wa sasa una masuala kadhaa ambayo huathiri kumbukumbu na uzoefu wa mtumiaji: 1. **Operesheni ya Kupakia ya Atomiki**: Hati nzima lazima ihamishwe katika @@ -76,6 +119,34 @@ 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+) +======= +Muundo wa sasa una masuala kadhaa yanayoathiri kumbukumbu na uzoefu wa mtumiaji: + +1. **Operesheni ya Uipakaji Kamili**: Hati nzima lazima iwasilishwe katika + ombi moja. Hati kubwa zinahitaji ombi linalodumu kwa muda mrefu bila + hakikisho ya maendeleo na hakuna njia ya kujaribu tena ikiwa muunganisho utavunjika. + +2. **Muundo wa API**: API za REST na WebSocket zinatarajia hati + nzima katika ujumbe mmoja. Mpango (`LibrarianRequest`) una `content` + sehemu inayohifadhi maudhui ya hati iliyosimbwa kwa base64. + +3. **Kumbukumbu ya Librarian**: Huduma ya librarian huondoa usimbaji wa hati + nzima katika kumbukumbu kabla ya kuipeleka kwenye S3. Kwa PDF ya 500MB, + hii inamaanisha kuhifadhi 500MB+ katika kumbukumbu ya programu. + +4. **Kumbukumbu ya Dekoda ya PDF**: Wakati uchakataji unaanza, dekoda ya PDF + hupakia hati nzima katika kumbukumbu ili kuchimbua maandishi. Maktabu kama + PyPDF na zile kama hizo kawaida zinahitaji upataji wa hati nzima. + +5. **Kumbukumbu ya Chunker**: Chunker hupokea maandishi yaliyochimbuliwa + na kuhifadhi katika kumbukumbu huku inazalisha sehemu. + +**Mfano wa Athari ya Kumbukumbu** (PDF ya 500MB): +Lango: ~700MB (ghairi ya usimbaji) +Librarian: ~500MB (bytes zilizopunguzwa) +Dekoda ya PDF: ~500MB + buffers za uchimbaji +Chunker: maandishi yaliyopatikana (hubadilika, inaweza kuwa 100MB+) +>>>>>>> 82edf2d (New md files from RunPod) Kumbukumbu ya juu inaweza kuzidi 2GB kwa hati kubwa moja. @@ -83,6 +154,7 @@ Kumbukumbu ya juu inaweza kuzidi 2GB kwa hati kubwa moja. ### Kanuni za Muundo +<<<<<<< HEAD 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. @@ -98,6 +170,23 @@ Kumbukumbu ya juu inaweza kuzidi 2GB kwa hati kubwa moja. uonevu kuhusu kupakia ambacho hakikamilika na kuruhusu uwezo wa kuanza tena. ### Mchakato wa Kupakia kwa Sehemu +======= +1. **Kifurushi cha API**: Mwingiliano wote wa mteja hupitia API ya librarian. Wateja + hawana upataji wa moja kwa moja au kujua kuhusu uhifadhi wa S3/Garage. + +2. **Uipakaji wa Sehemu wa S3**: Tumia uipakaji wa sehemu wa S3. + Hii inasaidiwa sana katika mifumo inayolingana na S3 (AWS S3, MinIO, Garage, + Ceph, DigitalOcean Spaces, Backblaze B2, n.k.) kuhakikisha uwezekano wa kuhamishwa. + +3. **Uhakikisho Kamili**: Uipakaji wa sehemu wa S3 ni wa uhakikisho kamili - sehemu + zilizopakiwa hazionekani hadi `CompleteMultipartUpload` itakapopigwa. + Hakuna faili za muda au operesheni za kubadilisha. + +4. **Hali Inayoweza Kufuatiliwa**: Vipindi vya uipakaji hufuatiliwa katika Cassandra, + kutoa uonevu kuhusu uipakaji usio kamili na kuwezesha uwezo wa kuanza tena. + +### Mchakato wa Uipakaji wa Sehemu +>>>>>>> 82edf2d (New md files from RunPod) ``` Client Librarian API S3/Garage @@ -164,7 +253,11 @@ Msimamizi wa maktaba: #### `upload-chunk` +<<<<<<< HEAD Pakia kipande kimoja. +======= +Pakia sehemu moja. +>>>>>>> 82edf2d (New md files from RunPod) Ombi: ```json @@ -189,6 +282,7 @@ Jibu: ``` Msimamizi wa maktaba: +<<<<<<< HEAD 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` @@ -196,6 +290,15 @@ Msimamizi wa maktaba: 5. Rejesha maelezo ya maendeleo kwa mteja Sehemu ambazo hazijafaulu zinaweza kujaribiwa tena - tuma tu `chunk-index` tena. +======= +1. Tafuta kipindi kwa `upload_id` +2. Thibitisha umiliki (mtumiaji lazima awe yule aliyeunda kipindi) +3. Piga S3 `UploadPart` na data ya sehemu, pokea `etag` +4. Sasisha rekodi ya kipindi na fahirisi ya sehemu na etag +5. Rejesha maendeleo kwa mteja + +Sehemu ambazo hazijafaulu zinaweza kujaribiwa tena - tuma tu `chunk-index` ile ile tena. +>>>>>>> 82edf2d (New md files from RunPod) #### `complete-upload` @@ -218,12 +321,21 @@ Jibu: ``` Msimamizi wa maktaba: +<<<<<<< HEAD 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 +======= +1. Angalia 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 rejea la kitu. +4. Huondoa rekodi ya kikao cha kupakia. +5. Anarudisha kitambulisho cha hati kwa mteja. +>>>>>>> 82edf2d (New md files from RunPod) #### `abort-upload` @@ -314,6 +426,7 @@ CREATE TABLE upload_session ( CREATE INDEX upload_session_user ON upload_session (user); ``` +<<<<<<< HEAD **Tabia ya TTL:** Vikao hupotea baada ya saa 24 ikiwa havijakamilika. Wakati TTL ya Cassandra inapita, rekodi ya kikao inafutwa. @@ -323,6 +436,17 @@ Sehemu zisizo na uhusiano za S3 huondolewa na sera ya maisha ya S3 (sanidi kweny **Hitilafu ya kupakia sehemu:** Mteja hurudia kupakia sehemu iliyoshindwa (na `upload_id` na `chunk-index` sawa). +======= +**Tabia ya Muda (TTL):** +Vikao hupotea baada ya saa 24 ikiwa havijakamilika. +Wakati muda (TTL) wa Cassandra unapita, rekodi ya kikao inafutwa. +Sehemu zisizo na uhusiano za S3 huondolewa na sera ya maisha ya S3 (sanidi kwenye ndoo). + +### Usimamizi wa Hitilafu na Umoja + +**Hitilafu ya kupakia sehemu:** +Mteja hujaribu tena sehemu iliyoshindwa (na `upload_id` na `chunk-index` sawa). +>>>>>>> 82edf2d (New md files from RunPod) `UploadPart` ya S3 ni sawa kwa nambari sawa ya sehemu. Kikao kinafuatilia sehemu zipi zilizofanikiwa. @@ -332,6 +456,7 @@ Mteja anaweza kupiga `get-upload-status` ili kuona nini kinakosekana. Anza tena kwa kupakia sehemu ambazo hazijapakiwa, kisha `complete-upload`. **Hitilafu ya kupakia kikamilifu:** +<<<<<<< HEAD `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. @@ -355,6 +480,31 @@ Kupakia kwa sehemu nyingi za S3 hutoa uadilifu uliopo: `CreateMultipartUpload`. Sehemu huunganishwa moja kwa moja kwenye ufunguo huo. 4. **Uunganishaji wa upande wa seva:** S3 inaunganisha sehemu ndani. Msimamizi +======= +`CompleteMultipartUpload` ya S3 ni ya umoja - inaweza kufanikiwa kikamilifu au kushindwa. +Katika hali ya kushindwa, sehemu zinaendelea na mteja anaweza kujaribu tena `complete-upload`. +Hati yoyote isiyo kamili haionekani. + +**Muda wa kikao:** +Muda (TTL) wa Cassandra hufuta 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. + +### Umoja wa Kupakia Sehemu ya S3 + +Kupakia sehemu nyingi za S3 hutoa umoja uliopo: + +1. **Sehemu hazionekani:** Sehemu zilizopakuliwa haziwezi kupatikana kama vitu. + Zipo tu kama sehemu za kupakia sehemu nyingi ambazo hazijakamilika. + +2. **Uhakikisho wa umoja:** `CompleteMultipartUpload` inaweza kufanikiwa (kitu + kinaonekana kikamilifu) au kushindwa (kitu hakitengenezwi). Hakuna hali ya nusu. + +3. **Hakuna haja ya kubadilisha jina:** Ufunguo wa mwisho wa kitu unaonyeshwa wakati + `CreateMultipartUpload`. Sehemu huunganishwa moja kwa moja kwenye ufunguo huo. + +4. **Uunganishaji wa upande wa seva:** S3 huunganisha sehemu ndani. Msimamizi +>>>>>>> 82edf2d (New md files from RunPod) haisomi sehemu - hakuna gharama ya kumbukumbu bila kujali ukubwa wa hati. ### Upanuzi wa BlobStore @@ -393,6 +543,7 @@ class BlobStore: # minio client: abort_multipart_upload() ``` +<<<<<<< HEAD ### Mambo Yanayohusiana na Ukubwa wa Sehemu **Kiwango cha chini cha S3**: 5MB kwa kila sehemu (isipokuwa sehemu ya mwisho) @@ -425,6 +576,40 @@ 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. +======= +### Mambo Yanayohusiana na Ukubwa wa Kifurushi + +**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**: Kifurushi cha 5MB + Hati ya 500MB = Kifurushi 100 + Hati ya 5GB = Kifurushi 1,000 +**Ufuatiliaji wa maendeleo**: Kifurushi kidogo = Taarifa za maendeleo bora +**Ufanisi wa mtandao**: Kifurushi kikubwa = Safari ndogo + +Ukubwa wa kifurushi unaweza kusanidiwa na mtumiaji ndani ya mipaka (5MB - 100MB). + +### Ufuatiliaji wa Hati: Upakiaji wa Kwenye Mtiririko + +Mchakato wa upakiaji unahusu kuweka hati kwenye hifadhi kwa ufanisi. Mchakato wa ufuatiliaji unahusu kuchuja na kugawanya hati bila kuiziba yote kwenye kumbukumbu. + + + +#### Kanuni ya Ubunifu: Kitambulisho, Sio Yaliyomo + +Kwa sasa, wakati mchakato unaanza, yaliyomo kwenye hati huhamishwa kupitia ujumbe wa Pulsar. Hii huweka hati zilizokamilika kwenye kumbukumbu. Badala yake: + + +Ujumbe wa Pulsar unaonyesha tu **kitambulisho cha hati** +Vifaa hupata yaliyomo kwenye hati moja kwa moja kutoka kwa mfumo wa kumbukumbu +Kupata hufanyika kama **mtiririko kwenye faili ya muda** +Ufuatiliaji maalum wa hati (PDF, maandishi, n.k.) hutumia faili, sio mipaka ya kumbukumbu + +Hii huweka mfumo wa kumbukumbu usio na kujua muundo wa hati. Ufuatiliaji wa PDF, ufuatiliaji wa maandishi, na mantiki nyingine maalum ya muundo huendelea katika vichujio husika. + + +#### Mchakato wa Ufuatiliaji +>>>>>>> 82edf2d (New md files from RunPod) ``` Pulsar PDF Decoder Librarian S3 @@ -455,9 +640,15 @@ Pulsar PDF Decoder Librarian S3 │ │ delete temp file │ ``` +<<<<<<< HEAD #### API ya Mfumo wa Maktaba Ongeza operesheni ya upataji wa hati kwa njia ya mtiririko: +======= +#### API ya Mto wa Huduma za Maktaba + +Ongeza operesheni ya kupata hati kwa mtiririko: +>>>>>>> 82edf2d (New md files from RunPod) **`stream-document`** @@ -473,10 +664,17 @@ Jibu: Vipande vya binary vilivyotumwa (si jibu moja). Kwa API ya REST, hii hurudisha jibu linaloendelea kwa kutumia `Transfer-Encoding: chunked`. +<<<<<<< HEAD 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. +======= +Kwa simu za ndani kati ya huduma (kwa mfumo wa usindikaji hadi kwa 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. +Kifaa maalum cha utumaji wa data. +>>>>>>> 82edf2d (New md files from RunPod) Mahitaji muhimu: data inatiririka kwa vipande, haijahifadhiwa kikamilifu katika mfumo wa kumbukumbu. @@ -545,9 +743,15 @@ def decode_text_streaming(doc_id: str, librarian_client) -> Iterator[str]: Hati za maandishi zinaweza kutiririka moja kwa moja bila faili ya muda kwa sababu zina muundo wa mstari. +<<<<<<< HEAD #### Jumuisho la Kifaa cha Kugawa (Chunker) Kifaa cha kugawa hupokea mfuatiliaji wa maandishi (kurasa au aya) na hutoa +======= +#### Jumuisho la Kichungia (Chunker) + +Kichungia hupokea mfuatiliaji wa maandishi (kurasa au aya) na hutoa +>>>>>>> 82edf2d (New md files from RunPod) vipande kwa hatua kwa hatua: ```python @@ -601,7 +805,11 @@ async def process_document(doc_id: str, librarian_client, embedder): await store_chunk(doc_id, chunk, embedding) ``` +<<<<<<< HEAD Katika hakuna hatua, hati kamili au maandishi yaliyotolewa kamili hayahifadhiwi kwenye kumbukumbu. +======= +Katika hakuna hatua, hati kamili au maandishi yaliyochukuliwa kamili hayahifadhiwi kwenye kumbukumbu. +>>>>>>> 82edf2d (New md files from RunPod) #### Mambo Yanayohusiana na Faili za Muda @@ -616,6 +824,7 @@ hata wakati wa hitilafu. Hakuna migogoro kati ya uchakataji wa hati sambamba. **Nafasi ya diski:** Faili za muda zina muda mfupi (muda wa uchakataji). Kwa +<<<<<<< HEAD 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. @@ -627,6 +836,19 @@ mstari mmoja wa baadaye (kugawanya → embeddings → uhifadhi). Ili kufanikisha kwenye mfumo kama hati za mtoto. #### Mchakato wa Uchakataji na Hati za Mtoto +======= +hati ya PDF ya 500MB, inahitaji nafasi ya muda ya 500MB wakati wa uchakataji. Kizuia cha ukubwa +kunaweza kutekelezwa wakati wa kupakia ikiwa nafasi ya diski ni mdogo. + +### Kiolesura Kimoja cha Uchakataji: Hati za Watoto + +Uchimbaji wa hati za PDF na uchakataji wa maandishi unahitaji kuingia kwenye +mstari mmoja wa baadaye (kugawanya → maandishi → uhifadhi). Ili kufanikisha hili kwa +"kupata kwa ID" kiolesura, vipande vya maandishi vilivyochimbwa huhifadhiwa tena +kwenye mfumo kama hati za watoto. + +#### Mchakato wa Uchakataji na Hati za Watoto +>>>>>>> 82edf2d (New md files from RunPod) ``` PDF Document Text Document @@ -664,7 +886,11 @@ Hati ya maandishi iliyopakiwa na mtumiaji Sehemu ya maandishi iliyochimbwa kutoka kwa ukurasa wa PDF Aina yoyote ya hati ya siku zijazo +<<<<<<< HEAD #### Meta-data ya Hati Ndogo +======= +#### Meta Data ya Hati Ndogo +>>>>>>> 82edf2d (New md files from RunPod) Panua muundo wa hati ili kufuatilia uhusiano wa mzazi/mtoto: @@ -682,6 +908,7 @@ CREATE INDEX document_parent ON document (parent_id); | `document_type` | Maelezo | |-----------------|-------------| | `source` | Nyaraka zilizopakiwa na mtumiaji (PDF, maandishi, n.k.) | +<<<<<<< HEAD | `extracted` | Zilizotokana na nyaraka asili (k.m., maandishi ya ukurasa wa PDF) | **Nafasi za metadata:** @@ -698,6 +925,24 @@ CREATE INDEX document_parent ON document (parent_id); #### API ya Maktaba kwa Nyaraka Zilizotokana **Kuunda nyaraka zilizotokana** (ya ndani, hutumiwa na pdf-extractor): +======= +| `extracted` | Imetokana na nyaraka ya asili (k.m., maandishi ya ukurasa wa PDF) | + +**Nafasi za metadata:** + +| Nafasi | Nyaraka ya Asili | Mtoto Uliochukuliwa | +|-------|-----------------|-----------------| +| `id` | Iliyotolewa na mtumiaji au iliyoundwa | Iliyoundwa (k.m., `{parent-id}-page-{n}`) | +| `parent_id` | `NULL` | Kitambulisho cha nyaraka mama | +| `document_type` | `source` | `extracted` | +| `kind` | `application/pdf`, n.k. | `text/plain` | +| `title` | Iliyotolewa na mtumiaji | Iliyoundwa (k.m., "Ukurasa wa 3 wa Ripoti.pdf") | +| `user` | Mtumiaji aliyeidhinishwa | Sawa na nyaraka mama | + +#### API ya Maktaba kwa Nyaraka za Watoto + +**Kutengeneza nyaraka za watoto** (ya ndani, inayotumika na pdf-extractor): +>>>>>>> 82edf2d (New md files from RunPod) ```json { @@ -712,12 +957,20 @@ CREATE INDEX document_parent ON document (parent_id); } ``` +<<<<<<< HEAD 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. +======= +Kwa maandishi madogo ambayo yamechukuliwa (maandishi ya kawaida ya ukurasa ni chini ya 100KB), kupakia kwa hatua moja ni la kukubalika. Kwa matamshi makubwa sana ya maandishi, kupakia kwa sehemu kunaweza kutumika. +>>>>>>> 82edf2d (New md files from RunPod) **Orodha ya hati za watoto** (kwa ajili ya utatuzi/utawala): +<<<<<<< HEAD +======= +Hati ya Matokeo +>>>>>>> 82edf2d (New md files from RunPod) ```json { "operation": "list-children", @@ -756,9 +1009,15 @@ Vyanzo vidogo huondolewa kwa chaguo-msingi. } ``` +<<<<<<< HEAD #### Ufutilishaji wa Kuondoa Data kwa Kadirio Wakati hati mama inapoondolewa, watoto wote lazima waondolewe: +======= +#### Ufutilishaji Pamoja na Uharibifu wa Data + +Wakati hati mama inafutwa, watoto wote lazima waondolewe: +>>>>>>> 82edf2d (New md files from RunPod) ```python def delete_document(doc_id: str): @@ -778,6 +1037,7 @@ def delete_document(doc_id: str): execute("DELETE FROM document WHERE id = ? AND user = ?", doc_id, user) ``` +<<<<<<< HEAD #### Mawazo Kuhusu Uhifadhi Matini yaliyotolewa yana nakala sawa: @@ -789,18 +1049,40 @@ Hii inaruhusu: **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 +======= +#### Mawasilisho ya Uhifadhi + +Matini yaliyotolewa yana nakala za maudhui: +Nakala ya asili ya PDF inahifadhiwa katika "Garage" +Nakala ya matini iliyotolewa kwa kila ukurasa pia inahifadhiwa katika "Garage" + +Hii inaruhusu: +**Kiolesura cha kawaida cha "chunker"**: "Chunker" daima hupata kwa kitambulisho +**Uanzishaji upya/jaribio**: Inaweza kuanzisha tena katika hatua ya "chunker" bila kuharibu tena PDF +**Urekebishaji**: Matini iliyotolewa inaweza kuchunguzwa +**Tofauti ya majukumu**: Huduma ya kutolea matini kutoka PDF na "chunker" ni huduma tofauti +>>>>>>> 82edf2d (New md files from RunPod) 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 +<<<<<<< HEAD #### 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 +======= +#### Matokeo ya Kutoa Matini kutoka PDF + +Kifaa cha kutoa matini kutoka PDF, baada ya kuchakata hati: + +1. Hupokea PDF kutoka kwa "librarian" hadi faili ya muda +2. Hutoa matini ukurasa kwa ukurasa +>>>>>>> 82edf2d (New md files from RunPod) 3. Kwa kila ukurasa, huhifadhi matini iliyotolewa kama hati ndogo kupitia "librarian" 4. Hutuma kitambulisho cha hati ndogo kwa folyo ya "chunker" @@ -833,15 +1115,26 @@ async def extract_pdf(doc_id: str, librarian_client, output_queue): await output_queue.send(child_id) ``` +<<<<<<< HEAD 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 +======= +Kifaa cha "chunker" hupokea kitambulisho hivi vya watoto na huviweka sawa na +jinsi lingeweza kuchakata hati ya maandishi iliyopakiwa na mtumiaji. + +### Masasisho ya Mteja +>>>>>>> 82edf2d (New md files from RunPod) #### SDK ya Python SDK ya Python (`trustgraph-base/trustgraph/api/library.py`) inapaswa kushughulikia +<<<<<<< HEAD vipakio vilivyogawanywa kwa njia ya moja kwa moja. Muundo wa umma haubadiliki: +======= +vipakio vilivyogawanywa kwa njia ambayo haionyeshi. Muundo wa umma haubadiliki: +>>>>>>> 82edf2d (New md files from RunPod) ```python # Existing interface - no change for users @@ -914,8 +1207,13 @@ tg-add-library-document --file large-report.pdf --title "Large Report" --progres **Vifaa vya zamani vimetoolewa:** +<<<<<<< HEAD `tg-load-pdf` - imepitwa na wakati, tumia `tg-add-library-document` `tg-load-text` - imepitwa na wakati, tumia `tg-add-library-document` +======= +`tg-load-pdf` - yamefutwa, tumia `tg-add-library-document` +`tg-load-text` - yamefutwa, tumia `tg-add-library-document` +>>>>>>> 82edf2d (New md files from RunPod) **Amri za utawala/uchunguzi** (hiari, kipaumbele cha chini): @@ -935,7 +1233,11 @@ Vipimo vya OpenAPI (`specs/api/paths/librarian.yaml`) vinahitaji mabadiliko kwa: **Utendaji mpya:** +<<<<<<< HEAD `begin-upload` - Anzisha kipindi cha kupakia kwa sehemu +======= +`begin-upload` - Anzisha kipindi cha kupakia sehemu +>>>>>>> 82edf2d (New md files from RunPod) `upload-chunk` - Pakia sehemu moja `complete-upload` - Kamilisha kupakia `abort-upload` - Ghairi kupakia @@ -949,7 +1251,11 @@ Vipimo vya OpenAPI (`specs/api/paths/librarian.yaml`) vinahitaji mabadiliko kwa: `list-documents` - Ongeza parameter `include-children` +<<<<<<< HEAD **Muundo mpya:** +======= +**Vipimo vipya:** +>>>>>>> 82edf2d (New md files from RunPod) `ChunkedUploadBeginRequest` `ChunkedUploadBeginResponse` @@ -961,7 +1267,11 @@ Vipimo vya OpenAPI (`specs/api/paths/librarian.yaml`) vinahitaji mabadiliko kwa: **Mabadiliko ya vipimo vya WebSocket** (`specs/websocket/`): Nakala utendaji wa REST kwa wateja wa WebSocket, na kuwezesha +<<<<<<< HEAD maendeleo ya muda halisi wakati wa kupakia. +======= +maendeleo ya wakati halisi wakati wa kupakia. +>>>>>>> 82edf2d (New md files from RunPod) #### Mambo ya Kuzingatia ya Uzoefu wa Mtumiaji @@ -973,12 +1283,21 @@ Muda uliokadiri wa kupakia Uwezo wa kusitisha/kuendeleza **Kupona kwa makosa:** +<<<<<<< HEAD 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 +======= +Chaguo la "endelea kupakia" kwa kupakia ambacho kimekatika +Orodha ya kupakia ambayo hayaja kamili wakati wa kuunganisha tena + +**Usimamizi wa faili kubwa:** +Uchunguzi wa ukubwa wa faili kwenye upande wa mteja +Kupakia kiotomatiki kwa sehemu kwa faili kubwa +>>>>>>> 82edf2d (New md files from RunPod) 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/docs/tech-specs/large-document-loading.tr.md b/docs/tech-specs/large-document-loading.tr.md new file mode 100644 index 00000000..b5916652 --- /dev/null +++ b/docs/tech-specs/large-document-loading.tr.md @@ -0,0 +1,984 @@ +# Büyük Belge Yükleme Teknik Özellikleri + +## Genel Bakış + +Bu teknik özellik, TrustGraph'e büyük belgelerin yüklenmesi sırasında ortaya çıkan ölçeklenebilirlik ve kullanıcı deneyimi sorunlarını ele almaktadır. Mevcut mimari, belge yüklemeyi tek bir atomik işlem olarak ele almaktadır, bu da boru hattının çeşitli noktalarında bellek yüklenmesine neden olmakta ve kullanıcılara herhangi bir geri bildirim veya kurtarma seçeneği sunmamaktadır. + +Bu uygulama, aşağıdaki kullanım senaryolarına yöneliktir: + + +1. **Büyük PDF İşleme**: Belleği tüketmeden yüzlerce megabayt boyutunda PDF dosyalarını yükleyin ve işleyin. + +2. **Devam Eden Yüklemeler**: Kesintiye uğrayan yüklemelerin, baştan başlamak yerine, durdurulduğu yerden devam etmesini sağlayın. + +3. **İlerleme Geri Bildirimi**: Kullanıcılara yükleme ve işleme sürecinin gerçek zamanlı görünürlüğünü sağlayın. + +4. **Bellek Verimli İşleme**: Belgeleri, tüm dosyaları bellekte tutmadan, akış halinde işleyin. + + + ## Hedefler + + +**Artımlı Yükleme**: REST ve WebSocket üzerinden parçalı belge yüklemeyi destekleyin. +**Devam Eden Aktarımlar**: Kesintiye uğrayan yüklemelerden kurtarmayı sağlayın. +**İlerleme Görünürlüğü**: İstemcilere yükleme/işleme sürecinin ilerleme durumunu geri bildirin. +**Bellek Verimliliği**: Boru hattının tamamında tam belge tamponlamayı ortadan kaldırın. +**Geriye Dönük Uyumluluk**: Mevcut, küçük belge iş akışlarının değişmeden devam etmesini sağlayın. +**Akış İşleme**: PDF kod çözme ve metin parçalama işlemleri, akışlar üzerinde gerçekleştirilir. + +## Arka Plan + + +### Mevcut Mimari + +Belge gönderme işlemi, aşağıdaki yolu izlemektedir: + +1. **İstemci**, belgeyi REST (`POST /api/v1/librarian`) veya WebSocket üzerinden gönderir. +2. **API Ağ Geçidi**, base64 ile kodlanmış belge içeriği içeren eksiksiz isteği alır. +3. **LibrarianRequestor**, isteği Pulsar mesajına dönüştürür. +4. **Librarian Hizmeti**, mesajı alır, belgeyi belleğe kodlar. +5. **BlobStore**, belgeyi Garage/S3'e yükler. +6. **Cassandra**, nesne referansı ile birlikte meta verileri depolar. +7. İşleme için: belge S3'ten alınır, kodlanır, parçalara ayrılır - hepsi bellekte. + +Önemli dosyalar: +REST/WebSocket girişi: `trustgraph-flow/trustgraph/gateway/service.py` +Librarian çekirdeği: `trustgraph-flow/trustgraph/librarian/librarian.py` +Blob depolama: `trustgraph-flow/trustgraph/librarian/blob_store.py` +Cassandra tabloları: `trustgraph-flow/trustgraph/tables/library.py` +API şeması: `trustgraph-base/trustgraph/schema/services/library.py` + +### Mevcut Sınırlamalar + +Mevcut tasarımın, çeşitli birikimli bellek ve kullanıcı deneyimi sorunları bulunmaktadır: + +1. **Atomik Yükleme İşlemi**: Tüm belge, + tek bir istekte iletilmelidir. Büyük belgeler, bağlantı başarısız olursa geri alma mekanizması olmadan, ilerleme göstergesi olmayan uzun süreli istekler gerektirir. + + +2. **API Tasarımı**: Hem REST hem de WebSocket API'leri, + tüm belgeyi tek bir mesajda bekler. Şema (`LibrarianRequest`), tüm base64 ile kodlanmış belgeyi içeren tek bir `content` + alanına sahiptir. + +3. **Kütüphaneci Belleği**: Kütüphaneci hizmeti, belgeyi S3'e yüklemeden önce tüm belgeyi belleğe aktarır. 500MB'lık bir PDF için, bu, işlem belleğinde 500MB+'yi tutmak anlamına gelir. + 500MB+ işlem belleğinde tutmak anlamına gelir. + + +4. **PDF Kod Çözücü Belleği**: İşleme başladığında, PDF kod çözücü, metni çıkarmak için tüm PDF'yi belleğe yükler. PyPDF ve benzeri kütüphaneler genellikle belgenin tamamına erişim gerektirir. + + + +5. **Parçalayıcı Belleği**: Metin parçalayıcı, çıkarılan tamamlanmış metni alır ve parçalar oluştururken bunu bellekte tutar. + + +**Bellek Kullanımı Örneği** (500MB PDF): +Gateway: ~700MB (base64 kodlama ek yükü) +Librarian: ~500MB (çözülmüş baytlar) +PDF Çözücü: ~500MB + çıkarma arabellekleri +Parçalayıcı: çıkarılan metin (değişken, potansiyel olarak 100MB+) + +Tek bir büyük belge için toplam maksimum bellek kullanımı 2GB'ı aşabilir. + +## Teknik Tasarım + +### Tasarım İlkeleri + +1. **API Arayüzü**: Tüm istemci etkileşimi, librarian API'si üzerinden gerçekleşir. İstemciler, + temelindeki S3/Garage depolamaya doğrudan erişemez veya bu depolama hakkında bilgi sahibi değildir. + +2. **S3 Çoklu Parça Yükleme**: Temelde standart S3 çoklu parça yükleme özelliğini kullanın. + Bu, S3 uyumlu sistemlerde (AWS S3, MinIO, Garage, + Ceph, DigitalOcean Spaces, Backblaze B2, vb.) yaygın olarak desteklenir ve taşınabilirliği sağlar. + +3. **Atomik Tamamlama**: S3 çoklu parça yüklemeleri doğası gereği atomiktir; yüklenen + parçalar, `CompleteMultipartUpload` çağrılana kadar görünmez. Geçici + dosyalar veya yeniden adlandırma işlemleri gerekmez. + +4. **Takip Edilebilir Durum**: Yükleme oturumları Cassandra'da takip edilir, bu da + tamamlanmamış yüklemeler hakkında görünürlük sağlar ve devam ettirme özelliğini etkinleştirir. + +### Parçalı Yükleme Akışı + +``` +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) │ +``` + +Müşteri, S3 ile doğrudan etkileşimde bulunmaz. Kütüphaneci, parçalı yükleme API'miz ile S3 çok parçalı işlemler arasında dahili olarak çeviri yapar. + +### Kütüphaneci API İşlemleri +### Kütüphaneci API İşlemleri + +#### `begin-upload` + +Parçalı bir yükleme oturumu başlatın. + +İstek: +```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 +} +``` + +Yanıt: +```json +{ + "upload-id": "upload-abc-123", + "chunk-size": 5242880, + "total-chunks": 100 +} +``` + +Kütüphaneci: +1. Benzersiz bir `upload_id` ve `object_id` oluşturur (blob depolama için UUID). +2. S3'ü `CreateMultipartUpload` ile çağırır, `s3_upload_id`'i alır. +3. Cassandra'da oturum kaydını oluşturur. +4. `upload_id`'ı istemciye döndürür. + +#### `upload-chunk` + +Tek bir bölüm yükleyin. + +İstek: +```json +{ + "operation": "upload-chunk", + "upload-id": "upload-abc-123", + "chunk-index": 0, + "content": "" +} +``` + +Yanıt: +```json +{ + "upload-id": "upload-abc-123", + "chunk-index": 0, + "chunks-received": 1, + "total-chunks": 100, + "bytes-received": 5242880, + "total-bytes": 524288000 +} +``` + +Kütüphaneci: +1. `upload_id` ile oturumu arar. +2. Mülkiyeti doğrular (kullanıcı, oturum oluşturucuyu eşleştirmelidir). +3. Parça verileriyle S3'ü `UploadPart` ile çağırır, `etag` alır. +4. Parça indeksini ve etiketini kullanarak oturum kaydını günceller. +5. İlerleme durumunu istemciye döndürür. + +Başarısız parçalar tekrar denenebilir - aynı `chunk-index`'ı tekrar gönderin. + +#### `complete-upload` + +Yüklemeyi tamamlayın ve belgeyi oluşturun. + +İstek: +```json +{ + "operation": "complete-upload", + "upload-id": "upload-abc-123" +} +``` + +Yanıt: +```json +{ + "document-id": "doc-123", + "object-id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +Kütüphaneci: +1. Oturumu kontrol eder, tüm parçaların alındığından emin olur. +2. Parça etiketleriyle birlikte S3'ü `CompleteMultipartUpload` ile çağırır (S3 parçaları dahili olarak birleştirir - kütüphaneci için bellek maliyeti sıfırdır). + 3. Cassandra'da, meta veriler ve nesne referansı ile birlikte bir belge kaydı oluşturur. +4. Yükleme oturumu kaydını siler. +5. Belge kimliğini müşteriye döndürür. + + +#### `abort-upload` + +Devam eden bir yüklemeyi iptal et. + +İstek: +```json +{ + "operation": "abort-upload", + "upload-id": "upload-abc-123" +} +``` + +Kütüphaneci: +1. Parçaları temizlemek için S3 `AbortMultipartUpload`'ı çağırır. +2. Oturum kaydını Cassandra'dan siler. + +#### `get-upload-status` + +Bir yüklemenin durumunu sorgula (devam ettirme özelliği için). + +İstek: +```json +{ + "operation": "get-upload-status", + "upload-id": "upload-abc-123" +} +``` + +Yanıt: +```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` + +Bir kullanıcı için eksik yüklemeleri listele. + +İstek: +```json +{ + "operation": "list-uploads" +} +``` + +Yanıt: +```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" + } + ] +} +``` + +### Yükleme Oturum Depolama + +Cassandra'da devam eden yüklemeleri takip edin: + +```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); +``` + +**TTL Davranışı:** +Oturumlar, tamamlanmadığı takdirde 24 saat sonra sona erer. +Cassandra TTL'si dolduğunda, oturum kaydı silinir. +Yalnız kalmış S3 parçaları, S3 yaşam döngüsü politikası tarafından temizlenir (kovada yapılandırılır). + +### Hata Yönetimi ve Atomiklik + +**Parça yükleme hatası:** +İstemci, başarısız olan parçayı tekrar dener (aynı `upload_id` ve `chunk-index`). +S3 `UploadPart`, aynı parça numarası için idempotent'tir. +Oturum, hangi parçaların başarılı olduğunu takip eder. + +**İstemci, yükleme sırasında bağlantıyı keser:** +Oturum, Cassandra'da alınan parçalarla birlikte kalır. +İstemci, eksik olanları görmek için `get-upload-status`'ı çağırabilir. +Yalnızca eksik parçaları yükleyerek devam edin ve ardından `complete-upload`'ı çağırın. + +**Tamamlanmış yükleme hatası:** +S3 `CompleteMultipartUpload` atomiktir - ya tamamen başarılı olur ya da başarısız olur. +Başarısızlık durumunda, parçalar kalır ve istemci `complete-upload`'ı tekrar deneyebilir. +Hiçbir kısmi belge görünmez. + +**Oturumun sona ermesi:** +Cassandra TTL, oturum kaydını 24 saat sonra siler. +S3 kova yaşam döngüsü politikası, tamamlanmamış çok parçalı yüklemeleri temizler. +Manuel temizliğe gerek yoktur. + +### S3 Çok Parçalı Atomiklik + +S3 çok parçalı yüklemeler, yerleşik atomiklik sağlar: + +1. **Parçalar görünmezdir:** Yüklenen parçalar, nesne olarak erişilemez. + Bunlar yalnızca tamamlanmamış bir çok parçalı yüklemenin parçaları olarak vardır. + +2. **Atomik tamamlama:** `CompleteMultipartUpload` ya başarılı olur (nesne + atomik olarak görünür) ya da başarısız olur (nesne oluşturulmaz). Herhangi bir kısmi durum yoktur. + +3. **Yeniden adlandırmaya gerek yoktur:** Son nesne anahtarı, + `CreateMultipartUpload` zamanında belirtilir. Parçalar doğrudan bu anahtara birleştirilir. + +4. **Sunucu tarafı birleştirme:** S3, parçaları dahili olarak birleştirir. Kütüphaneci + parçaları asla tekrar okumaz - belgenin boyutundan bağımsız olarak sıfır bellek yükü. + +### BlobStore Uzantıları + +**Dosya:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +Çok parçalı yükleme yöntemleri ekleyin: + +```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() +``` + +### Parça Boyutu Hususları + +**S3 minimumu**: Parça başına 5 MB (son parça hariç) +**S3 maksimumu**: Bir yükleme başına 10.000 parça +**Pratik varsayılan**: 5 MB'lık parçalar + 500 MB'lık bir belge = 100 parça + 5 GB'lık bir belge = 1.000 parça +**İlerleme hassasiyeti**: Daha küçük parçalar = daha hassas ilerleme güncellemeleri +**Ağ verimliliği**: Daha büyük parçalar = daha az sayıda istek + +Parça boyutu, belirli sınırlar içinde (5 MB - 100 MB) istemci tarafından yapılandırılabilir. + +### Belge İşleme: Akışlı Alma + +Yükleme akışı, belgelerin depolamaya verimli bir şekilde aktarılmasını sağlar. İşleme akışı, belgelerin tamamını belleğe yüklemeden, belgelerin çıkarılmasını ve parçalara ayrılmasını sağlar. + + + +#### Tasarım İlkesi: İçerik Değil, Tanımlayıcı + +Şu anda, işleme başlatıldığında, belge içeriği Pulsar mesajları aracılığıyla akar. Bu, tüm belgelerin belleğe yüklenmesine neden olur. Bunun yerine: + + +Pulsar mesajları yalnızca **belge tanımlayıcısını** taşır +İşleyiciler, belge içeriğini doğrudan kütüphaneden alırlar +Alma işlemi, bir **geçici dosyaya akış şeklinde** gerçekleşir +Belgeye özgü ayrıştırma (PDF, metin vb.), bellek arabellekleri yerine dosyalarla çalışır + +Bu, kütüphanenin belge yapısına bağımlı olmamasını sağlar. PDF ayrıştırma, metin +çıkarma ve diğer biçime özgü mantık, ilgili kodlayıcılarda kalır. + +#### İşleme Akışı + +``` +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 │ +``` + +#### Kütüphaneci Akış API'si + +Bir akışlı belge alma işlemi ekleyin: + +**`stream-document`** + +İstek: +```json +{ + "operation": "stream-document", + "document-id": "doc-123" +} +``` + +Yanıt: Akışlı ikili veri parçaları (tek bir yanıt değil). + +REST API için, bu, `Transfer-Encoding: chunked` ile bir akışlı yanıt döndürür. + +İç hizmetler arası iletişimler (işlemci ile kütüphaneci), şu şekilde olabilir: +İmza yoluyla doğrudan S3 akışı (eğer iç ağ izin veriyorsa) +Hizmet protokolü üzerinden parçalı yanıtlar +Özel bir akış uç noktası + +Temel gereksinim: Veri, kütüphaneci tarafından asla tamamen tamponlanmadan, parçalar halinde akmalıdır. + +#### PDF Kod Çözücü Değişiklikleri + +**Mevcut uygulama** (bellek yoğun): + +```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 +``` + +**Yeni uygulama** (geçici dosya, kademeli): + +```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 +``` + +Bellek profili: +Geçici dosya diskte: PDF'nin boyutu (disk ucuzdur) +Bellekte: bir seferde bir sayfanın metni +Maksimum bellek: sınırlı, belge boyutundan bağımsız + +#### Metin Belgesi Kod Çözücü Değişiklikleri + +Düz metin belgeleri için, daha da basit - geçici dosyaya ihtiyaç yok: + +```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 +``` + +Metin belgeleri, geçici bir dosyaya ihtiyaç duymadan doğrudan akış halinde iletilebilir, çünkü bunlar +doğrusal bir yapıya sahiptir. + +#### Akış Tabanlı Parçalama Entegrasyonu + +Parçalayıcı, metin (sayfalar veya paragraflar)den oluşan bir yineleyici alır ve +parçaları kademeli olarak üretir: + +```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 +``` + +#### Uçtan Uca İşlem Hattı + +```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) +``` + +Hiçbir noktada, tam belge veya tam çıkarılmış metin bellekte tutulmaz. + +#### Geçici Dosya Hususları + +**Konum:** Sistem geçici dizinini kullanın (`/tmp` veya eşdeğeri). +Sanallaştırılmış dağıtımlar için, geçici dizinin yeterli alana sahip olduğundan ve mümkünse hızlı depolama üzerinde olduğundan emin olun. + + +**Temizleme:** Temizlemenin, istisnalar olsa bile, sağlanması için bağlam yöneticileri (`with tempfile...`) kullanın. + + +**Eşzamanlı işleme:** Her işleme görevi kendi geçici dosyasına sahiptir. +Paralel belge işleme arasında herhangi bir çakışma olmaz. + +**Disk alanı:** Geçici dosyalar, kısa ömürlüdür (işlem süresi boyunca). +500MB'lık bir PDF için, işleme sırasında 500MB geçici alana ihtiyaç vardır. Disk alanı sınırlıysa, boyut sınırı yükleme sırasında uygulanabilir. + + +### Birlikte Çalışan İşlem Arayüzü: Alt Belgeler + +PDF çıkarma ve metin belge işleme, aynı +aşağı akış hattına (parçalayıcı → gömüler → depolama) beslenmelidir. Bunu, tutarlı bir "ID'ye göre alma" arayüzüyle sağlamak için, çıkarılan metin blokları, "librarian"a alt belgeler olarak geri kaydedilir. + + + +#### Alt Belgelerle İşlem Akışı + +``` +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] +``` + +Parçalayıcı, tek bir standart arayüze sahiptir: +Bir belge kimliğini alın (Pulsar aracılığıyla) +Kütüphaneden içeriği akış olarak alın +Bunu parçalara ayırın + +Bu, kimliğin neye atıfta bulunduğunu bilmez veya umursamaz: +Kullanıcı tarafından yüklenen bir metin belgesi +Bir PDF sayfasından çıkarılan bir metin bloğu +Herhangi bir gelecekteki belge türü + +#### Alt Belge Meta Verileri + +Belge şemasını, ana/alt ilişkilerini izlemek için genişletin: + +```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); +``` + +**Belge türleri:** + +| `document_type` | Açıklama | +|-----------------|-------------| +| `source` | Kullanıcı tarafından yüklenen belge (PDF, metin, vb.) | +| `extracted` | Kaynak bir belgeden türetilmiş (örneğin, PDF sayfa metni) | + +**Meta veri alanları:** + +| Alan | Kaynak Belge | Çıkarılan Alt Belge | +|-------|-----------------|-----------------| +| `id` | kullanıcı tarafından sağlanan veya oluşturulan | oluşturulan (örneğin, `{parent-id}-page-{n}`) | +| `parent_id` | `NULL` | ana belge kimliği | +| `document_type` | `source` | `extracted` | +| `kind` | `application/pdf`, vb. | `text/plain` | +| `title` | kullanıcı tarafından sağlanan | oluşturulan (örneğin, "Rapor.pdf'nin 3. sayfası") | +| `user` | kimliği doğrulanmış kullanıcı | ana belge ile aynı | + +#### Alt Belgeler için Kütüphaneci API'si + +**Alt belgeler oluşturma** (içerik, pdf-extractor tarafından kullanılır): + +```json +{ + "operation": "add-child-document", + "parent-id": "doc-123", + "document-metadata": { + "id": "doc-123-page-1", + "kind": "text/plain", + "title": "Page 1" + }, + "content": "" +} +``` + +Küçük boyutlu, çıkarılmış metinler için (tipik bir sayfa metni < 100KB), tek seferlik yükleme kabul edilebilir. Çok büyük metin çıkarımları için, parçalı yükleme kullanılabilir. + +**Alt belgelerin listelenmesi** (hata ayıklama/yönetim için): + + + +```json +{ + "operation": "list-children", + "parent-id": "doc-123" +} +``` + +Yanıt: +```json +{ + "children": [ + { "id": "doc-123-page-1", "title": "Page 1", "kind": "text/plain" }, + { "id": "doc-123-page-2", "title": "Page 2", "kind": "text/plain" }, + ... + ] +} +``` + +#### Kullanıcı Arayüzü Davranışı + +**`list-documents` varsayılan davranış:** + +```sql +SELECT * FROM document WHERE user = ? AND parent_id IS NULL; +``` + +Yalnızca en üst düzey (kaynak) belgeler, kullanıcının belge listesinde görünür. +Alt belgeler, varsayılan olarak filtrelenir. + +**İsteğe bağlı "çocukları-dahil-et" bayrağı** (yönetici/hata ayıklama için): + +```json +{ + "operation": "list-documents", + "include-children": true +} +``` + +#### Kaskad Sıralı Silme + +Bir üst belge silindiğinde, tüm alt belgelerin de silinmesi gerekir: + +```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) +``` + +#### Depolama Hususları + +Çıkarılan metin blokları, yinelenen içerik oluşturur: +Orijinal PDF, "Garage" (Depo) içinde saklanır. +Her sayfa için çıkarılan metin de "Garage" içinde saklanır. + +Bu denge şunları sağlar: +**Tutarlı bir parçalama arayüzü**: Parçalayıcı her zaman ID'ye göre veri alır. +**Devam ettirme/yeniden deneme**: PDF'i yeniden çıkarmadan, parçalama aşamasında yeniden başlatılabilir. +**Hata ayıklama**: Çıkarılan metin incelenebilir. +**Sorumlulukların ayrılması**: PDF çıkarıcı ve parçalayıcı bağımsız hizmetlerdir. + +200 sayfalık ve sayfa başına ortalama 5KB metin içeren 500MB'lık bir PDF için: +PDF depolama: 500MB +Çıkarılan metin depolama: ~1MB toplam +Ek yük: ihmal edilebilir + +#### PDF Çıkarıcı Çıktısı + +pdf-çıkarıcı, bir belgeyi işledikten sonra: + +1. PDF'i "librarian" (kütüphaneci) üzerinden geçici bir dosyaya aktarır. +2. Metni sayfa sayfa çıkarır. +3. Her sayfa için, çıkarılan metni "librarian" aracılığıyla bir alt belge olarak saklar. +4. Alt belge ID'lerini parçalayıcı kuyruğuna gönderir. +ÇIKTI SÖZLEŞMESİ (tam olarak aşağıdaki formatı takip etmelidir): +```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) +``` + +Parçalayıcı, bu alt kimlikleri alır ve bunları, bir kullanıcının yüklediği bir metin belgesini işlerken olduğu gibi aynı şekilde işler. + +### İstemci Güncellemeleri + +#### Python SDK + + +Python SDK'sı (`trustgraph-base/trustgraph/api/library.py`), parçalı yüklemeleri şeffaf bir şekilde işlemelidir. Kamu arayüzü değişmeden kalır: + + +```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"] +) +``` + +İçeride, SDK belge boyutunu algılar ve stratejiyi değiştirir: + +```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) +``` + +**İlerleme geri bildirimleri** (isteğe bağlı iyileştirme): + +```python +def add_document(self, ..., on_progress=None): + """ + on_progress: Optional callback(bytes_sent, total_bytes) + """ +``` + +Bu, kullanıcı arayüzlerinin temel API'yi değiştirmeden yükleme ilerlemesini görüntülemesini sağlar. + +#### Komut Satırı Araçları + +**`tg-add-library-document`** değişmeden çalışmaya devam ediyor: + +```bash +# Works transparently for any size - SDK handles chunking internally +tg-add-library-document --file large-report.pdf --title "Large Report" +``` + +İsteğe bağlı bir ilerleme durumu göstergesi eklenebilir: + +```bash +tg-add-library-document --file large-report.pdf --title "Large Report" --progress +# Output: +# Uploading: 45% (225MB / 500MB) +``` + +**Eski araçlar kaldırıldı:** + +`tg-load-pdf` - kullanımdan kaldırıldı, `tg-add-library-document`'i kullanın. +`tg-load-text` - kullanımdan kaldırıldı, `tg-add-library-document`'i kullanın. + +**Yönetici/hata ayıklama komutları** (isteğe bağlı, düşük öncelikli): + +```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 +``` + +Bunlar, ayrı araçlar yerine mevcut komuttaki bayraklar olabilir. + +#### API Özellik Güncellemeleri + +OpenAPI spesifikasyonu (`specs/api/paths/librarian.yaml`), aşağıdaki güncellemeleri gerektiriyor: + +**Yeni işlemler:** + +`begin-upload` - Parçalı yükleme oturumunu başlat +`upload-chunk` - Tek bir parçayı yükle +`complete-upload` - Yüklemeyi tamamla +`abort-upload` - Yüklemeyi iptal et +`get-upload-status` - Yükleme ilerlemesini sorgula +`list-uploads` - Kullanıcı için tamamlanmamış yüklemeleri listele +`stream-document` - Akışlı belge alma +`add-child-document` - Çıkarılan metni kaydet (iç) +`list-children` - Alt belgeleri listele (yönetici) + +**Değiştirilen işlemler:** + +`list-documents` - `include-children` parametresini ekle + +**Yeni şemalar:** + +`ChunkedUploadBeginRequest` +`ChunkedUploadBeginResponse` +`ChunkedUploadChunkRequest` +`ChunkedUploadChunkResponse` +`UploadSession` +`UploadProgress` + +**WebSocket spesifikasyonunda yapılan güncellemeler** (`specs/websocket/`): + +WebSocket istemcileri için REST işlemlerini yansıtın, böylece yükleme sırasında gerçek zamanlı +ilerleme güncellemeleri sağlanır. + +#### Kullanıcı Deneyimi Hususları + +API spesifikasyonundaki güncellemeler, ön yüzdeki iyileştirmelere olanak tanır: + +**Yükleme ilerleme arayüzü:** +Yüklenen parçaları gösteren ilerleme çubuğu +Kalan tahmini süre +Duraklatma/devam ettirme özelliği + +**Hata kurtarma:** +Kesintiye uğramış yüklemeler için "Yüklemeyi devam ettir" seçeneği +Yeniden bağlanırken bekleyen yüklemelerin listesi + +**Büyük dosya işleme:** +İstemci tarafında dosya boyutu tespiti +Büyük dosyalar için otomatik parçalı yükleme +Uzun yüklemeler sırasında net geri bildirim + +Bu kullanıcı deneyimi iyileştirmeleri, güncellenmiş API spesifikasyonu tarafından yönlendirilen ön yüz işleme gerektirir. diff --git a/docs/tech-specs/large-document-loading.zh-cn.md b/docs/tech-specs/large-document-loading.zh-cn.md new file mode 100644 index 00000000..5b9806f5 --- /dev/null +++ b/docs/tech-specs/large-document-loading.zh-cn.md @@ -0,0 +1,984 @@ +# 大型文档加载技术规范 + +## 概述 + +本规范解决了在将大型文档加载到 TrustGraph 时出现的可扩展性和用户体验问题。 当前架构将文档上传视为单个原子操作,这会在管道的多个阶段导致内存压力,并且不为用户提供任何反馈或恢复选项。 + +本次实施的目标是以下用例: + + +1. **大型 PDF 处理**: 在不耗尽内存的情况下,上传和处理数百兆字节的 PDF 文件。 + +2. **可恢复的上传**: 允许中断的上传从中断的地方继续,而不是重新开始。 + +3. **进度反馈**: 向用户提供有关上传和处理进度的实时可见性。 + +4. **内存高效处理**: 以流式方式处理文档,而无需将整个文件保存在内存中。 + + + ## 目标 + + +**增量上传**: 支持通过 REST 和 WebSocket 进行分块文档上传。 +**可恢复传输**: 启用从中断的上传中恢复。 +**进度可见性**: 向客户端提供上传/处理进度反馈。 +**内存效率**: 消除整个管道中的完整文档缓冲。 +**向后兼容性**: 现有的小型文档工作流程保持不变。 +**流式处理**: PDF 解码和文本分块操作在流上进行。 + +## 背景 + + +### 当前架构 + +文档提交流程如下: + +1. **客户端** 通过 REST (`POST /api/v1/librarian`) 或 WebSocket 提交文档。 +2. **API 网关** 接收包含 base64 编码的文档内容的完整请求。 +3. **LibrarianRequestor** 将请求转换为 Pulsar 消息。 +4. **Librarian 服务** 接收消息,将文档解码到内存中。 +5. **BlobStore** 将文档上传到 Garage/S3。 +6. **Cassandra** 存储包含对象引用的元数据。 +7. 为了处理:从 S3 中检索文档,解码,分块——所有都在内存中。 + +关键文件: +REST/WebSocket 入口:`trustgraph-flow/trustgraph/gateway/service.py` +Librarian 核心:`trustgraph-flow/trustgraph/librarian/librarian.py` +Blob 存储:`trustgraph-flow/trustgraph/librarian/blob_store.py` +Cassandra 表:`trustgraph-flow/trustgraph/tables/library.py` +API 模式:`trustgraph-base/trustgraph/schema/services/library.py` + +### 当前限制 + +当前设计存在几个相互影响的内存和用户体验问题: + +1. **原子上传操作**: 整个文档必须在一个请求中传输。 + 大型文档需要长时间运行的请求,并且在连接失败时没有进度指示和重试机制。 + + +2. **API 设计**: 无论是 REST 还是 WebSocket API,都期望在单个消息中接收完整的文档。 + 模式 (`LibrarianRequest`) 包含一个 `content` 字段,其中包含整个 base64 编码的文档。 + + +3. **Librarian 内存**: librarian 服务在将文档上传到 S3 之前,将其完全解码到内存中。 + 对于一个 500MB 的 PDF 文件,这意味着需要在进程内存中保留 500MB+。 + + +4. **PDF 解码器内存**: 当处理开始时,PDF 解码器将整个 PDF 文件加载到内存中以提取文本。 + PyPDF 和类似的库通常需要访问整个文档。 + + +5. **分块器内存**: 文本分块器接收完整的提取文本,并在生成块时将其保存在内存中。 + + +**内存影响示例** (500MB PDF): +网关:~700MB (base64 编码开销) +Librarian:~500MB (解码后的字节) +PDF 解码器:~500MB + 提取缓冲区 +分块器:提取的文本 (可变,可能高达 100MB+) + +对于单个大型文档,峰值内存总和可能超过 2GB。 + +## 技术设计 + +### 设计原则 + +1. **API 接口**: 所有客户端交互都通过 librarian API 进行。客户端 + 没有直接访问或了解底层 S3/Garage 存储的权限。 + +2. **S3 多部分上传**: 使用标准的 S3 多部分上传。 + 这在所有兼容 S3 的系统中都得到广泛支持 (AWS S3, MinIO, Garage, + Ceph, DigitalOcean Spaces, Backblaze B2 等),确保可移植性。 + +3. **原子完成**: S3 多部分上传本质上是原子的 - 上传的 + 部分在调用 `CompleteMultipartUpload` 之前是不可见的。不需要临时 + 文件或重命名操作。 + +4. **可跟踪的状态**: 上传会话在 Cassandra 中跟踪,从而 + 提供对未完成上传的可见性,并启用恢复功能。 + +### 分块上传流程 + +``` +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) │ +``` + +客户端从不直接与 S3 交互。 库(librarian)在内部将我们的分块上传 API 转换为 S3 的多部分操作。 + +### Librarian API 操作 +### 图书管理员API操作 + +#### `begin-upload` + +初始化一个分块上传会话。 + +请求: +```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 +} +``` + +响应: +```json +{ + "upload-id": "upload-abc-123", + "chunk-size": 5242880, + "total-chunks": 100 +} +``` + +馆员: +1. 生成一个唯一的 `upload_id` 和 `object_id` (用于对象存储的 UUID) +2. 调用 S3 `CreateMultipartUpload`,接收 `s3_upload_id` +3. 在 Cassandra 中创建会话记录 +4. 将 `upload_id` 返回给客户端 + +#### `upload-chunk` + +上传单个分块。 + +请求: +```json +{ + "operation": "upload-chunk", + "upload-id": "upload-abc-123", + "chunk-index": 0, + "content": "" +} +``` + +响应: +```json +{ + "upload-id": "upload-abc-123", + "chunk-index": 0, + "chunks-received": 1, + "total-chunks": 100, + "bytes-received": 5242880, + "total-bytes": 524288000 +} +``` + +馆员: +1. 通过 `upload_id` 查找会话。 +2. 验证所有权(用户必须与会话创建者匹配)。 +3. 使用块数据调用 S3 `UploadPart`,接收 `etag`。 +4. 使用块索引和 etag 更新会话记录。 +5. 将进度返回给客户端。 + +失败的块可以重试 - 只需要再次发送相同的 `chunk-index`。 + +#### `complete-upload` + +完成上传并创建文档。 + +请求: +```json +{ + "operation": "complete-upload", + "upload-id": "upload-abc-123" +} +``` + +响应: +```json +{ + "document-id": "doc-123", + "object-id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +馆员: +1. 查找会话,验证是否接收到所有分块。 +2. 使用 part etags 调用 S3 `CompleteMultipartUpload` (S3 内部合并分块,馆员无需消耗内存)。 + 3. 在 Cassandra 中创建文档记录,包含元数据和对象引用。 +4. 删除上传会话记录。 +5. 将文档 ID 返回给客户端。 + + +#### `abort-upload` + +取消正在进行的上传。 + +请求: +```json +{ + "operation": "abort-upload", + "upload-id": "upload-abc-123" +} +``` + +馆员: +1. 调用 S3 `AbortMultipartUpload` 清理部分数据。 +2. 从 Cassandra 中删除会话记录。 + +#### `get-upload-status` + +查询上传状态(用于断点续传功能)。 + +请求: +```json +{ + "operation": "get-upload-status", + "upload-id": "upload-abc-123" +} +``` + +响应: +```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` + +获取用户未完成上传的列表。 + +请求: +```json +{ + "operation": "list-uploads" +} +``` + +响应: +```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" + } + ] +} +``` + +### 上传会话存储 + +在 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); +``` + +**TTL 行为:** +如果未完成,会话将在 24 小时后过期。 +当 Cassandra TTL 过期时,会话记录将被删除。 +孤立的 S3 分片由 S3 生命周期策略清理(在桶上配置)。 + +### 故障处理和原子性 + +**分块上传失败:** +客户端重试失败的分块(使用相同的 `upload_id` 和 `chunk-index`)。 +S3 `UploadPart` 对于相同的分片编号是幂等的。 +会话跟踪哪些分块已成功。 + +**客户端在上传过程中断连接:** +会话仍然存在于 Cassandra 中,记录了已接收的分块。 +客户端可以调用 `get-upload-status` 以查看缺少的内容。 +通过仅上传缺失的分块来恢复,然后调用 `complete-upload`。 + +**完整上传失败:** +S3 `CompleteMultipartUpload` 是原子性的 - 要么完全成功,要么完全失败。 +如果失败,分片仍然存在,客户端可以重试 `complete-upload`。 +永远不会出现部分文档。 + +**会话过期:** +Cassandra TTL 在 24 小时后删除会话记录。 +S3 桶生命周期策略清理不完整的多部分上传。 +不需要手动清理。 + +### S3 多部分原子性 + +S3 多部分上传提供了内置的原子性: + +1. **分片不可见:** 上传的分片不能作为对象访问。 + 它们仅作为不完整的多部分上传的分片存在。 + +2. **原子完成:** `CompleteMultipartUpload` 要么成功(对象 + 以原子方式出现),要么失败(未创建对象)。 没有部分状态。 + +3. **无需重命名:** 最终对象键在 + `CreateMultipartUpload` 时指定。 分片直接合并到该键。 + +4. **服务器端合并:** S3 内部合并分片。 库管理员 + 永远不会读取分片 - 无论文档大小如何,都没有内存开销。 + +### BlobStore 扩展 + +**文件:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +添加多部分上传方法: + +```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() +``` + +### 分块大小的考量 + +**S3 最小值**: 每个分块 5MB (除了最后一个分块) +**S3 最大值**: 每个上传 10,000 个分块 +**实际默认值**: 5MB 分块 + 500MB 文档 = 100 个分块 + 5GB 文档 = 1,000 个分块 +**进度粒度**: 较小的分块 = 更精细的进度更新 +**网络效率**: 较大的分块 = 更少的网络请求 + +分块大小可以在一定范围内由客户端配置 (5MB - 100MB)。 + +### 文档处理:流式检索 + +上传流程旨在高效地将文档存储到存储系统中。处理流程旨在提取和分块文档,而无需将整个文档加载到内存中。 + + + +#### 设计原则:标识符,而非内容 + +目前,当触发处理时,文档内容通过 Pulsar 消息传递。这会将整个文档加载到内存中。 应该这样做: + + +Pulsar 消息仅携带 **文档标识符** +处理程序直接从 librarian 获取文档内容 +获取过程是 **流式传输到临时文件** +文档特定的解析 (PDF、文本等) 使用文件,而不是内存缓冲区 + +这使得 librarian 不依赖于文档结构。 PDF 解析、文本 +提取和其他特定于格式的逻辑保留在各自的解码器中。 + +#### 处理流程 + +``` +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 + +添加一个流式文档检索操作: + +**`stream-document`** + +请求: +```json +{ + "operation": "stream-document", + "document-id": "doc-123" +} +``` + +响应:流式传输的二进制数据块(不是单个响应)。 + +对于 REST API,这会返回一个带有 `Transfer-Encoding: chunked` 的流式响应。 + +对于内部服务之间的调用(处理器到图书管理员),可能如下: +通过预签名 URL 进行直接 S3 流式传输(如果内部网络允许)。 +通过服务协议进行分块响应。 +一个专用的流式传输端点。 + +关键要求:数据以块的形式流动,永远不会完全缓存在图书管理员中。 + +#### PDF 解码器更改 + +**当前实现**(占用大量内存): + +```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 +``` + +**新实现** (临时文件,增量式): + +```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 +``` + +内存配置: +临时文件在磁盘上:大小为 PDF 文件的大小(磁盘很便宜) +内存中:一次加载一页的文本 +峰值内存:受限,与文档大小无关 + +#### 文本文档解码器更改 + +对于纯文本文档,更加简单 - 不需要临时文件: + +```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 +``` + +文本文件可以直接流式传输,无需临时文件,因为它们的结构是线性的。 + + +#### 流式分块集成 + +分块器接收文本的迭代器(页面或段落),并逐步生成块: + + +```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 +``` + +#### 端到端处理流程 + +```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) +``` + +在任何时候,完整的文档或完整的提取文本都不会保存在内存中。 + +#### 临时文件注意事项 + +**位置:** 使用系统临时目录(`/tmp` 或等效目录)。对于 +容器化部署,请确保临时目录有足够的空间,并且位于快速存储上(如果可能,不要使用网络挂载)。 + + +**清理:** 使用上下文管理器(`with tempfile...`)以确保即使在出现异常时也能进行清理。 + + +**并发处理:** 每个处理任务都有自己的临时文件。 +并行文档处理之间不会发生冲突。 + +**磁盘空间:** 临时文件是短暂存在的(处理过程中的持续时间)。 +对于一个 500MB 的 PDF 文件,在处理过程中需要 500MB 的临时空间。如果磁盘空间受限,可以在上传时强制执行大小限制。 + + +### 统一处理接口:子文档 + +PDF 提取和文本文档处理需要输入到相同的下游流程(分块 → 嵌入 → 存储)。为了实现这一点,并使用一致的“按 ID 检索”接口,提取的文本块被存储回 librarian,作为子文档。 + + + + +#### 使用子文档的处理流程 + +``` +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] +``` + +分块器具有一个统一的接口: +接收文档 ID(通过 Pulsar) +从 Librarian 流式传输内容 +将其分块 + +它不知道也不关心该 ID 指的是: +用户上传的文本文档 +从 PDF 页面提取的文本块 +任何未来的文档类型 + +#### 子文档元数据 + +扩展文档模式以跟踪父/子关系: + +```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); +``` + +**文档类型:** + +| `document_type` | 描述 | +|-----------------|-------------| +| `source` | 用户上传的文档(PDF、文本等) | +| `extracted` | 源自源文档(例如,PDF 页面文本) | + +**元数据字段:** + +| 字段 | 源文档 | 提取的子文档 | +|-------|-----------------|-----------------| +| `id` | 用户提供或生成 | 生成(例如,`{parent-id}-page-{n}`) | +| `parent_id` | `NULL` | 父文档 ID | +| `document_type` | `source` | `extracted` | +| `kind` | `application/pdf`,等等 | `text/plain` | +| `title` | 用户提供 | 生成(例如,“Report.pdf 的第 3 页”) | +| `user` | 经过身份验证的用户 | 与父文档相同 | + +#### 子文档的 Librarian API + +**创建子文档**(内部,由 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": "" +} +``` + +对于较小的提取文本(典型页面文本通常小于 100KB),单次上传是可以接受的。对于非常大的文本提取,可以使用分块上传。 + + + +**列出子文档(用于调试/管理):** + +```json +{ + "operation": "list-children", + "parent-id": "doc-123" +} +``` + +响应: +```json +{ + "children": [ + { "id": "doc-123-page-1", "title": "Page 1", "kind": "text/plain" }, + { "id": "doc-123-page-2", "title": "Page 2", "kind": "text/plain" }, + ... + ] +} +``` + +#### 用户可见的行为 + +**`list-documents` 默认行为:** + +```sql +SELECT * FROM document WHERE user = ? AND parent_id IS NULL; +``` + +只有顶层(源)文档才会出现在用户的文档列表中。 +子文档默认会被过滤掉。 + +**可选的包含子文档标志**(用于管理员/调试): + +```json +{ + "operation": "list-documents", + "include-children": true +} +``` + +#### 级联删除 + +当父级文档被删除时,所有子级必须被删除: + +```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) +``` + +#### 存储注意事项 + +提取的文本块会重复内容: +原始 PDF 文件存储在 Garage 中 +每个页面的提取文本也存储在 Garage 中 + +这种权衡方案可以实现: +**统一的分块接口**: 分块器始终通过 ID 获取数据 +**恢复/重试**: 可以在分块阶段重新启动,而无需重新提取 PDF +**调试**: 可以检查提取的文本 +**职责分离**: PDF 提取器和分块器是独立的服务 + +对于一个 500MB 的 PDF 文件,其中包含 200 页,平均每页 5KB 的文本: +PDF 存储:500MB +提取的文本存储:约 1MB +额外开销:可以忽略不计 + +#### PDF 提取器输出 + +PDF 提取器在处理文档后: + +1. 从 librarian 流式传输 PDF 到临时文件 +2. 逐页提取文本 +3. 对于每一页,将提取的文本作为子文档通过 librarian 存储 +4. 将子文档 ID 发送到分块器队列 + +```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) +``` + +分块器接收这些子 ID,并以与处理用户上传的文本文档完全相同的方式处理它们。 +如何处理用户上传的文本文档。 + +### 客户端更新 + +#### Python SDK + +Python SDK (`trustgraph-base/trustgraph/api/library.py`) 应该能够透明地处理分块上传。公共接口保持不变: +分块上传。公共接口保持不变: + +```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"] +) +``` + +内部,SDK 会检测文档大小并切换策略: + +```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) +``` + +**进度回调** (可选的增强功能): + +```python +def add_document(self, ..., on_progress=None): + """ + on_progress: Optional callback(bytes_sent, total_bytes) + """ +``` + +这允许用户界面显示上传进度,而无需更改基本 API。 + +#### 命令行工具 + +**`tg-add-library-document`** 保持不变: + +```bash +# Works transparently for any size - SDK handles chunking internally +tg-add-library-document --file large-report.pdf --title "Large Report" +``` + +可以添加可选的进度显示: + +```bash +tg-add-library-document --file large-report.pdf --title "Large Report" --progress +# Output: +# Uploading: 45% (225MB / 500MB) +``` + +**已移除的旧工具:** + +`tg-load-pdf` - 已过时,请使用 `tg-add-library-document` +`tg-load-text` - 已过时,请使用 `tg-add-library-document` + +**管理员/调试命令**(可选,优先级较低): + +```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 +``` + +这些可能只是现有命令上的标志,而不是单独的工具。 + +#### API 规范更新 + +OpenAPI 规范 (`specs/api/paths/librarian.yaml`) 需要更新以下内容: + +**新操作:** + +`begin-upload` - 初始化分块上传会话 +`upload-chunk` - 上传单个分块 +`complete-upload` - 完成上传 +`abort-upload` - 取消上传 +`get-upload-status` - 查询上传进度 +`list-uploads` - 列出用户未完成的上传 +`stream-document` - 流式文档检索 +`add-child-document` - 存储提取的文本(内部) +`list-children` - 列出子文档(管理员) + +**修改后的操作:** + +`list-documents` - 添加 `include-children` 参数 + +**新的模式:** + +`ChunkedUploadBeginRequest` +`ChunkedUploadBeginResponse` +`ChunkedUploadChunkRequest` +`ChunkedUploadChunkResponse` +`UploadSession` +`UploadProgress` + +**WebSocket 规范更新** (`specs/websocket/`): + +镜像 REST 操作以供 WebSocket 客户端使用,从而实现上传过程的实时 +进度更新。 + +#### 用户体验注意事项 + +API 规范的更新可以实现前端改进: + +**上传进度 UI:** +显示已上传分块的进度条 +剩余预估时间 +暂停/恢复功能 + +**错误恢复:** +中断的上传可以选择“恢复上传” +重新连接时,显示挂起的上传列表 + +**大型文件处理:** +客户端文件大小检测 +大型文件的自动分块上传 +长时间上传时提供清晰的反馈 + +这些用户体验改进需要前端工作,并由更新后的 API 规范提供指导。 diff --git a/docs/tech-specs/logging-strategy.ar.md b/docs/tech-specs/logging-strategy.ar.md new file mode 100644 index 00000000..a494ec6e --- /dev/null +++ b/docs/tech-specs/logging-strategy.ar.md @@ -0,0 +1,350 @@ +# استراتيجية تسجيل الأحداث في TrustGraph + +## نظرة عامة + +تستخدم TrustGraph الوحدة `logging` المضمنة في Python لجميع عمليات التسجيل، مع تكوين مركزي ودمج اختياري مع Loki لتجميع السجلات. يوفر هذا نهجًا موحدًا ومرنًا لتسجيل الأحداث عبر جميع مكونات النظام. + +## التكوين الافتراضي + +### مستوى التسجيل +**المستوى الافتراضي**: `INFO` +**يمكن تكوينه عبر**: وسيط سطر الأوامر `--log-level` +**الخيارات**: `DEBUG`، `INFO`، `WARNING`، `ERROR`، `CRITICAL` + +### وجهات الإخراج +1. **وحدة التحكم (stdout)**: مفعل دائمًا - يضمن التوافق مع البيئات الحاويات. +2. **Loki**: تجميع سجلات مركزي اختياري (مفعل افتراضيًا، ويمكن تعطيله). + +## وحدة التسجيل المركزية + +تتم إدارة جميع تكوينات التسجيل بواسطة الوحدة `trustgraph.base.logging`، والتي توفر: +`add_logging_args(parser)` - يضيف وسيطات سطر الأوامر القياسية لتسجيل الأحداث. +`setup_logging(args)` - يقوم بتكوين التسجيل من الوسائط التي تم تحليلها. + +يتم استخدام هذا الوحدة بواسطة جميع المكونات من جانب الخادم: +الخدمات القائمة على AsyncProcessor +بوابة API +خادم MCP + +## إرشادات التنفيذ + +### 1. تهيئة المسجل + +يجب على كل وحدة إنشاء مسجل خاص بها باستخدام وحدة `__name__` الخاصة بالوحدة: + +```python +import logging + +logger = logging.getLogger(__name__) +``` + +اسم المسجل يُستخدم تلقائيًا كعلامة في Loki لتصفية البحث. + +### 2. تهيئة الخدمة + +تتلقى جميع الخدمات من جهة الخادم تلقائيًا تكوين التسجيل من خلال الوحدة المركزية: + +```python +from trustgraph.base import add_logging_args, setup_logging +import argparse + +def main(): + parser = argparse.ArgumentParser() + + # Add standard logging arguments (includes Loki configuration) + add_logging_args(parser) + + # Add your service-specific arguments + parser.add_argument('--port', type=int, default=8080) + + args = parser.parse_args() + args = vars(args) + + # Setup logging early in startup + setup_logging(args) + + # Rest of your service initialization + logger = logging.getLogger(__name__) + logger.info("Service starting...") +``` + +### 3. وسيطات سطر الأوامر + +تدعم جميع الخدمات وسيطات التسجيل التالية: + +**مستوى التسجيل:** +```bash +--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL} +``` + +**تكوين لوكي:** +```bash +--loki-enabled # Enable Loki (default) +--no-loki-enabled # Disable Loki +--loki-url URL # Loki push URL (default: http://loki:3100/loki/api/v1/push) +--loki-username USERNAME # Optional authentication +--loki-password PASSWORD # Optional authentication +``` + +**أمثلة:** +```bash +# Default - INFO level, Loki enabled +./my-service + +# Debug mode, console only +./my-service --log-level DEBUG --no-loki-enabled + +# Custom Loki server with auth +./my-service --loki-url http://loki.prod:3100/loki/api/v1/push \ + --loki-username admin --loki-password secret +``` + +### 4. متغيرات البيئة + +تدعم إعدادات Loki استخدام متغيرات البيئة كبدائل: + +```bash +export LOKI_URL=http://loki.prod:3100/loki/api/v1/push +export LOKI_USERNAME=admin +export LOKI_PASSWORD=secret +``` + +تتجاوز وسائط سطر الأوامر قيم المتغيرات البيئية. + +### 5. أفضل الممارسات في التسجيل. + +#### استخدام مستويات التسجيل. +**DEBUG**: معلومات تفصيلية لتشخيص المشكلات (قيم المتغيرات، دخول/خروج الدالة). +**INFO**: رسائل معلومات عامة (بدء الخدمة، تحميل التكوين، مراحل المعالجة). +**WARNING**: رسائل تحذيرية لحالات قد تكون ضارة (ميزات مهملة، أخطاء قابلة للاسترداد). +**ERROR**: رسائل خطأ للمشاكل الخطيرة (عمليات فاشلة، استثناءات). +**CRITICAL**: رسائل حرجة لأعطال النظام التي تتطلب اهتمامًا فوريًا. + +#### تنسيق الرسالة. +```python +# Good - includes context +logger.info(f"Processing document: {doc_id}, size: {doc_size} bytes") +logger.error(f"Failed to connect to database: {error}", exc_info=True) + +# Avoid - lacks context +logger.info("Processing document") +logger.error("Connection failed") +``` + +#### اعتبارات الأداء +```python +# Use lazy formatting for expensive operations +logger.debug("Expensive operation result: %s", expensive_function()) + +# Check log level for very expensive debug operations +if logger.isEnabledFor(logging.DEBUG): + debug_data = compute_expensive_debug_info() + logger.debug(f"Debug data: {debug_data}") +``` + +### 6. التسجيل المنظم باستخدام لوكي + +بالنسبة للبيانات المعقدة، استخدم التسجيل المنظم مع علامات إضافية لـ Loki: + +```python +logger.info("Request processed", extra={ + 'tags': { + 'request_id': request_id, + 'user_id': user_id, + 'status': 'success' + } +}) +``` + +تصبح هذه العلامات تصنيفات قابلة للبحث في Loki، بالإضافة إلى التصنيفات التلقائية: +`severity` - مستوى التسجيل (DEBUG، INFO، WARNING، ERROR، CRITICAL) +`logger` - اسم الوحدة (من `__name__`) + +### 7. تسجيل الاستثناءات + +قم دائمًا بتضمين تتبعات المكدس للاستثناءات: + +```python +try: + process_data() +except Exception as e: + logger.error(f"Failed to process data: {e}", exc_info=True) + raise +``` + +### 8. اعتبارات التسجيل غير المتزامن + +يستخدم نظام التسجيل معالجات غير متزامنة ومخزنة مؤقتًا لـ Loki: +الإخراج إلى وحدة التحكم متزامن (سريع) +يتم تخزين إخراج Loki في قائمة انتظار مع مخزن مؤقت مكون من 500 رسالة +يقوم خيط الخلفية بمعالجة إرسال Loki +لا يوجد حظر لرمز التطبيق الرئيسي + +```python +import asyncio +import logging + +async def async_operation(): + logger = logging.getLogger(__name__) + # Logging is thread-safe and won't block async operations + logger.info(f"Starting async operation in task: {asyncio.current_task().get_name()}") +``` + +## التكامل مع Loki + +### البنية التحتية + +يستخدم نظام التسجيل وظائف `QueueHandler` و `QueueListener` المضمنة في Python للتكامل غير المتزامن مع Loki: + +1. **QueueHandler**: يتم وضع السجلات في قائمة انتظار تحتوي على 500 رسالة (غير متزامنة). +2. **Background Thread**: يرسل QueueListener السجلات إلى Loki بشكل غير متزامن. +3. **Graceful Degradation**: إذا كان Loki غير متاح، يستمر التسجيل في وحدة التحكم. + +### التسميات التلقائية + +تتضمن كل سجل يتم إرساله إلى Loki: +`processor`: هوية المعالج (مثل `config-svc`، `text-completion`، `embeddings`). +`severity`: مستوى السجل (DEBUG، INFO، إلخ). +`logger`: اسم الوحدة (مثل `trustgraph.gateway.service`، `trustgraph.agent.react.service`). + +### التسميات المخصصة + +أضف تسميات مخصصة عبر المعامل `extra`: + +```python +logger.info("User action", extra={ + 'tags': { + 'user_id': user_id, + 'action': 'document_upload', + 'collection': collection_name + } +}) +``` + +### الاستعلام عن السجلات في Loki + +```logql +# All logs from a specific processor (recommended - matches Prometheus metrics) +{processor="config-svc"} +{processor="text-completion"} +{processor="embeddings"} + +# Error logs from a specific processor +{processor="config-svc", severity="ERROR"} + +# Error logs from all processors +{severity="ERROR"} + +# Logs from a specific processor with text filter +{processor="text-completion"} |= "Processing" + +# All logs from API gateway +{processor="api-gateway"} + +# Logs from processors matching pattern +{processor=~".*-completion"} + +# Logs with custom tags +{processor="api-gateway"} | json | user_id="12345" +``` + +### التدهور الأنيق + +إذا كان Loki غير متاح أو لم يتم تثبيت `python-logging-loki`: +يتم طباعة رسالة تحذير على وحدة التحكم. +يستمر تسجيل الأحداث في وحدة التحكم بشكل طبيعي. +يستمر التطبيق في العمل. +لا توجد آلية لإعادة المحاولة لاتصال Loki (الفشل السريع، والتدهور الأنيق). + +## الاختبار + +أثناء الاختبار، ضع في اعتبارك استخدام تكوين تسجيل مختلف: + +```python +# In test setup +import logging + +# Reduce noise during tests +logging.getLogger().setLevel(logging.WARNING) + +# Or disable Loki for tests +setup_logging({'log_level': 'WARNING', 'loki_enabled': False}) +``` + +## التكامل مع نظام المراقبة + +### التنسيق القياسي +جميع السجلات تستخدم تنسيقًا متسقًا: +``` +2025-01-09 10:30:45,123 - trustgraph.gateway.service - INFO - Request processed +``` + +مكونات التنسيق: +الطابع الزمني (بتنسيق ISO مع أجزاء من الثانية) +اسم المسجل (مسار الوحدة) +مستوى التسجيل +الرسالة + +### استعلامات Loki للمراقبة + +استعلامات مراقبة شائعة: + +```logql +# Error rate by processor +rate({severity="ERROR"}[5m]) by (processor) + +# Top error-producing processors +topk(5, count_over_time({severity="ERROR"}[1h]) by (processor)) + +# Recent errors with processor name +{severity="ERROR"} | line_format "{{.processor}}: {{.message}}" + +# All agent processors +{processor=~".*agent.*"} |= "exception" + +# Specific processor error count +count_over_time({processor="config-svc", severity="ERROR"}[1h]) +``` + +## اعتبارات الأمان + +**لا تقم أبدًا بتسجيل معلومات حساسة** (كلمات المرور، مفاتيح API، البيانات الشخصية، الرموز) +**قم بتنظيف مدخلات المستخدم** قبل التسجيل +**استخدم قيمًا محجوزة** للحقول الحساسة: `user_id=****1234` +**مصادقة Loki**: استخدم `--loki-username` و `--loki-password` للنشر الآمن +**نقل آمن**: استخدم HTTPS لعنوان URL الخاص بـ Loki في بيئة الإنتاج: `https://loki.prod:3100/loki/api/v1/push` + +## التبعيات + +يتطلب وحدة التسجيل المركزية ما يلي: +`python-logging-loki` - لتكامل Loki (اختياري، مع إمكانية التراجع الآمن في حالة عدم وجوده) + +تم تضمينها بالفعل في `trustgraph-base/pyproject.toml` و `requirements.txt`. + +## مسار الترحيل + +بالنسبة للكود الحالي: + +1. **الخدمات التي تستخدم بالفعل AsyncProcessor**: لا توجد تغييرات مطلوبة، دعم Loki تلقائي +2. **الخدمات التي لا تستخدم AsyncProcessor** (api-gateway, mcp-server): تم تحديثها بالفعل +3. **أدوات سطر الأوامر (CLI)**: خارج نطاق العمل - استمر في استخدام print() أو التسجيل البسيط + +### من print() إلى التسجيل: +```python +# Before +print(f"Processing document {doc_id}") + +# After +logger = logging.getLogger(__name__) +logger.info(f"Processing document {doc_id}") +``` + +## ملخص الإعدادات + +| الوسيط | القيمة الافتراضية | متغير البيئة | الوصف | +|----------|---------|---------------------|-------------| +| `--log-level` | `INFO` | - | مستوى تسجيل وحدة التحكم و Loki | +| `--loki-enabled` | `True` | - | تمكين تسجيل Loki | +| `--loki-url` | `http://loki:3100/loki/api/v1/push` | `LOKI_URL` | نقطة النهاية لدفع البيانات إلى Loki | +| `--loki-username` | `None` | `LOKI_USERNAME` | اسم المستخدم للمصادقة في Loki | +| `--loki-password` | `None` | `LOKI_PASSWORD` | كلمة المرور للمصادقة في Loki | diff --git a/docs/tech-specs/logging-strategy.he.md b/docs/tech-specs/logging-strategy.he.md new file mode 100644 index 00000000..bed091bf --- /dev/null +++ b/docs/tech-specs/logging-strategy.he.md @@ -0,0 +1,350 @@ +# אסטרטגיית רישום (לוגינג) של TrustGraph + +## סקירה כללית + +TrustGraph משתמש במודול `logging` המובנה של Python עבור כל פעולות הרישום, עם תצורה מרכזית ושילוב אופציונלי של Loki לאיסוף יומנים. זה מספק גישה סטנדרטית וגמישה לרישום בכל רכיבי המערכת. + +## תצורה ברירת מחדל + +### רמת רישום +**רמה ברירת מחדל**: `INFO` +**ניתן להגדרה באמצעות**: ארגומנט שורת הפקודה `--log-level` +**אפשרויות**: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` + +### יעדי פלט +1. **קונסולה (stdout)**: תמיד מופעלת - מבטיחה תאימות עם סביבות מבוססות קונטיינרים +2. **Loki**: איסוף יומנים מרכזי אופציונלי (מופעל כברירת מחדל, ניתן לביטול) + +## מודול רישום מרכזי + +כל תצורת הרישום מנוהלת על ידי המודול `trustgraph.base.logging`, המספק: +`add_logging_args(parser)` - מוסיף ארגומנטי שורת פקודה סטנדרטיים לרישום +`setup_logging(args)` - מגדיר רישום מארגומנטים מנותחים + +מודול זה משמש את כל רכיבי הצד-שרת: +שירותים מבוססי AsyncProcessor +API Gateway +MCP Server + +## הנחיות יישום + +### 1. אתחול רשומות + +כל מודול צריך ליצור את הרשומות שלו באמצעות המודול `__name__`: + +```python +import logging + +logger = logging.getLogger(__name__) +``` + +שם ה-logger משמש באופן אוטומטי כתווית ב-Loki לצורך סינון וחיפוש. + +### 2. אתחול שירות + +כל השירותים בצד השרת מקבלים באופן אוטומטי הגדרות רישום דרך המודול המרכזי: + +```python +from trustgraph.base import add_logging_args, setup_logging +import argparse + +def main(): + parser = argparse.ArgumentParser() + + # Add standard logging arguments (includes Loki configuration) + add_logging_args(parser) + + # Add your service-specific arguments + parser.add_argument('--port', type=int, default=8080) + + args = parser.parse_args() + args = vars(args) + + # Setup logging early in startup + setup_logging(args) + + # Rest of your service initialization + logger = logging.getLogger(__name__) + logger.info("Service starting...") +``` + +### 3. ארגומנטים של שורת הפקודה + +כל השירותים תומכים בארגומנטים אלה של רישום: + +**רמת רישום:** +```bash +--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL} +``` + +**תצורת לוקי:** +```bash +--loki-enabled # Enable Loki (default) +--no-loki-enabled # Disable Loki +--loki-url URL # Loki push URL (default: http://loki:3100/loki/api/v1/push) +--loki-username USERNAME # Optional authentication +--loki-password PASSWORD # Optional authentication +``` + +**דוגמאות:** +```bash +# Default - INFO level, Loki enabled +./my-service + +# Debug mode, console only +./my-service --log-level DEBUG --no-loki-enabled + +# Custom Loki server with auth +./my-service --loki-url http://loki.prod:3100/loki/api/v1/push \ + --loki-username admin --loki-password secret +``` + +### 4. משתני סביבה + +תצורת Loki תומכת באפשרויות ברירת מחדל עבור משתני סביבה: + +```bash +export LOKI_URL=http://loki.prod:3100/loki/api/v1/push +export LOKI_USERNAME=admin +export LOKI_PASSWORD=secret +``` + +ארגומנטים משורת הפקודה גוברים על משתני סביבה. + +### 5. שיטות עבודה מומלצות לרישום נתונים + +#### שימוש ברמות רישום +**DEBUG**: מידע מפורט לצורך אבחון בעיות (ערכי משתנים, כניסה/יציאה מפונקציות) +**INFO**: הודעות מידע כלליות (השירות התחיל, תצורה נטענה, נקודות ציון בעיבוד) +**WARNING**: הודעות אזהרה למצבים שעלולים להיות מזיקים (תכונות מיושנות, שגיאות שניתן להתאושש מהן) +**ERROR**: הודעות שגיאה לבעיות חמורות (פעולות שנכשלו, חריגות) +**CRITICAL**: הודעות קריטיות לכשלים במערכת הדורשים התייחסות מיידית + +#### פורמט ההודעה +```python +# Good - includes context +logger.info(f"Processing document: {doc_id}, size: {doc_size} bytes") +logger.error(f"Failed to connect to database: {error}", exc_info=True) + +# Avoid - lacks context +logger.info("Processing document") +logger.error("Connection failed") +``` + +#### שיקולי ביצועים +```python +# Use lazy formatting for expensive operations +logger.debug("Expensive operation result: %s", expensive_function()) + +# Check log level for very expensive debug operations +if logger.isEnabledFor(logging.DEBUG): + debug_data = compute_expensive_debug_info() + logger.debug(f"Debug data: {debug_data}") +``` + +### 6. רישום מובנה עם לוקי + +עבור נתונים מורכבים, השתמש ברישום מובנה עם תגיות נוספות עבור לוקי: + +```python +logger.info("Request processed", extra={ + 'tags': { + 'request_id': request_id, + 'user_id': user_id, + 'status': 'success' + } +}) +``` + +תגיות אלו הופכות לתויות הניתנות לחיפוש ב-Loki, בנוסף לתויות אוטומטיות: +`severity` - רמת לוג (DEBUG, INFO, WARNING, ERROR, CRITICAL) +`logger` - שם מודול (מתוך `__name__`) + +### 7. רישום חריגות + +תמיד כללו עקבות מחסנית עבור חריגות: + +```python +try: + process_data() +except Exception as e: + logger.error(f"Failed to process data: {e}", exc_info=True) + raise +``` + +### 8. שיקולים בנושא רישום אסינכרוני + +מערכת הרישום משתמשת במטפלים (handlers) בתור לא חוסמים עבור Loki: +פלט לקונסולה הוא סינכרוני (מהיר) +פלט ל-Loki מוצג בתור עם מאגר של 500 הודעות +ניתוב רקע מטפל בהעברת נתונים ל-Loki +אין חסימה של קוד האפליקציה הראשי + +```python +import asyncio +import logging + +async def async_operation(): + logger = logging.getLogger(__name__) + # Logging is thread-safe and won't block async operations + logger.info(f"Starting async operation in task: {asyncio.current_task().get_name()}") +``` + +## אינטגרציה עם לוקי + +### ארכיטקטורה + +מערכת הרישום משתמשת בפונקציות המובנות של Python, `QueueHandler` ו-`QueueListener`, עבור אינטגרציה לא חוסמת עם לוקי: + +1. **QueueHandler**: הודעות רישום מוכנסות לתור של 500 הודעות (לא חוסם). +2. **Background Thread**: QueueListener שולח הודעות רישום ללוקי באופן אסינכרוני. +3. **Graceful Degradation**: אם לוקי אינו זמין, רישום לקונסולה ממשיך. + +### תגיות אוטומטיות + +כל הודעת רישום שנשלחת ללוקי כוללת: +`processor`: זהות המעבד (לדוגמה, `config-svc`, `text-completion`, `embeddings`). +`severity`: רמת הרישום (DEBUG, INFO, וכו'). +`logger`: שם המודול (לדוגמה, `trustgraph.gateway.service`, `trustgraph.agent.react.service`). + +### תגיות מותאמות אישית + +הוספת תגיות מותאמות אישית באמצעות הפרמטר `extra`: + +```python +logger.info("User action", extra={ + 'tags': { + 'user_id': user_id, + 'action': 'document_upload', + 'collection': collection_name + } +}) +``` + +### שאילתת יומנים ב-Loki + +```logql +# All logs from a specific processor (recommended - matches Prometheus metrics) +{processor="config-svc"} +{processor="text-completion"} +{processor="embeddings"} + +# Error logs from a specific processor +{processor="config-svc", severity="ERROR"} + +# Error logs from all processors +{severity="ERROR"} + +# Logs from a specific processor with text filter +{processor="text-completion"} |= "Processing" + +# All logs from API gateway +{processor="api-gateway"} + +# Logs from processors matching pattern +{processor=~".*-completion"} + +# Logs with custom tags +{processor="api-gateway"} | json | user_id="12345" +``` + +### ניוון מבוקר (Graceful Degradation) + +אם Loki אינו זמין או `python-logging-loki` אינו מותקן: +הודעת אזהרה מוצגת לקונסולה +רישום לקונסולה ממשיך כרגיל +היישום ממשיך לפעול +אין לוגיקה של ניסיון חוזר לחיבור ל-Loki (כשל מהיר, ניוון מבוקר) + +## בדיקות (Testing) + +במהלך הבדיקות, שקלו להשתמש בתצורת רישום שונה: + +```python +# In test setup +import logging + +# Reduce noise during tests +logging.getLogger().setLevel(logging.WARNING) + +# Or disable Loki for tests +setup_logging({'log_level': 'WARNING', 'loki_enabled': False}) +``` + +## אינטגרציה של ניטור + +### פורמט סטנדרטי +כל הרישומים משתמשים בפורמט עקבי: +``` +2025-01-09 10:30:45,123 - trustgraph.gateway.service - INFO - Request processed +``` + +מרכיבי פורמט: +חותמת זמן (פורמט ISO עם מילישניות) +שם הלוגר (נתיב מודול) +רמת לוג +הודעה + +### שאילתות לוקי לניטור + +שאילתות ניטור נפוצות: + +```logql +# Error rate by processor +rate({severity="ERROR"}[5m]) by (processor) + +# Top error-producing processors +topk(5, count_over_time({severity="ERROR"}[1h]) by (processor)) + +# Recent errors with processor name +{severity="ERROR"} | line_format "{{.processor}}: {{.message}}" + +# All agent processors +{processor=~".*agent.*"} |= "exception" + +# Specific processor error count +count_over_time({processor="config-svc", severity="ERROR"}[1h]) +``` + +## שיקולי אבטחה + +**לעולם אין לרשום מידע רגיש** (סיסמאות, מפתחות API, נתונים אישיים, טוקנים) +**לנקות קלט משתמש** לפני רישום +**להשתמש במחזירי מקום** עבור שדות רגישים: `user_id=****1234` +**אימות לוקי:** השתמשו ב-`--loki-username` ו-`--loki-password` עבור פריסות מאובטחות +**העברה מאובטחת:** השתמשו ב-HTTPS עבור כתובת ה-URL של לוקי בסביבת ייצור: `https://loki.prod:3100/loki/api/v1/push` + +## תלויות + +מודול הרישום המרכזי דורש: +`python-logging-loki` - עבור אינטגרציה עם לוקי (אופציונלי, ירידה הדרגתית אם חסר) + +כלול כבר ב-`trustgraph-base/pyproject.toml` ו-`requirements.txt`. + +## נתיב מעבר + +עבור קוד קיים: + +1. **שירותים שכבר משתמשים ב-AsyncProcessor:** אין צורך בשינויים, תמיכה בלוקי היא אוטומטית +2. **שירותים שאינם משתמשים ב-AsyncProcessor** (api-gateway, mcp-server): כבר עודכנו +3. **כלי שורת פקודה:** מחוץ לתחום - המשיכו להשתמש ב-print() או ברישום פשוט + +### מ-print() לרישום: +```python +# Before +print(f"Processing document {doc_id}") + +# After +logger = logging.getLogger(__name__) +logger.info(f"Processing document {doc_id}") +``` + +## סיכום הגדרות + +| ארגומנט | ברירת מחדל | משתנה סביבה | תיאור | +|----------|---------|---------------------|-------------| +| `--log-level` | `INFO` | - | רמת רישום עבור קונסולה ו-Loki | +| `--loki-enabled` | `True` | - | הפעלת רישום Loki | +| `--loki-url` | `http://loki:3100/loki/api/v1/push` | `LOKI_URL` | נקודת קצה (endpoint) של Loki לשליחה | +| `--loki-username` | `None` | `LOKI_USERNAME` | שם משתמש לאימות ב-Loki | +| `--loki-password` | `None` | `LOKI_PASSWORD` | סיסמה לאימות ב-Loki | diff --git a/docs/tech-specs/logging-strategy.hi.md b/docs/tech-specs/logging-strategy.hi.md new file mode 100644 index 00000000..1da07be0 --- /dev/null +++ b/docs/tech-specs/logging-strategy.hi.md @@ -0,0 +1,350 @@ +# ट्रस्टग्राफ लॉगिंग रणनीति + +## अवलोकन + +ट्रस्टग्राफ सभी लॉगिंग कार्यों के लिए पायथन के अंतर्निहित `logging` मॉड्यूल का उपयोग करता है, जिसमें केंद्रीकृत कॉन्फ़िगरेशन और लॉग एकत्रीकरण के लिए वैकल्पिक लोकी एकीकरण शामिल है। यह सिस्टम के सभी घटकों में लॉगिंग के लिए एक मानकीकृत, लचीला दृष्टिकोण प्रदान करता है। + +## डिफ़ॉल्ट कॉन्फ़िगरेशन + +### लॉगिंग स्तर +**डिफ़ॉल्ट स्तर**: `INFO` +**कॉन्फ़िगरेशन**: `--log-level` कमांड-लाइन तर्क के माध्यम से +**विकल्प**: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` + +### आउटपुट गंतव्य +1. **कंसोल (stdout)**: हमेशा सक्षम - कंटेनरीकृत वातावरणों के साथ संगतता सुनिश्चित करता है +2. **लोकी**: वैकल्पिक केंद्रीकृत लॉग एकत्रीकरण (डिफ़ॉल्ट रूप से सक्षम, इसे अक्षम किया जा सकता है) + +## केंद्रीकृत लॉगिंग मॉड्यूल + +सभी लॉगिंग कॉन्फ़िगरेशन को `trustgraph.base.logging` मॉड्यूल द्वारा प्रबंधित किया जाता है, जो निम्नलिखित प्रदान करता है: +`add_logging_args(parser)` - मानक लॉगिंग CLI तर्क जोड़ता है +`setup_logging(args)` - पार्स किए गए तर्कों से लॉगिंग को कॉन्फ़िगर करता है + +इस मॉड्यूल का उपयोग सभी सर्वर-साइड घटकों द्वारा किया जाता है: +AsyncProcessor-आधारित सेवाएं +एपीआई गेटवे +एमसीपी सर्वर + +## कार्यान्वयन दिशानिर्देश + +### 1. लॉगर इनिशियलाइज़ेशन + +प्रत्येक मॉड्यूल को मॉड्यूल के `__name__` का उपयोग करके अपना लॉगर बनाना चाहिए: + +```python +import logging + +logger = logging.getLogger(__name__) +``` + +लॉगर का नाम स्वचालित रूप से लोकी में फ़िल्टरिंग और खोज के लिए एक लेबल के रूप में उपयोग किया जाता है। + +### 2. सेवा आरंभिकरण + +सभी सर्वर-साइड सेवाओं को केंद्रीकृत मॉड्यूल के माध्यम से स्वचालित रूप से लॉगिंग कॉन्फ़िगरेशन प्राप्त होता है: + +```python +from trustgraph.base import add_logging_args, setup_logging +import argparse + +def main(): + parser = argparse.ArgumentParser() + + # Add standard logging arguments (includes Loki configuration) + add_logging_args(parser) + + # Add your service-specific arguments + parser.add_argument('--port', type=int, default=8080) + + args = parser.parse_args() + args = vars(args) + + # Setup logging early in startup + setup_logging(args) + + # Rest of your service initialization + logger = logging.getLogger(__name__) + logger.info("Service starting...") +``` + +### 3. कमांड-लाइन तर्क + +सभी सेवाएं इन लॉगिंग तर्कों का समर्थन करती हैं: + +**लॉग स्तर:** +```bash +--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL} +``` + +**लोकी कॉन्फ़िगरेशन:** +```bash +--loki-enabled # Enable Loki (default) +--no-loki-enabled # Disable Loki +--loki-url URL # Loki push URL (default: http://loki:3100/loki/api/v1/push) +--loki-username USERNAME # Optional authentication +--loki-password PASSWORD # Optional authentication +``` + +**उदाहरण:** +```bash +# Default - INFO level, Loki enabled +./my-service + +# Debug mode, console only +./my-service --log-level DEBUG --no-loki-enabled + +# Custom Loki server with auth +./my-service --loki-url http://loki.prod:3100/loki/api/v1/push \ + --loki-username admin --loki-password secret +``` + +### 4. पर्यावरण चर + +लोकी कॉन्फ़िगरेशन पर्यावरण चर के उपयोग का समर्थन करता है: + +```bash +export LOKI_URL=http://loki.prod:3100/loki/api/v1/push +export LOKI_USERNAME=admin +export LOKI_PASSWORD=secret +``` + +कमांड-लाइन तर्क पर्यावरण चर से अधिक महत्वपूर्ण होते हैं। + +### 5. लॉगिंग के सर्वोत्तम अभ्यास + +#### लॉग स्तरों का उपयोग +**DEBUG**: समस्याओं के निदान के लिए विस्तृत जानकारी (चर मान, फ़ंक्शन प्रविष्टि/निकास) +**INFO**: सामान्य सूचनात्मक संदेश (सेवा शुरू, कॉन्फ़िगरेशन लोड, प्रसंस्करण मील के पत्थर) +**WARNING**: संभावित रूप से हानिकारक स्थितियों के लिए चेतावनी संदेश (अप्रचलित सुविधाएँ, ठीक होने योग्य त्रुटियाँ) +**ERROR**: गंभीर समस्याओं के लिए त्रुटि संदेश (विफल संचालन, अपवाद) +**CRITICAL**: तत्काल ध्यान देने की आवश्यकता वाले सिस्टम विफलताओं के लिए महत्वपूर्ण संदेश + +#### संदेश प्रारूप +```python +# Good - includes context +logger.info(f"Processing document: {doc_id}, size: {doc_size} bytes") +logger.error(f"Failed to connect to database: {error}", exc_info=True) + +# Avoid - lacks context +logger.info("Processing document") +logger.error("Connection failed") +``` + +#### प्रदर्शन संबंधी विचार +```python +# Use lazy formatting for expensive operations +logger.debug("Expensive operation result: %s", expensive_function()) + +# Check log level for very expensive debug operations +if logger.isEnabledFor(logging.DEBUG): + debug_data = compute_expensive_debug_info() + logger.debug(f"Debug data: {debug_data}") +``` + +### 6. लोकी के साथ संरचित लॉगिंग + +जटिल डेटा के लिए, लोकी के लिए अतिरिक्त टैग के साथ संरचित लॉगिंग का उपयोग करें: + +```python +logger.info("Request processed", extra={ + 'tags': { + 'request_id': request_id, + 'user_id': user_id, + 'status': 'success' + } +}) +``` + +ये टैग, स्वचालित लेबल के अतिरिक्त, लोकी में खोज योग्य लेबल बन जाते हैं: +`severity` - लॉग स्तर (डीबग, जानकारी, चेतावनी, त्रुटि, गंभीर) +`logger` - मॉड्यूल का नाम (`__name__` से) + +### 7. अपवाद लॉगिंग + +हमेशा अपवादों के लिए स्टैक ट्रेस शामिल करें: + +```python +try: + process_data() +except Exception as e: + logger.error(f"Failed to process data: {e}", exc_info=True) + raise +``` + +### 8. एसिंक्रोनस लॉगिंग संबंधी विचार + +लॉगिंग सिस्टम लोकी के लिए गैर-ब्लॉकिंग कतार वाले हैंडलर का उपयोग करता है: +कंसोल आउटपुट सिंक्रोनस (तेज़) है +लोकी आउटपुट 500-संदेश बफर के साथ कतारबद्ध है +बैकग्राउंड थ्रेड लोकी ट्रांसमिशन को संभालता है +मुख्य एप्लिकेशन कोड का कोई अवरोधन नहीं + +```python +import asyncio +import logging + +async def async_operation(): + logger = logging.getLogger(__name__) + # Logging is thread-safe and won't block async operations + logger.info(f"Starting async operation in task: {asyncio.current_task().get_name()}") +``` + +## लोकी एकीकरण + +### वास्तुकला + +लॉगिंग सिस्टम, गैर-अवरुद्ध लोकी एकीकरण के लिए पायथन के अंतर्निहित `QueueHandler` और `QueueListener` का उपयोग करता है: + +1. **क्यू हैंडलर**: लॉग को 500 संदेशों की कतार में रखा जाता है (गैर-अवरुद्ध)। +2. **बैकग्राउंड थ्रेड**: क्यू लिसनर एसिंक्रोनस रूप से लोकी को लॉग भेजता है। +3. **सुगम गिरावट**: यदि लोकी अनुपलब्ध है, तो कंसोल लॉगिंग जारी रहती है। + +### स्वचालित लेबल + +लोकी को भेजे गए प्रत्येक लॉग में शामिल हैं: +`processor`: प्रोसेसर पहचान (उदाहरण के लिए, `config-svc`, `text-completion`, `embeddings`) +`severity`: लॉग स्तर (डीबग, जानकारी, आदि) +`logger`: मॉड्यूल नाम (उदाहरण के लिए, `trustgraph.gateway.service`, `trustgraph.agent.react.service`) + +### कस्टम लेबल + +`extra` पैरामीटर के माध्यम से कस्टम लेबल जोड़ें: + +```python +logger.info("User action", extra={ + 'tags': { + 'user_id': user_id, + 'action': 'document_upload', + 'collection': collection_name + } +}) +``` + +### लोकी में लॉग की खोज + +```logql +# All logs from a specific processor (recommended - matches Prometheus metrics) +{processor="config-svc"} +{processor="text-completion"} +{processor="embeddings"} + +# Error logs from a specific processor +{processor="config-svc", severity="ERROR"} + +# Error logs from all processors +{severity="ERROR"} + +# Logs from a specific processor with text filter +{processor="text-completion"} |= "Processing" + +# All logs from API gateway +{processor="api-gateway"} + +# Logs from processors matching pattern +{processor=~".*-completion"} + +# Logs with custom tags +{processor="api-gateway"} | json | user_id="12345" +``` + +### सुचारू रूप से कार्यक्षमता में कमी + +यदि लोकी अनुपलब्ध है या `python-logging-loki` स्थापित नहीं है: +कंसोल पर चेतावनी संदेश प्रदर्शित किया जाता है +कंसोल लॉगिंग सामान्य रूप से जारी रहता है +एप्लिकेशन चलता रहता है +लोकी कनेक्शन के लिए कोई पुनः प्रयास तर्क नहीं (तुरंत विफल, सुचारू रूप से कार्यक्षमता में कमी) + +## परीक्षण + +परीक्षण के दौरान, एक अलग लॉगिंग कॉन्फ़िगरेशन का उपयोग करने पर विचार करें: + +```python +# In test setup +import logging + +# Reduce noise during tests +logging.getLogger().setLevel(logging.WARNING) + +# Or disable Loki for tests +setup_logging({'log_level': 'WARNING', 'loki_enabled': False}) +``` + +## निगरानी एकीकरण + +### मानक प्रारूप +सभी लॉग एक सुसंगत प्रारूप का उपयोग करते हैं: +``` +2025-01-09 10:30:45,123 - trustgraph.gateway.service - INFO - Request processed +``` + +प्रारूप घटक: +टाइमस्टैम्प (मिलीसेकंड के साथ आईएसओ प्रारूप) +लॉगर नाम (मॉड्यूल पथ) +लॉग स्तर +संदेश + +### निगरानी के लिए लोकी प्रश्न + +सामान्य निगरानी प्रश्न: + +```logql +# Error rate by processor +rate({severity="ERROR"}[5m]) by (processor) + +# Top error-producing processors +topk(5, count_over_time({severity="ERROR"}[1h]) by (processor)) + +# Recent errors with processor name +{severity="ERROR"} | line_format "{{.processor}}: {{.message}}" + +# All agent processors +{processor=~".*agent.*"} |= "exception" + +# Specific processor error count +count_over_time({processor="config-svc", severity="ERROR"}[1h]) +``` + +## सुरक्षा संबंधी विचार + +**कभी भी संवेदनशील जानकारी लॉग न करें** (पासवर्ड, एपीआई कुंजियाँ, व्यक्तिगत डेटा, टोकन) +लॉगिंग से पहले **उपयोगकर्ता इनपुट को साफ़ करें** +संवेदनशील फ़ील्ड के लिए **प्लेसहोल्डर का उपयोग करें**: `user_id=****1234` +**लोकी प्रमाणीकरण**: सुरक्षित परिनियोजन के लिए `--loki-username` और `--loki-password` का उपयोग करें +**सुरक्षित परिवहन**: उत्पादन में लोकी यूआरएल के लिए HTTPS का उपयोग करें: `https://loki.prod:3100/loki/api/v1/push` + +## निर्भरताएँ + +केंद्रीकृत लॉगिंग मॉड्यूल को निम्नलिखित की आवश्यकता है: +`python-logging-loki` - लोकी एकीकरण के लिए (वैकल्पिक, यदि अनुपलब्ध हो तो सुचारू गिरावट) + +पहले से ही `trustgraph-base/pyproject.toml` और `requirements.txt` में शामिल है। + +## माइग्रेशन पथ + +मौजूदा कोड के लिए: + +1. **AsyncProcessor का उपयोग कर रहे सेवाएँ**: कोई बदलाव आवश्यक नहीं, लोकी समर्थन स्वचालित है +2. **AsyncProcessor का उपयोग नहीं कर रही सेवाएँ** (api-gateway, mcp-server): पहले से ही अपडेट किया गया है +3. **CLI उपकरण**: दायरे से बाहर - print() या साधारण लॉगिंग का उपयोग जारी रखें + +### print() से लॉगिंग तक: +```python +# Before +print(f"Processing document {doc_id}") + +# After +logger = logging.getLogger(__name__) +logger.info(f"Processing document {doc_id}") +``` + +## कॉन्फ़िगरेशन सारांश + +| तर्क | डिफ़ॉल्ट | पर्यावरण चर | विवरण | +|----------|---------|---------------------|-------------| +| `--log-level` | `INFO` | - | कंसोल और लोकी लॉग स्तर | +| `--loki-enabled` | `True` | - | लोकी लॉगिंग सक्षम करें | +| `--loki-url` | `http://loki:3100/loki/api/v1/push` | `LOKI_URL` | लोकी पुश एंडपॉइंट | +| `--loki-username` | `None` | `LOKI_USERNAME` | लोकी ऑथ उपयोगकर्ता नाम | +| `--loki-password` | `None` | `LOKI_PASSWORD` | लोकी ऑथ पासवर्ड | diff --git a/docs/tech-specs/logging-strategy.pt.md b/docs/tech-specs/logging-strategy.pt.md new file mode 100644 index 00000000..03ebb516 --- /dev/null +++ b/docs/tech-specs/logging-strategy.pt.md @@ -0,0 +1,350 @@ +# Estratégia de Registro (Logging) do TrustGraph + +## Visão Geral + +O TrustGraph utiliza o módulo `logging` integrado do Python para todas as operações de registro, com configuração centralizada e integração opcional com o Loki para agregação de logs. Isso fornece uma abordagem padronizada e flexível para o registro em todos os componentes do sistema. + +## Configuração Padrão + +### Nível de Registro +**Nível Padrão**: `INFO` +**Configurável via**: argumento de linha de comando `--log-level` +**Opções**: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` + +### Destinos de Saída +1. **Console (stdout)**: Sempre habilitado - garante compatibilidade com ambientes conteinerizados. +2. **Loki**: Agregação de logs centralizada opcional (habilitada por padrão, pode ser desabilitada). + +## Módulo de Registro Centralizado + +Toda a configuração de registro é gerenciada pelo módulo `trustgraph.base.logging`, que fornece: +`add_logging_args(parser)` - Adiciona argumentos de linha de comando padrão para registro. +`setup_logging(args)` - Configura o registro a partir de argumentos analisados. + +Este módulo é usado por todos os componentes do lado do servidor: +Serviços baseados em AsyncProcessor. +API Gateway. +Servidor MCP. + +## Diretrizes de Implementação + +### 1. Inicialização do Logger + +Cada módulo deve criar seu próprio logger usando o módulo `__name__`: + +```python +import logging + +logger = logging.getLogger(__name__) +``` + +O nome do logger é automaticamente usado como um rótulo no Loki para filtragem e pesquisa. + +### 2. Inicialização do Serviço + +Todos os serviços do lado do servidor recebem automaticamente a configuração de registro através do módulo centralizado: + +```python +from trustgraph.base import add_logging_args, setup_logging +import argparse + +def main(): + parser = argparse.ArgumentParser() + + # Add standard logging arguments (includes Loki configuration) + add_logging_args(parser) + + # Add your service-specific arguments + parser.add_argument('--port', type=int, default=8080) + + args = parser.parse_args() + args = vars(args) + + # Setup logging early in startup + setup_logging(args) + + # Rest of your service initialization + logger = logging.getLogger(__name__) + logger.info("Service starting...") +``` + +### 3. Argumentos de Linha de Comando + +Todos os serviços suportam estes argumentos de registro: + +**Nível de Log:** +```bash +--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL} +``` + +**Configuração do Loki:** +```bash +--loki-enabled # Enable Loki (default) +--no-loki-enabled # Disable Loki +--loki-url URL # Loki push URL (default: http://loki:3100/loki/api/v1/push) +--loki-username USERNAME # Optional authentication +--loki-password PASSWORD # Optional authentication +``` + +**Exemplos:** +```bash +# Default - INFO level, Loki enabled +./my-service + +# Debug mode, console only +./my-service --log-level DEBUG --no-loki-enabled + +# Custom Loki server with auth +./my-service --loki-url http://loki.prod:3100/loki/api/v1/push \ + --loki-username admin --loki-password secret +``` + +### 4. Variáveis de Ambiente + +A configuração do Loki suporta a utilização de variáveis de ambiente como valores padrão: + +```bash +export LOKI_URL=http://loki.prod:3100/loki/api/v1/push +export LOKI_USERNAME=admin +export LOKI_PASSWORD=secret +``` + +Os argumentos da linha de comando têm precedência sobre as variáveis de ambiente. + +### 5. Melhores Práticas de Registro (Logging) + +#### Uso dos Níveis de Log +**DEBUG**: Informações detalhadas para diagnosticar problemas (valores de variáveis, entrada/saída de funções) +**INFO**: Mensagens informativas gerais (serviço iniciado, configuração carregada, marcos de processamento) +**WARNING**: Mensagens de aviso para situações potencialmente perigosas (recursos obsoletos, erros recuperáveis) +**ERROR**: Mensagens de erro para problemas graves (operações com falha, exceções) +**CRITICAL**: Mensagens críticas para falhas do sistema que exigem atenção imediata + +#### Formato da Mensagem +```python +# Good - includes context +logger.info(f"Processing document: {doc_id}, size: {doc_size} bytes") +logger.error(f"Failed to connect to database: {error}", exc_info=True) + +# Avoid - lacks context +logger.info("Processing document") +logger.error("Connection failed") +``` + +#### Considerações de Desempenho +```python +# Use lazy formatting for expensive operations +logger.debug("Expensive operation result: %s", expensive_function()) + +# Check log level for very expensive debug operations +if logger.isEnabledFor(logging.DEBUG): + debug_data = compute_expensive_debug_info() + logger.debug(f"Debug data: {debug_data}") +``` + +### 6. Registro Estruturado com Loki + +Para dados complexos, use o registro estruturado com tags adicionais para o Loki: + +```python +logger.info("Request processed", extra={ + 'tags': { + 'request_id': request_id, + 'user_id': user_id, + 'status': 'success' + } +}) +``` + +Essas tags se tornam rótulos pesquisáveis no Loki, além de rótulos automáticos: +`severity` - Nível de log (DEBUG, INFO, WARNING, ERROR, CRITICAL) +`logger` - Nome do módulo (de `__name__`) + +### 7. Registro de Exceções + +Sempre inclua rastreamentos de pilha para exceções: + +```python +try: + process_data() +except Exception as e: + logger.error(f"Failed to process data: {e}", exc_info=True) + raise +``` + +### 8. Considerações sobre o Logging Assíncrono + +O sistema de logging utiliza manipuladores enfileirados não bloqueantes para o Loki: +A saída para o console é síncrona (rápida) +A saída para o Loki é enfileirada com um buffer de 500 mensagens +Uma thread em segundo plano gerencia a transmissão para o Loki +Não há bloqueio do código principal da aplicação + +```python +import asyncio +import logging + +async def async_operation(): + logger = logging.getLogger(__name__) + # Logging is thread-safe and won't block async operations + logger.info(f"Starting async operation in task: {asyncio.current_task().get_name()}") +``` + +## Integração com Loki + +### Arquitetura + +O sistema de registro utiliza os recursos nativos de Python `QueueHandler` e `QueueListener` para a integração não bloqueante com o Loki: + +1. **QueueHandler**: Os registros são colocados em uma fila de 500 mensagens (não bloqueante). +2. **Thread em Segundo Plano**: O QueueListener envia os registros para o Loki de forma assíncrona. +3. **Degradação Graciosa**: Se o Loki estiver indisponível, o registro no console continua. + +### Rótulos Automáticos + +Cada registro enviado para o Loki inclui: +`processor`: Identidade do processador (por exemplo, `config-svc`, `text-completion`, `embeddings`). +`severity`: Nível de registro (DEBUG, INFO, etc.). +`logger`: Nome do módulo (por exemplo, `trustgraph.gateway.service`, `trustgraph.agent.react.service`). + +### Rótulos Personalizados + +Adicione rótulos personalizados através do parâmetro `extra`: + +```python +logger.info("User action", extra={ + 'tags': { + 'user_id': user_id, + 'action': 'document_upload', + 'collection': collection_name + } +}) +``` + +### Consultando Logs no Loki + +```logql +# All logs from a specific processor (recommended - matches Prometheus metrics) +{processor="config-svc"} +{processor="text-completion"} +{processor="embeddings"} + +# Error logs from a specific processor +{processor="config-svc", severity="ERROR"} + +# Error logs from all processors +{severity="ERROR"} + +# Logs from a specific processor with text filter +{processor="text-completion"} |= "Processing" + +# All logs from API gateway +{processor="api-gateway"} + +# Logs from processors matching pattern +{processor=~".*-completion"} + +# Logs with custom tags +{processor="api-gateway"} | json | user_id="12345" +``` + +### Degradação Graciosa + +Se o Loki estiver indisponível ou `python-logging-loki` não estiver instalado: +Mensagem de aviso impressa no console +O registro no console continua normalmente +O aplicativo continua em execução +Sem lógica de repetição para a conexão com o Loki (falha rápida, degrade graciosamente) + +## Testes + +Durante os testes, considere usar uma configuração de registro diferente: + +```python +# In test setup +import logging + +# Reduce noise during tests +logging.getLogger().setLevel(logging.WARNING) + +# Or disable Loki for tests +setup_logging({'log_level': 'WARNING', 'loki_enabled': False}) +``` + +## Integração de Monitoramento + +### Formato Padrão +Todos os logs utilizam um formato consistente: +``` +2025-01-09 10:30:45,123 - trustgraph.gateway.service - INFO - Request processed +``` + +Componentes de formatação: +Timestamp (formato ISO com milissegundos) +Nome do logger (caminho do módulo) +Nível de log +Mensagem + +### Consultas Loki para Monitoramento + +Consultas de monitoramento comuns: + +```logql +# Error rate by processor +rate({severity="ERROR"}[5m]) by (processor) + +# Top error-producing processors +topk(5, count_over_time({severity="ERROR"}[1h]) by (processor)) + +# Recent errors with processor name +{severity="ERROR"} | line_format "{{.processor}}: {{.message}}" + +# All agent processors +{processor=~".*agent.*"} |= "exception" + +# Specific processor error count +count_over_time({processor="config-svc", severity="ERROR"}[1h]) +``` + +## Considerações de Segurança + +**Nunca registre informações sensíveis** (senhas, chaves de API, dados pessoais, tokens) +**Sanitize a entrada do usuário** antes de registrar +**Use espaços reservados** para campos sensíveis: `user_id=****1234` +**Autenticação Loki**: Use `--loki-username` e `--loki-password` para implantações seguras +**Transporte seguro**: Use HTTPS para a URL do Loki em produção: `https://loki.prod:3100/loki/api/v1/push` + +## Dependências + +O módulo de registro centralizado requer: +`python-logging-loki` - Para integração com o Loki (opcional, degradação graciosa se ausente) + +Já incluído em `trustgraph-base/pyproject.toml` e `requirements.txt`. + +## Caminho de Migração + +Para código existente: + +1. **Serviços que já usam AsyncProcessor**: Nenhuma alteração necessária, o suporte ao Loki é automático +2. **Serviços que não usam AsyncProcessor** (api-gateway, mcp-server): Já foram atualizados +3. **Ferramentas de linha de comando (CLI)**: Fora do escopo - continue usando print() ou registro simples + +### De print() para registro: +```python +# Before +print(f"Processing document {doc_id}") + +# After +logger = logging.getLogger(__name__) +logger.info(f"Processing document {doc_id}") +``` + +## Resumo da Configuração + +| Argumento | Padrão | Variável de Ambiente | Descrição | +|----------|---------|---------------------|-------------| +| `--log-level` | `INFO` | - | Nível de log do console e do Loki | +| `--loki-enabled` | `True` | - | Habilitar o registro de log do Loki | +| `--loki-url` | `http://loki:3100/loki/api/v1/push` | `LOKI_URL` | Endpoint de envio do Loki | +| `--loki-username` | `None` | `LOKI_USERNAME` | Nome de usuário de autenticação do Loki | +| `--loki-password` | `None` | `LOKI_PASSWORD` | Senha de autenticação do Loki | diff --git a/docs/tech-specs/logging-strategy.sw.md b/docs/tech-specs/logging-strategy.sw.md new file mode 100644 index 00000000..a28fc375 --- /dev/null +++ b/docs/tech-specs/logging-strategy.sw.md @@ -0,0 +1,350 @@ +# Mbinu ya Uandikaji (Logging) ya TrustGraph + +## Muhtasari + +TrustGraph hutumia moduli iliyojumuishwa ya Python `logging` kwa operesheni zote za uandikaji, pamoja na usanidi uliokatikati na ujumuishaji wa Loki wa hiari kwa ukusanyaji wa matangazo. Hii hutoa mbinu iliyoendeshwa na kikao, inayobadilika kwa uandikaji katika vipengele vyote vya mfumo. + +## Mpangilio Chaguwa + +### Kigezo cha Uandikaji +**Kigezo Chaguwa**: `INFO` +**Inayoweza kusanidiwa kupitia**: hoja ya mstari wa amri `--log-level` +**Chaguo**: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` + +### Vituo vya Matokeo +1. **Kikonsoli (stdout)**: Daima inaanzishwa - huhakikisha utangamano na mazingira yaliyofungwa. +2. **Loki**: Ukusanyaji wa matangazo uliokatikati wa hiari (inaanzishwa kwa chaguwa, inaweza kuzimwa). + +## Moduli ya Uandikaji Iliyokatikati + +Mpangilio wote wa uandikaji unadhibitiwa na moduli `trustgraph.base.logging`, ambayo hutoa: +`add_logging_args(parser)` - Inaongeza hoja za kawaida za CLI za uandikaji. +`setup_logging(args)` - Inasanidi uandikaji kutoka kwa hoja zilizochanganuliwa. + +Moduli hii inatumika na vipengele vyote vya upande wa seva: +Huduma zinazotegemea AsyncProcessor +API Gateway +MCP Server + +## Miongozo ya Utendaji + +### 1. Uanzishaji wa Kichunguzi + +Kila moduli inapaswa kuunda kichunguzi chake mwenyewe kwa kutumia moduli ya `__name__`: + +```python +import logging + +logger = logging.getLogger(__name__) +``` + +Jina la kichujio hutumika kiotomatiki kama lebo katika Loki kwa ajili ya kuchujua na kutafuta. + +### 2. Uanzishaji wa Huduma + +Huduma zote za upande wa seva hupokea kiotomatiki usanidi wa uandishi wa matukio kupitia moduli ya kituo: + +```python +from trustgraph.base import add_logging_args, setup_logging +import argparse + +def main(): + parser = argparse.ArgumentParser() + + # Add standard logging arguments (includes Loki configuration) + add_logging_args(parser) + + # Add your service-specific arguments + parser.add_argument('--port', type=int, default=8080) + + args = parser.parse_args() + args = vars(args) + + # Setup logging early in startup + setup_logging(args) + + # Rest of your service initialization + logger = logging.getLogger(__name__) + logger.info("Service starting...") +``` + +### 3. Vigezo vya Kamba ya Amri + +Huduma zote zinaunga mkono vigezo hivi vya uandishi wa matukio: + +**Kiwango cha Uandishi:** +```bash +--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL} +``` + +**Mipangilio ya Loki:** +```bash +--loki-enabled # Enable Loki (default) +--no-loki-enabled # Disable Loki +--loki-url URL # Loki push URL (default: http://loki:3100/loki/api/v1/push) +--loki-username USERNAME # Optional authentication +--loki-password PASSWORD # Optional authentication +``` + +**Mfano:** +```bash +# Default - INFO level, Loki enabled +./my-service + +# Debug mode, console only +./my-service --log-level DEBUG --no-loki-enabled + +# Custom Loki server with auth +./my-service --loki-url http://loki.prod:3100/loki/api/v1/push \ + --loki-username admin --loki-password secret +``` + +### 4. Vigezo vya Mazingira + +Usanidi wa Loki unaounga mkono utumizi wa vigezo vya mazingira kama chaguo-mbadala: + +```bash +export LOKI_URL=http://loki.prod:3100/loki/api/v1/push +export LOKI_USERNAME=admin +export LOKI_PASSWORD=secret +``` + +Vigezo vya mstari wa amana hupendelewa kuliko vigezo vya mazingira. + +### 5. Mbinu Bora za Uandishi wa Matukio + +#### Matumizi ya Viwango vya Matukio +**DEBUG**: Habari za kina kwa ajili ya utambuzi wa matatizo (maelezo ya vigezo, kuingia/kuacha kazi) +**INFO**: Jumbe za habari za jumla (huduma ilianza, usanidi ulipakuliwa, hatua muhimu za usindikaji) +**WARNING**: Jumbe za onyo kwa hali ambazo zinaweza kuwa hatari (vipengele vilivyomalizwa, makosa yanayoweza kutatuliwa) +**ERROR**: Jumbe za makosa kwa matatizo makubwa (operesheni zilizoendea, ukiukaji) +**CRITICAL**: Jumbe muhimu kwa ajili ya hitilafu za mfumo zinazohitaji uangalifu wa haraka + +#### Muundo wa Jumbe +```python +# Good - includes context +logger.info(f"Processing document: {doc_id}, size: {doc_size} bytes") +logger.error(f"Failed to connect to database: {error}", exc_info=True) + +# Avoid - lacks context +logger.info("Processing document") +logger.error("Connection failed") +``` + +#### Mawazo ya Utendaji +```python +# Use lazy formatting for expensive operations +logger.debug("Expensive operation result: %s", expensive_function()) + +# Check log level for very expensive debug operations +if logger.isEnabledFor(logging.DEBUG): + debug_data = compute_expensive_debug_info() + logger.debug(f"Debug data: {debug_data}") +``` + +### 6. Uandikaji Maelezo Ulio Pamoja na Muundo Ukitumia Loki + +Kwa data ngumu, tumia uandikaji maelezo uliopangwa na lebo za ziada kwa ajili ya Loki: + +```python +logger.info("Request processed", extra={ + 'tags': { + 'request_id': request_id, + 'user_id': user_id, + 'status': 'success' + } +}) +``` + +Alama hizi zinakuwa lebo zinazoweza kutafutwa katika Loki, pamoja na lebo za kiotomatiki: +`severity` - Kiwango cha matukio (DEBUG, INFO, WARNING, ERROR, CRITICAL) +`logger` - Jina la moduli (kutoka `__name__`) + +### 7. Uandikaji wa Matukio ya Aina ya Makosa + +Daima jumuisha maandishi ya mfuatano wa mazingira kwa matukio ya aina ya makosa: + +```python +try: + process_data() +except Exception as e: + logger.error(f"Failed to process data: {e}", exc_info=True) + raise +``` + +### 8. Mambo ya Kuzingatia Kuhusu Uandikaji wa Matukio (Logging) ya Aina ya Async + +Mfumo wa uandikaji wa matukio hutumia vichuja (handlers) visivyozuia (non-blocking) vilivyopangwa kwa Loki: +Matokeo ya konseli ni ya aina moja kwa moja (haraka) +Matokeo ya Loki yanapangwa na buffer ya ujumbe 500 +Mfumo wa nyuma hushughulikia usambazaji wa Loki +Hakuna kuzuiliwa kwa msimbo mkuu wa programu + +```python +import asyncio +import logging + +async def async_operation(): + logger = logging.getLogger(__name__) + # Logging is thread-safe and won't block async operations + logger.info(f"Starting async operation in task: {asyncio.current_task().get_name()}") +``` + +## Uunganisho wa Loki + +### Muundo + +Mfumo wa uandikaji matumizi hutumia `QueueHandler` na `QueueListener` zilizojumuishwa katika Python kwa uunganisho wa Loki usiozuia: + +1. **QueueHandler**: Matukio yanawekwa kwenye folyo ya ujumbe 500 (hayazuilii) +2. **Mfululizo wa Nyuma**: QueueListener hutuma matukio kwa Loki kwa njia isiyo ya moja kwa moja +3. **Upunguzaji wa Kawaida**: Ikiwa Loki haipatikani, uandikaji matukio kwenye konsi unaendelea + +### Laha za Otomatiki + +Kila tukio linalotumwa kwa Loki linajumuisha: +`processor`: Kitambulisho cha kichakata (k.m., `config-svc`, `text-completion`, `embeddings`) +`severity`: Kiwango cha matukio (DEBUG, INFO, n.k.) +`logger`: Jina la moduli (k.m., `trustgraph.gateway.service`, `trustgraph.agent.react.service`) + +### Laha za Msingi + +Ongeza laha za msingi kupitia parameter ya `extra`: + +```python +logger.info("User action", extra={ + 'tags': { + 'user_id': user_id, + 'action': 'document_upload', + 'collection': collection_name + } +}) +``` + +### Kuuliza Kumbukumbu katika Loki + +```logql +# All logs from a specific processor (recommended - matches Prometheus metrics) +{processor="config-svc"} +{processor="text-completion"} +{processor="embeddings"} + +# Error logs from a specific processor +{processor="config-svc", severity="ERROR"} + +# Error logs from all processors +{severity="ERROR"} + +# Logs from a specific processor with text filter +{processor="text-completion"} |= "Processing" + +# All logs from API gateway +{processor="api-gateway"} + +# Logs from processors matching pattern +{processor=~".*-completion"} + +# Logs with custom tags +{processor="api-gateway"} | json | user_id="12345" +``` + +### Upunguzaji wa Athari (Graceful Degradation) + +Ikiwa Loki haipatikani au `python-logging-loki` haijafunguliwa: +Ujumbe wa onyo huonyeshwa kwenye konsoli +Uandikaji kwenye konsoli unaendelea kama kawaida +Programu inaendelea kuendeshwa +Hakuna mfumo wa kujaribu tena muunganisho wa Loki (fainda haraka, punguza athari) + +## Majaribio + +Wakati wa majaribio, fikiria kutumia usanidi tofauti wa uandikaji: + +```python +# In test setup +import logging + +# Reduce noise during tests +logging.getLogger().setLevel(logging.WARNING) + +# Or disable Loki for tests +setup_logging({'log_level': 'WARNING', 'loki_enabled': False}) +``` + +## Ufuatiliaji wa Uunganishaji + +### Muundo wa Kawaida +Matumizi yote ya rekodi hutumia muundo unaofuata sheria: +``` +2025-01-09 10:30:45,123 - trustgraph.gateway.service - INFO - Request processed +``` + +Vipengele vya muundo: +Wakati (muundo wa ISO na milisekundi) +Jina la kisajili (njia ya moduli) +Kiwango cha kisajili +Ujumbe + +### Maswali ya Loki kwa Ufuatiliaji + +Maswali ya kawaida ya ufuatiliaji: + +```logql +# Error rate by processor +rate({severity="ERROR"}[5m]) by (processor) + +# Top error-producing processors +topk(5, count_over_time({severity="ERROR"}[1h]) by (processor)) + +# Recent errors with processor name +{severity="ERROR"} | line_format "{{.processor}}: {{.message}}" + +# All agent processors +{processor=~".*agent.*"} |= "exception" + +# Specific processor error count +count_over_time({processor="config-svc", severity="ERROR"}[1h]) +``` + +## Mambo ya Kuzingatia Kuhusu Usalama + +**Usisahirishe kamwe taarifa nyeti** (manenosi, funguo za API, data ya kibinafsi, alama) +**Safisha pembejeo za mtumiaji** kabla ya kuzisajili +**Tumia nafasi za kubadilika** kwa sehemu nyeti: `user_id=****1234` +**Uthibitishaji wa Loki**: Tumia `--loki-username` na `--loki-password` kwa matumizi salama +**Usafiri salama**: Tumia HTTPS kwa URL ya Loki katika mazingira ya uzalishaji: `https://loki.prod:3100/loki/api/v1/push` + +## Utegemezi + +Moduli ya uandikaji matukio ya kituo inahitaji: +`python-logging-loki` - Kwa ujumuishaji wa Loki (hiari, utendaji wa chini ikiwa haipo) + +Tayari imejumuishwa katika `trustgraph-base/pyproject.toml` na `requirements.txt`. + +## Njia ya Uhamishaji + +Kwa programu zilizopo: + +1. **Huduma ambazo tayari zinatumia AsyncProcessor**: Hakuna mabadiliko yanayohitajika, usaidizi wa Loki ni moja kwa moja +2. **Huduma ambazo hazitumii AsyncProcessor** (api-gateway, mcp-server): Tayari zimefanyiwa mabadiliko +3. **Zana za CLI**: Hayajajumuishwa - endelea kutumia print() au uandikaji matukio rahisi + +### Kutoka print() hadi uandikaji matukio: +```python +# Before +print(f"Processing document {doc_id}") + +# After +logger = logging.getLogger(__name__) +logger.info(f"Processing document {doc_id}") +``` + +## Muhtasari wa Usanidi + +| Jina la hoja | Chaguizi | Kigezo cha mazingira | Maelezo | +|----------|---------|---------------------|-------------| +| `--log-level` | `INFO` | - | Kigezo cha uingishaji wa Loki na kituo cha uendeshaji | +| `--loki-enabled` | `True` | - | Wezesha uingishaji wa Loki | +| `--loki-url` | `http://loki:3100/loki/api/v1/push` | `LOKI_URL` | Kifaa cha utumaji cha Loki | +| `--loki-username` | `None` | `LOKI_USERNAME` | Jina la mtumiaji la uthibitishaji wa Loki | +| `--loki-password` | `None` | `LOKI_PASSWORD` | Nenosiri la uthibitishaji wa Loki | diff --git a/docs/tech-specs/logging-strategy.tr.md b/docs/tech-specs/logging-strategy.tr.md new file mode 100644 index 00000000..a82cb75e --- /dev/null +++ b/docs/tech-specs/logging-strategy.tr.md @@ -0,0 +1,350 @@ +# TrustGraph Kayıt (Log) Stratejisi + +## Genel Bakış + +TrustGraph, tüm kayıt işlemlerinde Python'un yerleşik `logging` modülünü kullanır, merkezi yapılandırma ve kayıt toplama için isteğe bağlı Loki entegrasyonuna sahiptir. Bu, sistemin tüm bileşenleri için standartlaştırılmış, esnek bir kayıt yaklaşımı sağlar. + +## Varsayılan Yapılandırma + +### Kayıt Seviyesi +**Varsayılan Seviye**: `INFO` +**Yapılandırılabilir**: `--log-level` komut satırı argümanı aracılığıyla +**Seçenekler**: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` + +### Çıkış Hedefleri +1. **Konsol (stdout)**: Her zaman etkindir - konteynerleştirilmiş ortamlarla uyumluluğu sağlar. +2. **Loki**: İsteğe bağlı, merkezi kayıt toplama (varsayılan olarak etkindir, devre dışı bırakılabilir). + +## Merkezi Kayıt Modülü + +Tüm kayıt yapılandırması, aşağıdaki özellikleri sağlayan `trustgraph.base.logging` modülü tarafından yönetilir: +`add_logging_args(parser)` - Standart kayıt komut satırı argümanlarını ekler. +`setup_logging(args)` - Ayrıştırılmış argümanlardan kaydı yapılandırır. + +Bu modül, tüm sunucu tarafı bileşenleri tarafından kullanılır: +AsyncProcessor tabanlı hizmetler +API Ağ Geçidi +MCP Sunucusu + +## Uygulama Yönergeleri + +### 1. Kayıt Oluşturucu Başlatma + +Her modül, modülün `__name__`'ını kullanarak kendi kayıt oluşturucusunu oluşturmalıdır: + +```python +import logging + +logger = logging.getLogger(__name__) +``` + +Kayıt günlüğünün adı, Loki'de filtreleme ve arama için otomatik olarak bir etiket olarak kullanılır. + +### 2. Hizmet Başlatma + +Tüm sunucu tarafı hizmetleri, merkezi modül aracılığıyla otomatik olarak günlük yapılandırması alır: + +```python +from trustgraph.base import add_logging_args, setup_logging +import argparse + +def main(): + parser = argparse.ArgumentParser() + + # Add standard logging arguments (includes Loki configuration) + add_logging_args(parser) + + # Add your service-specific arguments + parser.add_argument('--port', type=int, default=8080) + + args = parser.parse_args() + args = vars(args) + + # Setup logging early in startup + setup_logging(args) + + # Rest of your service initialization + logger = logging.getLogger(__name__) + logger.info("Service starting...") +``` + +### 3. Komut Satırı Argümanları + +Tüm hizmetler bu günlük kaydı argümanlarını destekler: + +**Günlük Seviyesi:** +```bash +--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL} +``` + +**Loki Yapılandırması:** +```bash +--loki-enabled # Enable Loki (default) +--no-loki-enabled # Disable Loki +--loki-url URL # Loki push URL (default: http://loki:3100/loki/api/v1/push) +--loki-username USERNAME # Optional authentication +--loki-password PASSWORD # Optional authentication +``` + +**Örnekler:** +```bash +# Default - INFO level, Loki enabled +./my-service + +# Debug mode, console only +./my-service --log-level DEBUG --no-loki-enabled + +# Custom Loki server with auth +./my-service --loki-url http://loki.prod:3100/loki/api/v1/push \ + --loki-username admin --loki-password secret +``` + +### 4. Ortam Değişkenleri + +Loki yapılandırması, ortam değişkeni geri dönüşlerini destekler: + +```bash +export LOKI_URL=http://loki.prod:3100/loki/api/v1/push +export LOKI_USERNAME=admin +export LOKI_PASSWORD=secret +``` + +Komut satırı argümanları, ortam değişkenlerine göre önceliklidir. + +### 5. Kayıt (Logging) İçin En İyi Uygulamalar + +#### Kayıt Seviyelerinin Kullanımı +**DEBUG**: Sorunları teşhis etmek için detaylı bilgiler (değişken değerleri, fonksiyon giriş/çıkış) +**INFO**: Genel bilgilendirici mesajlar (hizmet başlatıldı, yapılandırma yüklendi, işlem aşamaları) +**WARNING**: Potansiyel olarak tehlikeli durumlara yönelik uyarı mesajları (kullanımdan kaldırılmış özellikler, düzeltilebilir hatalar) +**ERROR**: Ciddi sorunlara yönelik hata mesajları (başarısız işlemler, istisnalar) +**CRITICAL**: Acil müdahale gerektiren sistem arızalarına yönelik kritik mesajlar + +#### Mesaj Formatı +```python +# Good - includes context +logger.info(f"Processing document: {doc_id}, size: {doc_size} bytes") +logger.error(f"Failed to connect to database: {error}", exc_info=True) + +# Avoid - lacks context +logger.info("Processing document") +logger.error("Connection failed") +``` + +#### Performans Hususları +```python +# Use lazy formatting for expensive operations +logger.debug("Expensive operation result: %s", expensive_function()) + +# Check log level for very expensive debug operations +if logger.isEnabledFor(logging.DEBUG): + debug_data = compute_expensive_debug_info() + logger.debug(f"Debug data: {debug_data}") +``` + +### 6. Loki ile Yapılandırılmış Günlüğe Kayıt + +Karmaşık veriler için, Loki için ek etiketlerle yapılandırılmış günlüğe kaydı kullanın: + +```python +logger.info("Request processed", extra={ + 'tags': { + 'request_id': request_id, + 'user_id': user_id, + 'status': 'success' + } +}) +``` + +Bu etiketler, otomatik etiketlerin yanı sıra, Loki'de aranabilir etiketler haline gelir: +`severity` - Log seviyesi (DEBUG, INFO, WARNING, ERROR, CRITICAL) +`logger` - Modül adı (`__name__`'den) + +### 7. İstisna Kaydı + +İstisnalar için her zaman yığın izlerini ekleyin: + +```python +try: + process_data() +except Exception as e: + logger.error(f"Failed to process data: {e}", exc_info=True) + raise +``` + +### 8. Asenkron Kayıt (Logging) Hususları + +Kayıt sistemi, Loki için engellemeyen, kuyruklu işleyiciler kullanır: +Konsol çıktısı senkron (hızlıdır) +Loki çıktısı, 500 mesajlık bir arabellekle kuyruğa alınır +Arka plan iş parçacığı, Loki iletimini yönetir +Ana uygulama kodunun engellenmesi olmaz + +```python +import asyncio +import logging + +async def async_operation(): + logger = logging.getLogger(__name__) + # Logging is thread-safe and won't block async operations + logger.info(f"Starting async operation in task: {asyncio.current_task().get_name()}") +``` + +## Loki Entegrasyonu + +### Mimari + +Günlük sistemi, engellemeyen Loki entegrasyonu için Python'un yerleşik `QueueHandler` ve `QueueListener` özelliklerini kullanır: + +1. **QueueHandler**: Günlükler, 500 mesajlık bir kuyruğa (engellemesiz) yerleştirilir. +2. **Arka Plan İş Parçacığı**: QueueListener, günlükleri Loki'ye asenkron olarak gönderir. +3. **Usulüne Uygun Bozulma**: Loki kullanılamıyorsa, konsol günlüğü devam eder. + +### Otomatik Etiketler + +Loki'ye gönderilen her günlük şunları içerir: +`processor`: İşlemci kimliği (örneğin, `config-svc`, `text-completion`, `embeddings`) +`severity`: Günlük seviyesi (DEBUG, INFO, vb.) +`logger`: Modül adı (örneğin, `trustgraph.gateway.service`, `trustgraph.agent.react.service`) + +### Özel Etiketler + +Özel etiketleri `extra` parametresi aracılığıyla ekleyin: + +```python +logger.info("User action", extra={ + 'tags': { + 'user_id': user_id, + 'action': 'document_upload', + 'collection': collection_name + } +}) +``` + +### Loki'de Logları Sorgulama + +```logql +# All logs from a specific processor (recommended - matches Prometheus metrics) +{processor="config-svc"} +{processor="text-completion"} +{processor="embeddings"} + +# Error logs from a specific processor +{processor="config-svc", severity="ERROR"} + +# Error logs from all processors +{severity="ERROR"} + +# Logs from a specific processor with text filter +{processor="text-completion"} |= "Processing" + +# All logs from API gateway +{processor="api-gateway"} + +# Logs from processors matching pattern +{processor=~".*-completion"} + +# Logs with custom tags +{processor="api-gateway"} | json | user_id="12345" +``` + +### Zarif Bozulma + +Eğer Loki kullanılamıyorsa veya `python-logging-loki` yüklü değilse: +Uyarı mesajı konsola yazdırılır +Konsol kaydı normal şekilde devam eder +Uygulama çalışmaya devam eder +Loki bağlantısı için tekrar deneme mantığı yoktur (hızlı bir şekilde başarısız olun, zarif bir şekilde bozulun) + +## Test + +Testler sırasında, farklı bir kayıt yapılandırması kullanmayı düşünün: + +```python +# In test setup +import logging + +# Reduce noise during tests +logging.getLogger().setLevel(logging.WARNING) + +# Or disable Loki for tests +setup_logging({'log_level': 'WARNING', 'loki_enabled': False}) +``` + +## İzleme Entegrasyonu + +### Standart Format +Tüm günlükler tutarlı bir formata sahiptir: +``` +2025-01-09 10:30:45,123 - trustgraph.gateway.service - INFO - Request processed +``` + +Biçim öğeleri: +Zaman damgası (milisaniyelerle birlikte ISO formatı) +Kayıt yöneticisi adı (modül yolu) +Kayıt düzeyi +Mesaj + +### İzleme için Loki Sorguları + +Yaygın izleme sorguları: + +```logql +# Error rate by processor +rate({severity="ERROR"}[5m]) by (processor) + +# Top error-producing processors +topk(5, count_over_time({severity="ERROR"}[1h]) by (processor)) + +# Recent errors with processor name +{severity="ERROR"} | line_format "{{.processor}}: {{.message}}" + +# All agent processors +{processor=~".*agent.*"} |= "exception" + +# Specific processor error count +count_over_time({processor="config-svc", severity="ERROR"}[1h]) +``` + +## Güvenlik Hususları + +**Hassas bilgileri asla kaydetmeyin** (şifreler, API anahtarları, kişisel veriler, token'lar) +**Kayıt işleminden önce kullanıcı girişini temizleyin** +**Hassas alanlar için yer tutucular kullanın**: `user_id=****1234` +**Loki kimlik doğrulaması**: Güvenli dağıtımlar için `--loki-username` ve `--loki-password`'i kullanın +**Güvenli taşıma**: Üretimde Loki URL'si için HTTPS kullanın: `https://loki.prod:3100/loki/api/v1/push` + +## Bağımlılıklar + +Merkezi günlük kaydı modülü şunları gerektirir: +`python-logging-loki` - Loki entegrasyonu için (isteğe bağlı, eksikse sorunsuz bir şekilde çalışır) + +Zaten `trustgraph-base/pyproject.toml` ve `requirements.txt` içinde bulunmaktadır. + +## Geçiş Yolu + +Mevcut kod için: + +1. **AsyncProcessor kullanan hizmetler**: Herhangi bir değişiklik gerekmez, Loki desteği otomatik olarak sağlanır +2. **AsyncProcessor kullanmayan hizmetler** (api-gateway, mcp-server): Zaten güncellenmiştir +3. **CLI araçları**: Kapsam dışındadır - print() veya basit günlük kaydını kullanmaya devam edin + +### print()'ten günlük kaydına: +```python +# Before +print(f"Processing document {doc_id}") + +# After +logger = logging.getLogger(__name__) +logger.info(f"Processing document {doc_id}") +``` + +## Yapılandırma Özeti + +| Argüman | Varsayılan Değer | Ortam Değişkeni | Açıklama | +|----------|---------|---------------------|-------------| +| `--log-level` | `INFO` | - | Konsol ve Loki log seviyesi | +| `--loki-enabled` | `True` | - | Loki log kaydını etkinleştir | +| `--loki-url` | `http://loki:3100/loki/api/v1/push` | `LOKI_URL` | Loki push endpoint'i | +| `--loki-username` | `None` | `LOKI_USERNAME` | Loki kimlik doğrulama kullanıcı adı | +| `--loki-password` | `None` | `LOKI_PASSWORD` | Loki kimlik doğrulama parolası | diff --git a/docs/tech-specs/mcp-tool-arguments.hi.md b/docs/tech-specs/mcp-tool-arguments.hi.md new file mode 100644 index 00000000..fe8f034e --- /dev/null +++ b/docs/tech-specs/mcp-tool-arguments.hi.md @@ -0,0 +1,256 @@ +# एमसीपी टूल आर्गुमेंट्स स्पेसिफिकेशन + +## अवलोकन +**फ़ीचर नाम**: एमसीपी टूल आर्गुमेंट्स सपोर्ट +**लेखक**: क्लाउड कोड असिस्टेंट +**तिथि**: 2025-08-21 +**स्थिति**: अंतिम रूप दिया गया + +### कार्यकारी सारांश + +रीएक्ट एजेंटों को उचित रूप से परिभाषित आर्गुमेंट्स के साथ एमसीपी (मॉडल कॉन्टेक्स्ट प्रोटोकॉल) टूल को उपयोग करने की अनुमति दें, +एमसीपी टूल कॉन्फ़िगरेशन में आर्गुमेंट स्पेसिफिकेशन सपोर्ट जोड़कर, उसी तरह जैसे कि प्रॉम्प्ट टेम्पलेट टूल +वर्तमान में काम करते हैं। + +### समस्या विवरण + + +वर्तमान में, रीएक्ट एजेंट फ्रेमवर्क में एमसीपी टूल अपने +अपेक्षित आर्गुमेंट्स को निर्दिष्ट नहीं कर सकते हैं। `McpToolImpl.get_arguments()` विधि +एक खाली सूची लौटाती है, जिससे एलएलएम को केवल टूल नामों और विवरणों के आधार पर सही पैरामीटर संरचना का अनुमान लगाना पड़ता है। +इससे निम्नलिखित समस्याएं होती हैं: +पैरामीटर अनुमान के कारण अविश्वसनीय टूल उपयोग +गलत आर्गुमेंट्स के कारण टूल विफल होने पर खराब उपयोगकर्ता अनुभव +निष्पादन से पहले टूल पैरामीटर का कोई सत्यापन नहीं +एजेंट प्रॉम्प्ट में गायब पैरामीटर दस्तावेज़ + +### लक्ष्य + +[ ] एमसीपी टूल कॉन्फ़िगरेशन को अपेक्षित आर्गुमेंट्स (नाम, प्रकार, विवरण) निर्दिष्ट करने की अनुमति दें। +[ ] एजेंट मैनेजर को एलएलएम को प्रॉम्प्ट के माध्यम से एमसीपी टूल आर्गुमेंट्स को उजागर करने के लिए अपडेट करें। +[ ] मौजूदा एमसीपी टूल कॉन्फ़िगरेशन के साथ पिछड़े अनुकूलता बनाए रखें। +[ ] प्रॉम्प्ट टेम्पलेट टूल के समान आर्गुमेंट सत्यापन का समर्थन करें। + +### गैर-लक्ष्य +एमसीपी सर्वर से गतिशील आर्गुमेंट खोज (भविष्य में सुधार) +बुनियादी संरचना से परे आर्गुमेंट प्रकार सत्यापन +जटिल आर्गुमेंट स्कीमा (नेस्टेड ऑब्जेक्ट, एरे) + +## पृष्ठभूमि और संदर्भ + +### वर्तमान स्थिति +एमसीपी टूल को रीएक्ट एजेंट सिस्टम में न्यूनतम मेटाडेटा के साथ कॉन्फ़िगर किया जाता है: +```json +{ + "type": "mcp-tool", + "name": "get_bank_balance", + "description": "Get bank account balance", + "mcp-tool": "get_bank_balance" +} +``` + +`McpToolImpl.get_arguments()` विधि `[]` लौटाती है, इसलिए एलएलएम (LLM) अपने प्रॉम्प्ट में किसी भी तर्क मार्गदर्शन को प्राप्त नहीं करते हैं। + +### सीमाएँ + +1. **कोई तर्क विनिर्देश नहीं**: एमसीपी (MCP) उपकरण अपेक्षित मापदंडों को परिभाषित नहीं कर सकते। + पैरामीटर + +2. **एलएलएम पैरामीटर का अनुमान**: एजेंटों को टूल के नामों/वर्णनों से पैरामीटर का अनुमान लगाना होता है। + +3. **गायब प्रॉम्प्ट जानकारी**: एजेंट प्रॉम्प्ट में एमसीपी टूल के लिए किसी भी तर्क विवरण नहीं होते हैं। + + 4. **कोई सत्यापन नहीं**: अमान्य पैरामीटर केवल एमसीपी टूल के निष्पादन समय पर ही पकड़े जाते हैं। + +### संबंधित घटक + **trustgraph-flow/agent/react/service.py**: टूल कॉन्फ़िगरेशन लोडिंग और एजेंटमैनेजर (AgentManager) निर्माण। +**trustgraph-flow/agent/react/tools.py**: McpToolImpl कार्यान्वयन। +**trustgraph-flow/agent/react/agent_manager.py**: टूल तर्कों के साथ प्रॉम्प्ट पीढ़ी। +**trustgraph-cli**: एमसीपी टूल प्रबंधन के लिए सीएलआई (CLI) उपकरण। +**वर्कबेंच (Workbench)**: एजेंट टूल कॉन्फ़िगरेशन के लिए बाहरी यूआई (UI)। + +## आवश्यकताएँ + +### कार्यात्मक आवश्यकताएँ +## आवश्यकताएँ + +### कार्यात्मक आवश्यकताएँ + +1. **MCP टूल कॉन्फ़िगरेशन तर्क**: MCP टूल कॉन्फ़िगरेशन में एक वैकल्पिक `arguments` सरणी होनी चाहिए जिसमें नाम, प्रकार और विवरण फ़ील्ड हों। +2. **तर्क का प्रदर्शन**: `McpToolImpl.get_arguments()` को खाली सूची के बजाय कॉन्फ़िगर किए गए तर्कों को वापस करना चाहिए। +3. **प्रॉम्प्ट एकीकरण**: एजेंट प्रॉम्प्ट में MCP टूल तर्क विवरण शामिल होने चाहिए जब तर्क निर्दिष्ट किए जाते हैं। +4. **पिछला अनुकूलता**: बिना तर्कों वाले मौजूदा MCP टूल कॉन्फ़िगरेशन को भी काम करना जारी रखना चाहिए। +5. **CLI समर्थन**: मौजूदा `tg-invoke-mcp-tool` CLI तर्कों का समर्थन करता है (पहले से लागू)। + +### गैर-कार्यात्मक आवश्यकताएँ +1. **पिछला अनुकूलता**: मौजूदा MCP टूल कॉन्फ़िगरेशन के लिए कोई ब्रेकिंग परिवर्तन नहीं। +2. **प्रदर्शन**: एजेंट प्रॉम्प्ट पीढ़ी पर कोई महत्वपूर्ण प्रदर्शन प्रभाव नहीं। +3. **संगति**: तर्क हैंडलिंग को प्रॉम्प्ट टेम्पलेट टूल पैटर्न से मेल खाना चाहिए। + +### उपयोगकर्ता कहानियां + +1. एक **एजेंट डेवलपर** के रूप में, मैं LLMs को सही मापदंडों के साथ टूल को आमंत्रित करने के लिए MCP टूल तर्कों को कॉन्फ़िगरेशन में निर्दिष्ट करना चाहता हूं। +2. एक **वर्कबेंच उपयोगकर्ता** के रूप में, मैं एजेंटों को सही ढंग से टूल का उपयोग करने के लिए UI में MCP टूल तर्कों को कॉन्फ़िगर करना चाहता हूं। +3. एक **ReACT एजेंट में एक LLM** के रूप में, मैं सही मापदंडों प्रदान करने के लिए प्रॉम्प्ट में टूल तर्क विनिर्देशों को देखना चाहता हूं। + +## डिज़ाइन + +### उच्च-स्तरीय आर्किटेक्चर +MCP टूल कॉन्फ़िगरेशन को प्रॉम्प्ट टेम्पलेट पैटर्न से मिलाने के लिए: +1. MCP टूल कॉन्फ़िगरेशन में एक वैकल्पिक `arguments` सरणी जोड़ें। +2. `McpToolImpl` को कॉन्फ़िगर किए गए तर्कों को स्वीकार करने और वापस करने के लिए संशोधित करें। +3. MCP टूल तर्कों को संभालने के लिए टूल कॉन्फ़िगरेशन लोडिंग को अपडेट करें। +4. सुनिश्चित करें कि एजेंट प्रॉम्प्ट में MCP टूल तर्क जानकारी शामिल है। + +### कॉन्फ़िगरेशन स्कीमा +```json +{ + "type": "mcp-tool", + "name": "get_bank_balance", + "description": "Get bank account balance", + "mcp-tool": "get_bank_balance", + "arguments": [ + { + "name": "account_id", + "type": "string", + "description": "Bank account identifier" + }, + { + "name": "date", + "type": "string", + "description": "Date for balance query (optional, format: YYYY-MM-DD)" + } + ] +} +``` + +### डेटा प्रवाह +1. **कॉन्फ़िगरेशन लोडिंग**: एमसीपी टूल कॉन्फ़िगरेशन और तर्क `on_tools_config()` द्वारा लोड किए जाते हैं। +2. **टूल निर्माण**: तर्कों को पार्स किया जाता है और `McpToolImpl` को कंस्ट्रक्टर के माध्यम से पास किया जाता है। +3. **प्रॉम्प्ट जनरेशन**: `agent_manager.py` एलएलएम प्रॉम्प्ट में शामिल करने के लिए `tool.arguments` को कॉल करता है। +4. **टूल इनवोकेशन**: एलएलएम पैरामीटर प्रदान करता है जिन्हें एमसीपी सेवा को बिना किसी बदलाव के पास किया जाता है। + +### एपीआई परिवर्तन +कोई बाहरी एपीआई परिवर्तन नहीं - यह पूरी तरह से आंतरिक कॉन्फ़िगरेशन और तर्क प्रबंधन है। + +### घटक विवरण + +#### घटक 1: service.py (टूल कॉन्फ़िगरेशन लोडिंग) +**उद्देश्य**: एमसीपी टूल कॉन्फ़िगरेशन को पार्स करें और टूल इंस्टेंस बनाएं। +**आवश्यक परिवर्तन**: एमसीपी टूल के लिए तर्क पार्सिंग जोड़ें (प्रॉम्प्ट टूल के समान)। +**नई कार्यक्षमता**: एमसीपी टूल कॉन्फ़िगरेशन से `arguments` सरणी निकालें और `Argument` ऑब्जेक्ट बनाएं। + +#### घटक 2: tools.py (McpToolImpl) +**उद्देश्य**: एमसीपी टूल कार्यान्वयन रैपर। +**आवश्यक परिवर्तन**: कंस्ट्रक्टर में तर्क स्वीकार करें और उन्हें `get_arguments()` से वापस करें। +**नई कार्यक्षमता**: कॉन्फ़िगर किए गए तर्कों को संग्रहीत करें और प्रदर्शित करें, खाली सूची वापस करने के बजाय। + +#### घटक 3: वर्कबेंच (बाहरी रिपॉजिटरी) +**उद्देश्य**: एजेंट टूल को कॉन्फ़िगर करने के लिए यूआई। +**आवश्यक परिवर्तन**: एमसीपी टूल के लिए तर्क विनिर्देश यूआई जोड़ें। +**नई कार्यक्षमता**: उपयोगकर्ताओं को एमसीपी टूल के लिए तर्क जोड़ने/संपादित करने/हटाने की अनुमति दें। + +#### घटक 4: सीएलआई टूल +**उद्देश्य**: कमांड-लाइन टूल प्रबंधन। +**आवश्यक परिवर्तन**: एमसीपी टूल निर्माण/अपडेट कमांड में तर्क विनिर्देश का समर्थन करें। +**नई कार्यक्षमता**: टूल कॉन्फ़िगरेशन कमांड में तर्क पैरामीटर स्वीकार करें। + +## कार्यान्वयन योजना + +### चरण 1: कोर एजेंट फ्रेमवर्क परिवर्तन +[ ] `McpToolImpl` कंस्ट्रक्टर को `arguments` पैरामीटर स्वीकार करने के लिए अपडेट करें। +[ ] `McpToolImpl.get_arguments()` को संग्रहीत तर्कों को वापस करने के लिए बदलें। +[ ] तर्कों को संभालने के लिए `service.py` एमसीपी टूल कॉन्फ़िगरेशन पार्सिंग को संशोधित करें। +[ ] एमसीपी टूल तर्क हैंडलिंग के लिए यूनिट टेस्ट जोड़ें। +[ ] सत्यापित करें कि एजेंट प्रॉम्प्ट में एमसीपी टूल तर्क शामिल हैं। + +### चरण 2: बाहरी टूल समर्थन +[ ] एमसीपी टूल तर्क विनिर्देश का समर्थन करने के लिए सीएलआई टूल को अपडेट करें। +[ ] उपयोगकर्ताओं के लिए तर्क कॉन्फ़िगरेशन प्रारूप का दस्तावेज़ बनाएं। +[ ] एमसीपी टूल तर्क कॉन्फ़िगरेशन का समर्थन करने के लिए वर्कबेंच यूआई को अपडेट करें। +[ ] उदाहरण और दस्तावेज़ जोड़ें। + +### कोड परिवर्तन सारांश +| फ़ाइल | परिवर्तन का प्रकार | विवरण | +|------|------------|-------------| +| `tools.py` | संशोधित | `tools.py` को तर्क स्वीकार करने और संग्रहीत करने के लिए अपडेट करें | +| `service.py` | संशोधित | एमसीपी टूल कॉन्फ़िगरेशन से तर्कों को पार्स करें (पंक्ति 108-113) | +| `test_react_processor.py` | संशोधित | एमसीपी टूल तर्कों के लिए परीक्षण जोड़ें | +| सीएलआई टूल | संशोधित | कमांड में तर्क विनिर्देश का समर्थन करें | +| वर्कबेंच | संशोधित | एमसीपी टूल तर्क कॉन्फ़िगरेशन के लिए यूआई जोड़ें | + +## परीक्षण रणनीति + +### यूनिट टेस्ट +**एमसीपी टूल तर्क पार्सिंग**: परीक्षण करें कि `service.py` एमसीपी टूल कॉन्फ़िगरेशन से तर्कों को सही ढंग से पार्स करता है। +**McpToolImpl तर्क**: परीक्षण करें कि `get_arguments()` कॉन्फ़िगर किए गए तर्कों को वापस करता है, खाली सूची के बजाय। +**पिछला अनुकूलता**: परीक्षण करें कि तर्कों के बिना एमसीपी टूल काम करना जारी रखते हैं (खाली सूची वापस करें)। +**एजेंट प्रॉम्प्ट जनरेशन**: परीक्षण करें कि एजेंट प्रॉम्प्ट में एमसीपी टूल तर्क विवरण शामिल हैं। + +### एकीकरण परीक्षण +**एंड-टू-एंड टूल इनवोकेशन**: एमसीपी टूल आर्गुमेंट्स के साथ टेस्ट एजेंट सफलतापूर्वक टूल को इनवोक कर सकता है। +**कॉन्फ़िगरेशन लोडिंग**: एमसीपी टूल आर्गुमेंट्स के साथ टेस्ट संपूर्ण कॉन्फ़िगरेशन लोडिंग साइकिल। +**क्रॉस-कंपोनेंट**: टेस्ट आर्गुमेंट्स का प्रवाह सही ढंग से कॉन्फ़िगरेशन → टूल क्रिएशन → प्रॉम्प्ट जेनरेशन से होता है। + +### मैनुअल टेस्टिंग +**एजेंट बिहेवियर**: मैन्युअल रूप से सत्यापित करें कि एलएलएम रीएक्ट साइकिल में आर्गुमेंट जानकारी प्राप्त करता है और उसका उपयोग करता है। +**सीएलआई इंटीग्रेशन**: टेस्ट `tg-invoke-mcp-tool` नए आर्गुमेंट-कॉन्फ़िगर किए गए एमसीपी टूल के साथ काम करता है। +**वर्कबेंच इंटीग्रेशन**: टेस्ट यूआई एमसीपी टूल आर्गुमेंट कॉन्फ़िगरेशन का समर्थन करता है। + +## माइग्रेशन और रोलआउट + +### माइग्रेशन रणनीति +माइग्रेशन की आवश्यकता नहीं है - यह पूरी तरह से अतिरिक्त कार्यक्षमता है: +मौजूदा एमसीपी टूल कॉन्फ़िगरेशन जिसमें `arguments` नहीं है, वह बिना किसी बदलाव के काम करना जारी रखता है। +`McpToolImpl.get_arguments()` लेगेसी टूल के लिए खाली सूची लौटाता है। +नए कॉन्फ़िगरेशन वैकल्पिक रूप से `arguments` सरणी शामिल कर सकते हैं। + +### रोलआउट योजना +1. **फेज 1**: डेवलपमेंट/स्टेजिंग में कोर एजेंट फ्रेमवर्क परिवर्तनों को तैनात करें। +2. **फेज 2**: सीएलआई टूल अपडेट और दस्तावेज़ तैनात करें। +3. **फेज 3**: आर्गुमेंट कॉन्फ़िगरेशन के लिए वर्कबेंच यूआई अपडेट तैनात करें। +4. **फेज 4**: मॉनिटरिंग के साथ प्रोडक्शन रोलआउट। + +### रोलबैक योजना +कोर परिवर्तन पिछड़े संगत हैं - कार्यक्षमता के लिए रोलबैक की आवश्यकता नहीं है। +यदि कोई समस्या उत्पन्न होती है, तो एमसीपी टूल कॉन्फ़िगरेशन लोडिंग लॉजिक को वापस करके आर्गुमेंट पार्सिंग को अक्षम करें। +वर्कबेंच और सीएलआई परिवर्तन स्वतंत्र हैं और उन्हें अलग से वापस किया जा सकता है। + +## सुरक्षा संबंधी विचार +**कोई नया अटैक सरफेस नहीं**: आर्गुमेंट्स मौजूदा कॉन्फ़िगरेशन स्रोतों से पार्स किए जाते हैं, जिसमें कोई नया इनपुट नहीं है। +**पैरामीटर सत्यापन**: आर्गुमेंट्स को एमसीपी टूल स्तर पर अपरिवर्तित एमसीपी टूल में पास किया जाता है - सत्यापन एमसीपी टूल स्तर पर रहता है। +**कॉन्फ़िगरेशन अखंडता**: आर्गुमेंट विनिर्देश टूल कॉन्फ़िगरेशन का हिस्सा हैं - समान सुरक्षा मॉडल लागू होता है। + +## प्रदर्शन प्रभाव +**न्यूनतम ओवरहेड**: आर्गुमेंट पार्सिंग केवल कॉन्फ़िगरेशन लोडिंग के दौरान होती है, प्रति-अनुरोध नहीं। +**प्रॉम्प्ट आकार में वृद्धि**: एजेंट प्रॉम्प्ट में एमसीपी टूल आर्गुमेंट विवरण शामिल होंगे, जिससे टोकन उपयोग थोड़ा बढ़ जाएगा। +**मेमोरी उपयोग**: टूल ऑब्जेक्ट में आर्गुमेंट विनिर्देशों को संग्रहीत करने के लिए मामूली वृद्धि। + +## दस्तावेज़ + +### उपयोगकर्ता दस्तावेज़ +[ ] आर्गुमेंट उदाहरणों के साथ एमसीपी टूल कॉन्फ़िगरेशन गाइड को अपडेट करें। +[ ] सीएलआई टूल हेल्प टेक्स्ट में आर्गुमेंट विनिर्देश जोड़ें। +[ ] सामान्य एमसीपी टूल आर्गुमेंट पैटर्न के उदाहरण बनाएं। + +### डेवलपर दस्तावेज़ +[ ] `McpToolImpl` क्लास दस्तावेज़ को अपडेट करें। +[ ] आर्गुमेंट पार्सिंग लॉजिक के लिए इनलाइन टिप्पणियाँ जोड़ें। +[ ] सिस्टम आर्किटेक्चर में आर्गुमेंट प्रवाह का दस्तावेज़ बनाएं। + +## खुले प्रश्न +1. **आर्गुमेंट सत्यापन**: क्या हमें बुनियादी संरचना जांच से परे आर्गुमेंट प्रकार/प्रारूपों को मान्य करना चाहिए? +2. **डायनामिक डिस्कवरी**: एमसीपी सर्वर से टूल स्कीमा को स्वचालित रूप से क्वेरी करने के लिए भविष्य में संवर्द्धन? + +## विचारे गए विकल्प +1. **डायनामिक एमसीपी स्कीमा डिस्कवरी**: रनटाइम पर टूल आर्गुमेंट स्कीमा के लिए एमसीपी सर्वर को क्वेरी करें - जटिलता और विश्वसनीयता संबंधी चिंताओं के कारण अस्वीकृत। +2. **अलग आर्गुमेंट रजिस्ट्री**: एमसीपी टूल आर्गुमेंट को अलग कॉन्फ़िगरेशन अनुभाग में संग्रहीत करें - प्रॉम्प्ट टेम्पलेट दृष्टिकोण के साथ स्थिरता के कारण अस्वीकृत। +3. **टाइप सत्यापन**: आर्गुमेंट के लिए पूर्ण JSON स्कीमा सत्यापन - प्रारंभिक कार्यान्वयन को सरल रखने के लिए भविष्य के संवर्द्धन के रूप में स्थगित। + +## संदर्भ +[एमसीपी प्रोटोकॉल विनिर्देश](https://github.com/modelcontextprotocol/spec) +[प्रॉम्प्ट टेम्पलेट टूल कार्यान्वयन](./trustgraph-flow/trustgraph/agent/react/service.py#L114-129) +[वर्तमान एमसीपी टूल कार्यान्वयन](./trustgraph-flow/trustgraph/agent/react/tools.py#L58-86) + +## परिशिष्ट +[कोई भी अतिरिक्त जानकारी, आरेख या उदाहरण] diff --git a/docs/tech-specs/mcp-tool-arguments.pt.md b/docs/tech-specs/mcp-tool-arguments.pt.md new file mode 100644 index 00000000..adff869a --- /dev/null +++ b/docs/tech-specs/mcp-tool-arguments.pt.md @@ -0,0 +1,256 @@ +# Especificação de Argumentos da Ferramenta MCP + +## Visão Geral +**Nome da Funcionalidade**: Suporte a Argumentos da Ferramenta MCP +**Autor**: Claude Code Assistant +**Data**: 2025-08-21 +**Status**: Finalizado + +### Resumo Executivo + +Permitir que agentes ReACT invoquem ferramentas MCP (Protocolo de Contexto do Modelo) com +argumentos definidos de forma adequada, adicionando suporte à especificação de argumentos às +configurações das ferramentas MCP, de forma semelhante a como as ferramentas de modelo de prompt +funcionam atualmente. + +### Declaração do Problema + +Atualmente, as ferramentas MCP no framework do agente ReACT não podem especificar seus +argumentos esperados. O método `McpToolImpl.get_arguments()` retorna +uma lista vazia, forçando os LLMs a adivinhar a estrutura correta de parâmetros +com base apenas nos nomes e descrições das ferramentas. Isso leva a: +Invocação de ferramentas não confiável devido à suposição de parâmetros +Má experiência do usuário quando as ferramentas falham devido a argumentos incorretos +Ausência de validação dos parâmetros da ferramenta antes da execução +Documentação de parâmetros ausente nos prompts do agente + +### Objetivos + +[ ] Permitir que as configurações da ferramenta MCP especifiquem os argumentos esperados (nome, tipo, descrição) +[ ] Atualizar o gerenciador de agentes para expor os argumentos da ferramenta MCP aos LLMs por meio de prompts +[ ] Manter a compatibilidade com versões anteriores com as configurações existentes da ferramenta MCP +[ ] Suportar a validação de argumentos semelhante às ferramentas de modelo de prompt + +### Não Objetivos +Descoberta dinâmica de argumentos a partir de servidores MCP (melhoria futura) +Validação de tipo de argumento além da estrutura básica +Esquemas de argumentos complexos (objetos aninhados, arrays) + +## Contexto e Informações de Base + +### Estado Atual +As ferramentas MCP são configuradas no sistema de agente ReACT com metadados mínimos: +```json +{ + "type": "mcp-tool", + "name": "get_bank_balance", + "description": "Get bank account balance", + "mcp-tool": "get_bank_balance" +} +``` + +O método `McpToolImpl.get_arguments()` retorna `[]`, portanto, os LLMs não recebem orientação de argumentos em seus prompts. + +### Limitações + +1. **Sem especificação de argumentos**: As ferramentas MCP não podem definir parâmetros esperados. + parâmetros. + +2. **Adivinhação de parâmetros do LLM**: Os agentes devem inferir parâmetros a partir dos nomes/descrições das ferramentas. + +3. **Informações do prompt ausentes**: Os prompts dos agentes não mostram detalhes dos argumentos para as ferramentas MCP. + + 4. **Sem validação**: Parâmetros inválidos são detectados apenas no momento da execução da ferramenta MCP. + +### Componentes Relacionados + **trustgraph-flow/agent/react/service.py**: Carregamento de configuração de ferramentas e criação do AgentManager. +**trustgraph-flow/agent/react/tools.py**: Implementação do McpToolImpl. +**trustgraph-flow/agent/react/agent_manager.py**: Geração de prompts com argumentos de ferramentas. +**trustgraph-cli**: Ferramentas de linha de comando para gerenciamento de ferramentas MCP. +**Workbench**: Interface de usuário externa para configuração de ferramentas de agente. + +## Requisitos + +### Requisitos Funcionais +## Requisitos + +### Requisitos Funcionais + +1. **Argumentos de Configuração da Ferramenta MCP**: As configurações da ferramenta MCP DEVEM suportar um array opcional `arguments` com campos de nome, tipo e descrição. +2. **Exposição de Argumentos**: `McpToolImpl.get_arguments()` DEVE retornar os argumentos configurados em vez de uma lista vazia. +3. **Integração com Prompts**: Os prompts do agente DEVEM incluir detalhes dos argumentos da ferramenta MCP quando os argumentos forem especificados. +4. **Compatibilidade com Versões Anteriores**: As configurações existentes da ferramenta MCP sem argumentos DEVEM continuar a funcionar. +5. **Suporte para CLI**: A CLI existente `tg-invoke-mcp-tool` suporta argumentos (já implementado). + +### Requisitos Não Funcionais +1. **Compatibilidade com Versões Anteriores**: Nenhuma alteração disruptiva para as configurações existentes da ferramenta MCP. +2. **Desempenho**: Nenhum impacto significativo no desempenho da geração de prompts do agente. +3. **Consistência**: O tratamento de argumentos DEVE corresponder aos padrões de ferramentas de modelos de prompt. + +### Histórias de Usuário + +1. Como um **desenvolvedor de agente**, quero especificar argumentos da ferramenta MCP na configuração para que os LLMs possam invocar ferramentas com parâmetros corretos. +2. Como um **usuário da workbench**, quero configurar argumentos da ferramenta MCP na interface do usuário para que os agentes usem as ferramentas corretamente. +3. Como um **LLM em um agente ReACT**, quero ver as especificações dos argumentos da ferramenta nos prompts para que eu possa fornecer parâmetros corretos. + +## Design + +### Arquitetura de Alto Nível +Estenda a configuração da ferramenta MCP para corresponder ao padrão do modelo de prompt, adicionando: +1. Um array opcional `arguments` às configurações da ferramenta MCP. +2. Modificações em `McpToolImpl` para aceitar e retornar argumentos configurados. +3. Atualizações no carregamento da configuração para lidar com os argumentos da ferramenta MCP. +4. Garantir que os prompts do agente incluam informações sobre os argumentos da ferramenta MCP. + +### Esquema de Configuração +```json +{ + "type": "mcp-tool", + "name": "get_bank_balance", + "description": "Get bank account balance", + "mcp-tool": "get_bank_balance", + "arguments": [ + { + "name": "account_id", + "type": "string", + "description": "Bank account identifier" + }, + { + "name": "date", + "type": "string", + "description": "Date for balance query (optional, format: YYYY-MM-DD)" + } + ] +} +``` + +### Fluxo de Dados +1. **Carregamento de Configuração**: A configuração da ferramenta MCP, juntamente com seus argumentos, é carregada por `on_tools_config()` +2. **Criação da Ferramenta**: Os argumentos são analisados e passados para `McpToolImpl` através do construtor +3. **Geração de Prompt**: `agent_manager.py` chama `tool.arguments` para incluir nos prompts do LLM +4. **Invocar a Ferramenta**: O LLM fornece parâmetros que são passados para o serviço MCP sem modificação + +### Alterações na API +Não há alterações na API externa - isso é puramente configuração interna e tratamento de argumentos. + +### Detalhes do Componente + +#### Componente 1: service.py (Carregamento de Configuração da Ferramenta) +**Propósito**: Analisar as configurações da ferramenta MCP e criar instâncias da ferramenta +**Alterações Necessárias**: Adicionar análise de argumentos para ferramentas MCP (semelhante às ferramentas de prompt) +**Nova Funcionalidade**: Extrair o array `arguments` da configuração da ferramenta MCP e criar objetos `Argument` + +#### Componente 2: tools.py (McpToolImpl) +**Propósito**: Wrapper de implementação da ferramenta MCP +**Alterações Necessárias**: Aceitar argumentos no construtor e retorná-los de `get_arguments()` +**Nova Funcionalidade**: Armazenar e expor os argumentos configurados em vez de retornar uma lista vazia + +#### Componente 3: Workbench (Repositório Externo) +**Propósito**: Interface do usuário para configurar ferramentas de agente +**Alterações Necessárias**: Adicionar interface do usuário para especificar argumentos para ferramentas MCP +**Nova Funcionalidade**: Permitir que os usuários adicionem/editem/removam argumentos para ferramentas MCP + +#### Componente 4: Ferramentas de Linha de Comando +**Propósito**: Gerenciamento de ferramentas de linha de comando +**Alterações Necessárias**: Suportar a especificação de argumentos nos comandos de criação/atualização da ferramenta MCP +**Nova Funcionalidade**: Aceitar o parâmetro de argumentos nos comandos de configuração da ferramenta + +## Plano de Implementação + +### Fase 1: Alterações no Framework Central do Agente +[ ] Atualizar o construtor de `McpToolImpl` para aceitar o parâmetro `arguments` +[ ] Alterar `McpToolImpl.get_arguments()` para retornar os argumentos armazenados +[ ] Modificar a análise de configuração da ferramenta MCP em `service.py` para lidar com argumentos +[ ] Adicionar testes unitários para o tratamento de argumentos da ferramenta MCP +[ ] Verificar se os prompts do agente incluem os argumentos da ferramenta MCP + +### Fase 2: Suporte para Ferramentas Externas +[ ] Atualizar as ferramentas de linha de comando para suportar a especificação de argumentos da ferramenta MCP +[ ] Documentar o formato de configuração de argumentos para os usuários +[ ] Atualizar a interface do usuário do Workbench para suportar a configuração de argumentos da ferramenta MCP +[ ] Adicionar exemplos e documentação + +### Resumo das Alterações no Código +| Arquivo | Tipo de Alteração | Descrição | +|------|------------|-------------| +| `tools.py` | Modificado | Atualizar McpToolImpl para aceitar e armazenar argumentos | +| `service.py` | Modificado | Analisar argumentos da configuração da ferramenta MCP (linhas 108-113) | +| `test_react_processor.py` | Modificado | Adicionar testes para argumentos da ferramenta MCP | +| Ferramentas de linha de comando | Modificado | Suportar a especificação de argumentos nos comandos | +| Workbench | Modificado | Adicionar interface do usuário para a configuração de argumentos da ferramenta MCP | + +## Estratégia de Teste + +### Testes Unitários +**Análise de Argumentos da Ferramenta MCP**: Testar se `service.py` analisa corretamente os argumentos das configurações da ferramenta MCP +**Argumentos do McpToolImpl**: Testar se `get_arguments()` retorna os argumentos configurados em vez de uma lista vazia +**Compatibilidade com Versões Anteriores**: Testar se as ferramentas MCP sem argumentos continuam a funcionar (retornam uma lista vazia) +**Geração de Prompt do Agente**: Testar se os prompts do agente incluem os detalhes dos argumentos da ferramenta MCP + +### Testes de Integração +**Invocar Ferramenta de Extremo a Extremo**: O agente de teste com argumentos da ferramenta MCP pode invocar ferramentas com sucesso. +**Carregamento de Configuração**: Testar o ciclo completo de carregamento de configuração com argumentos da ferramenta MCP. +**Componentes Cruzados**: Testar se os argumentos fluem corretamente de config → criação de ferramenta → geração de prompt. + +### Testes Manuais +**Comportamento do Agente**: Verificar manualmente se o LLM recebe e usa as informações dos argumentos nos ciclos ReACT. +**Integração com a Linha de Comando**: Testar se tg-invoke-mcp-tool funciona com ferramentas MCP configuradas com novos argumentos. +**Integração com o Workbench**: Testar se a interface do usuário suporta a configuração de argumentos para ferramentas MCP. + +## Migração e Implantação + +### Estratégia de Migração +Não é necessária migração - esta é uma funcionalidade puramente adicional: +As configurações existentes da ferramenta MCP sem `arguments` continuam a funcionar inalteradas. +`McpToolImpl.get_arguments()` retorna uma lista vazia para ferramentas legadas. +Novas configurações podem incluir opcionalmente o array `arguments`. + +### Plano de Implantação +1. **Fase 1**: Implantar as alterações principais do framework do agente para desenvolvimento/staging. +2. **Fase 2**: Implantar as atualizações da ferramenta de linha de comando e a documentação. +3. **Fase 3**: Implantar as atualizações da interface do usuário do Workbench para a configuração de argumentos. +4. **Fase 4**: Implantação em produção com monitoramento. + +### Plano de Reversão +As alterações principais são compatíveis com versões anteriores - nenhuma reversão é necessária para a funcionalidade. +Se surgirem problemas, desative a análise de argumentos revertendo a lógica de carregamento da configuração da ferramenta MCP. +As alterações do Workbench e da linha de comando são independentes e podem ser revertidas separadamente. + +## Considerações de Segurança +**Nenhuma nova superfície de ataque**: Os argumentos são analisados a partir de fontes de configuração existentes, sem novas entradas. +**Validação de parâmetros**: Os argumentos são passados para as ferramentas MCP sem alterações - a validação permanece no nível da ferramenta MCP. +**Integridade da configuração**: As especificações de argumentos fazem parte da configuração da ferramenta - o mesmo modelo de segurança se aplica. + +## Impacto no Desempenho +**Sobrecarga mínima**: A análise de argumentos ocorre apenas durante o carregamento da configuração, não por solicitação. +**Aumento do tamanho do prompt**: Os prompts do agente incluirão detalhes dos argumentos da ferramenta MCP, aumentando ligeiramente o uso de tokens. +**Uso de memória**: Aumento insignificante para armazenar as especificações de argumentos em objetos de ferramenta. + +## Documentação + +### Documentação do Usuário +[ ] Atualizar o guia de configuração da ferramenta MCP com exemplos de argumentos. +[ ] Adicionar a especificação de argumentos ao texto de ajuda da ferramenta de linha de comando. +[ ] Criar exemplos de padrões comuns de argumentos da ferramenta MCP. + +### Documentação para Desenvolvedores +[ ] Atualizar a documentação da classe McpToolImpl. +[ ] Adicionar comentários inline para a lógica de análise de argumentos. +[ ] Documentar o fluxo de argumentos na arquitetura do sistema. + +## Perguntas Abertas +1. **Validação de argumentos**: Devemos validar os tipos/formatos de argumentos além da verificação básica da estrutura? +2. **Descoberta dinâmica**: Uma melhoria futura para consultar os servidores MCP para esquemas de ferramentas automaticamente? + +## Alternativas Consideradas +1. **Descoberta dinâmica do esquema MCP**: Consultar os servidores MCP para esquemas de argumentos em tempo de execução - rejeitado devido à complexidade e preocupações com a confiabilidade. +2. **Registro de argumentos separado**: Armazenar os argumentos da ferramenta MCP em uma seção de configuração separada - rejeitado devido à inconsistência com a abordagem do modelo de prompt. +3. **Validação de tipo**: Validação completa do esquema JSON para argumentos - adiada como uma melhoria futura para manter a implementação inicial simples. + +## Referências +[Especificação do Protocolo MCP](https://github.com/modelcontextprotocol/spec) +[Implementação da Ferramenta do Modelo de Prompt](./trustgraph-flow/trustgraph/agent/react/service.py#L114-129) +[Implementação Atual da Ferramenta MCP](./trustgraph-flow/trustgraph/agent/react/tools.py#L58-86) + +## Apêndice +[Quaisquer informações adicionais, diagramas ou exemplos] diff --git a/docs/tech-specs/mcp-tool-arguments.sw.md b/docs/tech-specs/mcp-tool-arguments.sw.md new file mode 100644 index 00000000..81a28d9d --- /dev/null +++ b/docs/tech-specs/mcp-tool-arguments.sw.md @@ -0,0 +1,256 @@ +# Vipimo vya Majadiliano ya Zana ya MCP + +## Muhtasari +**Jina la Kipengele:** Usaidizi wa Majadiliano ya Zana ya MCP +**Mwandishi:** Claude Code Assistant +**Tarehe:** 2025-08-21 +**Hali:** Imekamilika + +### Muhtasari + +Kuruhusu wakala wa ReACT kuita zana za MCP (Model Context Protocol) kwa +majadiliano yaliyobainishwa vizuri kwa kuongeza usaidizi wa majadiliano katika +usanidi wa zana za MCP, kama vile zana za kiolezo za matangazo +zinavyofanya sasa. + +### Tatizo + +Kwa sasa, zana za MCP katika mfumo wa wakala wa ReACT haziwezi kuainisha +majadiliano yake yanayotarajiwa. Njia ya `McpToolImpl.get_arguments()` hurudisha +orodha tupu, na kuwafanya LLMs (Large Language Models) nadhani muundo sahihi +wa vigezo kulingana na majina na maelezo ya zana pekee. Hii husababisha: +Utendaji usio wa kuaminika wa zana kutokana na nadharia ya vigezo +Uzoefu mbaya wa mtumiaji wakati zana zinashindwa kutokana na majadiliano yasiyo sahihi +Hakuna uthibitishaji wa vigezo vya zana kabla ya utekelezaji +Ukosefu wa maandishi ya vigezo katika matangazo ya wakala + +### Lengo + +[ ] Kuruhusu usanidi wa zana za MCP kuainisha majadiliano yanayotarajiwa (jina, aina, maelezo) +[ ] Kusasisha meneja wa wakala ili kuonyesha majadiliano ya zana za MCP kwa LLMs kupitia matangazo +[ ] Kuhifadhi utangamano na usanidi wa zana za MCP zilizopo +[ ] Kusaidia uthibitishaji wa majadiliano kama vile zana za kiolezo za matangazo + +### Mambo ambayo Hayatarajiwi +Kugundua majadiliano kwa njia ya moja kwa moja kutoka kwa seva za MCP (ongezeko la baadaye) +Uthibitishaji wa aina ya majadiliano zaidi ya muundo wa msingi +Mifumo ngumu ya majadiliano (vitu vilivyojumuishwa, safu) + +## Asili na Mfumo + +### Hali ya Sasa +Zana za MCP zimepangwa katika mfumo wa wakala wa ReACT na metadata ndogo: +```json +{ + "type": "mcp-tool", + "name": "get_bank_balance", + "description": "Get bank account balance", + "mcp-tool": "get_bank_balance" +} +``` + +Njia `McpToolImpl.get_arguments()` hurudia `[]`, kwa hivyo, mifumo ya lugha kubwa (LLMs) hayapokei mwongozo wowote kuhusu hoja katika maagizo yao. + +### Mapungufu + +1. **Hakuna uainishaji wa hoja**: Vifaa vya MCP haviwezi kufafanua + vigezo. + +2. **Utabiri wa vigezo vya LLM**: Wawakilishi lazima watabiri vigezo kutoka kwa majina/maelezo ya zana. + +3. **Habari ya maagizo inayokosekana**: Maagizo ya wakala yanaonyesha maelezo yoyote kuhusu hoja kwa vifaa vya MCP. + + 4. **Hakuna uthibitisho**: Vigezo visivyofaa hugunduliwa wakati wa utekelezaji wa zana ya MCP. + +### Vipengele Vinavyohusiana + **trustgraph-flow/agent/react/service.py**: Kupakia usanidi wa zana na uundaji wa AgentManager. +**trustgraph-flow/agent/react/tools.py**: Utendaji wa McpToolImpl. +**trustgraph-flow/agent/react/agent_manager.py**: Uundaji wa maagizo pamoja na hoja za zana. +**trustgraph-cli**: Vifaa vya CLI kwa usimamizi wa zana za MCP. +**Workbench**: Kiolesura cha nje cha usanidi wa zana za wakala. + +## Mahitaji + +### Mahitaji ya Kifamilia +## Mahitaji + +### Mahitaji ya Kazi + +1. **Vigezo vya Usanidi wa Zana ya MCP**: Usanidi wa zana za MCP LAZIMA uunga mkono safu ya hiari ya `arguments` yenye nyanja za jina, aina, na maelezo. +2. **Uonyeshaji wa Vigezo**: `McpToolImpl.get_arguments()` INAHITAJIKA kurudisha vigezo vilivyosanidiwa badala ya orodha tupu. +3. **Uunganisho wa Maagizo**: Maagizo ya wakala LAZIMA yajumuise maelezo ya vigezo vya zana ya MCP wakati vigezo vinapotajwa. +4. **Ulinganifu na Mifumo ya Zamani**: Usanidi wa zana za MCP uliopo bila vigezo LAZIMA uendelee kufanya kazi. +5. **Usaidizi wa CLI**: CLI ya `tg-invoke-mcp-tool` iliyopo inasaidia vigezo (tayari imetekelezwa). + +### Mahitaji Yasiyo ya Kazi +1. **Ulinganifu na Mifumo ya Zamani**: Hakuna mabadiliko yoyote yanayoweza kusababisha migogoro kwa usanidi wa zana za MCP uliopo. +2. **Utendaji**: Hakuna athari kubwa ya utendaji kwenye uzalishaji wa maagizo ya wakala. +3. **Ulinganifu**: Usimamizi wa vigezo LAZIMA uangane na mifumo ya zana za kiolezo katika kiolezo cha maagizo. + +### Hadithi za Mtumiaji + +1. Kama **msanidi programu wa wakala**, ninataka kuainisha vigezo vya zana ya MCP katika usanidi ili kwamba mifumo ya LLM iweze kutumia zana na vigezo sahihi. +2. Kama **mtumiaji wa benchi ya kazi**, ninataka kusanidi vigezo vya zana ya MCP katika UI ili kwamba wakala watumie zana vizuri. +3. Kama **mfumo wa LLM katika wakala wa ReACT**, ninataka kuona maelezo ya vigezo vya zana katika maagizo ili kwamba niweze kutoa vigezo sahihi. + +## Muundo + +### Muundo wa Juu +Panua usanidi wa zana ya MCP ili uangane na muundo wa kiolezo cha maagizo kwa: +1. Kuongeza safu ya hiari ya `arguments` kwa usanidi wa zana za MCP. +2. Kubadilisha `McpToolImpl` ili kukubali na kurudisha vigezo vilivyosanidiwa. +3. Kusasisha upakaji wa usanidi ili kushughulikia vigezo vya zana ya MCP. +4. Kuhakikisha kwamba maagizo ya wakala yajumuise taarifa ya vigezo vya zana ya MCP. + +### Mfumo wa Usanidi +```json +{ + "type": "mcp-tool", + "name": "get_bank_balance", + "description": "Get bank account balance", + "mcp-tool": "get_bank_balance", + "arguments": [ + { + "name": "account_id", + "type": "string", + "description": "Bank account identifier" + }, + { + "name": "date", + "type": "string", + "description": "Date for balance query (optional, format: YYYY-MM-DD)" + } + ] +} +``` + +### Mtiririko wa Data +1. **Uipakaji wa Usanidi**: Usanidi wa zana ya MCP pamoja na hoja huipakwa na `on_tools_config()` +2. **Uundaji wa Zana**: Hoja huzingatiwa na kupitishwa kwa `McpToolImpl` kupitia kwa konstrukta +3. **Uundaji wa Maagizo**: `agent_manager.py` huita `tool.arguments` ili kujumuishwa katika maagizo ya LLM +4. **Utendaji wa Zana**: LLM hutoa vigezo ambavyo hupitishwa kwa huduma ya MCP bila kubadilishwa + +### Mabadiliko ya API +Hakuna mabadiliko ya API ya nje - hii ni usanidi na usimamizi wa hoja wa ndani tu. + +### Maelezo ya Vipengele + +#### Kipengele 1: service.py (Uipakaji wa Usanidi wa Zana) +**Madhumuni**: Kuchanganua usanidi wa zana za MCP na kuunda mifano ya zana +**Mabadiliko Yanayohitajika**: Ongeza uchanganuzi wa hoja kwa zana za MCP (kama vile zana za maagizo) +**Utendaji Mpya**: Toa safu ya `arguments` kutoka usanidi wa zana ya MCP na uunde vitu vya `Argument` + +#### Kipengele 2: tools.py (McpToolImpl) +**Madhumuni**: Kifungashio cha utekelezaji wa zana ya MCP +**Mabadiliko Yanayohitajika**: Kukubali hoja katika konstrukta na kurejesha hoja hizo kutoka `get_arguments()` +**Utendaji Mpya**: Kuhifadhi na kuonyesha hoja zilizosanidiwa badala ya kurejesha orodha tupu + +#### Kipengele 3: Workbench (Hifadhi Nje) +**Madhumuni**: Kiolesura cha usanidi wa zana za wakala +**Mabadiliko Yanayohitajika**: Ongeza kiolesura cha maelezo ya hoja kwa zana za MCP +**Utendaji Mpya**: Kuruhusu watumiaji kuongeza/kuhariri/kuondoa hoja kwa zana za MCP + +#### Kipengele 4: Zana za CLI +**Madhumuni**: Usimamizi wa zana za mstari wa amri +**Mabadiliko Yanayohitajika**: Kusaidia maelezo ya hoja katika amri za uundaji/kusasisha zana za MCP +**Utendaji Mpya**: Kukubali parameter ya hoja katika amri za usanidi wa zana + +## Mpango wa Utendaji + +### Awamu ya 1: Marekebisho ya Msingi ya Mfumo wa Wakala +[ ] Sasisha konstrukta ya `McpToolImpl` ili kukubali parameter ya `arguments` +[ ] Badilisha `McpToolImpl.get_arguments()` ili irudishe hoja zilizohifadhiwa +[ ] Badilisha usanifuaji wa `service.py` wa zana ya MCP ili kushughulikia hoja +[ ] Ongeza vipimo vya kitengo kwa usimamizi wa hoja za zana ya MCP +[ ] Hakikisha maagizo ya wakala yanajumuisha hoja za zana ya MCP + +### Awamu ya 2: Usaidizi wa Zana za Nje +[ ] Sasisha zana za CLI ili kusaidia vipimo vya hoja za zana ya MCP +[ ] Andika maelezo ya muundo wa usanifuaji wa hoja kwa watumiaji +[ ] Sasisha kiolesura cha Kazi (Workbench) ili kusaidia usanifuaji wa hoja za zana ya MCP +[ ] Ongeza mifano na maandishi + +### Muhtasari wa Marekebisho ya Msimbo +| Faili | Aina ya Marekebisho | Maelezo | +|------|------------|-------------| +| `tools.py` | Imebadilishwa | Sasisha McpToolImpl ili kukubali na kuhifadhi hoja | +| `service.py` | Imebadilishwa | Pata hoja kutoka usanifuaji wa zana ya MCP (mstari wa 108-113) | +| `test_react_processor.py` | Imebadilishwa | Ongeza vipimo kwa hoja za zana ya MCP | +| Zana za CLI | Imebadilishwa | Saidia vipimo vya hoja katika amri | +| Workbench | Imebadilishwa | Ongeza kiolesura kwa usanifuaji wa hoja za zana ya MCP | + +## Mkakati wa Upimaji + +### Vipimo vya Kitengo +**Uchanganuzi wa Hoja za Zana ya MCP**: Hakikisha `service.py` inachanganua hoja vizuri kutoka usanifuaji wa zana ya MCP +**Hoja za McpToolImpl**: Hakikisha `get_arguments()` inarudisha hoja zilizosanifishwa badala ya orodha tupu +**Ulinganishi wa Awali**: Hakikisha zana za MCP bila hoja zinaendelea kufanya kazi (kurudisha orodha tupu) +**Uundaji wa Maagizo ya Wakala**: Hakikisha maagizo ya wakala yanajumuisha maelezo ya hoja za zana ya MCP + +### Vipimo vya Uunganisho +**Uteuzi wa Zana Kamili**: Mfumo wa majaribio unaweza kuendesha zana kwa kutumia hoja za zana za MCP. +**Uipakaji wa Mipangilio**: Jaribu mchakato kamili wa kupakua mipangilio kwa kutumia hoja za zana za MCP. +**Kati ya Vipengele**: Hakikisha hoja zinapitishwa vizuri kutoka kwenye mipangilio hadi katika uundaji wa zana na uundaji wa maagizo. + +### Majaribio ya Kawaida +**Tabia ya Mfumo**: Angalia kwa uangalifu kama mfumo unapokea na kutumia taarifa za hoja katika mzunguko wa ReACT. +**Uunganisho wa CLI**: Jaribu kama `tg-invoke-mcp-tool` inafanya kazi na zana za MCP ambazo zimepangwa na hoja. +**Uunganisho wa Workbench**: Jaribu kama UI inasaidia upangaji wa hoja za zana za MCP. + +## Uhamisho na Uanzishaji + +### Mkakati wa Uhamisho +Hakuna uhamishaji unaohitajika - hii ni kipengele cha ziada: +Mipangilio ya zana za MCP iliyopo ambayo haina `arguments` inaendelea kufanya kazi bila mabadiliko. +`McpToolImpl.get_arguments()` inarudisha orodha tupu kwa zana za zamani. +Mipangilio mipya inaweza kujumuisha `arguments`. + +### Mpango wa Uanzishaji +1. **Awamu ya 1**: Anzisha mabadiliko ya msingi ya mfumo kwenye eneo la maendeleo/maandalizi. +2. **Awamu ya 2**: Anzisha sasisho za zana za CLI na nyaraka. +3. **Awamu ya 3**: Anzisha sasisho za UI za Workbench kwa upangaji wa hoja. +4. **Awamu ya 4**: Uanzishaji wa uzalishaji na ufuatiliaji. + +### Mpango wa Kurudisha Nyuma +Mabadiliko ya msingi yanaambatana na matoleo ya awali - hakuna haja ya kurudisha nyuma kwa utendaji. +Ikiwa matatizo yanajitokeza, zima uchanganuzi wa hoja kwa kurejesha mantiki ya kupakua mipangilio ya zana za MCP. +Mabadiliko ya Workbench na CLI yanaweza kurejeshwa kando. + +## Masuala ya Usalama +**Hakuna eneo jipya la shambulio**: Hoja zinachanganzwa kutoka kwa vyanzo vya mipangilio iliyopo bila pembejeo mpya. +**Uthibitisho wa vigezo**: Hoja huhamishwa kwa zana za MCP bila mabadiliko - uthibitisho unaendelea katika kiwango cha zana za MCP. +**Uadilifu wa mipangilio**: Maelezo ya hoja ni sehemu ya upangaji wa zana - mfumo sawa wa usalama unafanya kazi. + +## Athari za Utendaji +**Uongezeko mdogo**: Uchanganuzi wa hoja hufanyika tu wakati wa kupakua mipangilio, sio kwa kila ombi. +**Kukua kwa saizi ya maagizo**: Maagizo ya mfumo yatajumuisha maelezo ya hoja za zana za MCP, na hivyo kuongeza matumizi ya tokeni. +**Matumizi ya kumbukumbu**: Kuongezeka kwa kiasi kidogo kwa kuhifadhi maelezo ya hoja katika vitu vya zana. + +## Nyaraka + +### Nyaraka za Mtumiaji +[ ] Sasisha mwongozo wa upangaji wa zana za MCP na mifano ya hoja. +[ ] Ongeza maelezo ya hoja kwenye maandishi ya usaidizi wa zana za CLI. +[ ] Unda mifano ya muundo wa kawaida wa hoja za zana za MCP. + +### Nyaraka za Mpelelezi +[ ] Sasisha nyaraka za darasa la `McpToolImpl`. +[ ] Ongeza maelezo ya ndani kwa mantiki ya uchanganuzi wa hoja. +[ ] Andika maelezo ya mtiririko wa hoja katika muundo wa mfumo. + +## Maswali Yaliyofunguliwa +1. **Uthibitisho wa hoja**: Je, tunapaswa kuthibitisha aina/aina za hoja zaidi ya ukaguzi wa muundo wa msingi? +2. **Utafiti wa kiotomatiki**: Uboreshaji wa baadaye wa kuuliza seva za MCP kwa schema za zana kiotomatiki? + +## Mbadala Zilizozingatiwa +1. **Utafiti wa kiotomatiki wa schema ya MCP**: Kuuliza seva za MCP kwa schema za hoja za zana wakati wa utendaji - ilikataliwa kwa sababu ya utata na wasiwasi wa kuegemea. +2. **Usajili wa kando wa hoja**: Kuhifadhi hoja za zana za MCP katika sehemu tofauti ya upangaji - ilikataliwa kwa utangamano na mbinu ya kiolezo ya maagizo. +3. **Uthibitisho wa aina**: Uthibitisho kamili wa schema ya JSON kwa hoja - imeahirishwa kama uboreshaji wa baadaye ili kuendeleza utekelezaji wa awali. + +## Marejeleo +[Maelezo ya Itifaki ya MCP](https://github.com/modelcontextprotocol/spec) +[Utekelezaji wa Zana ya Kiolezo ya Maagizo](./trustgraph-flow/trustgraph/agent/react/service.py#L114-129) +[Utekelezaji wa Sasa wa Zana ya MCP](./trustgraph-flow/trustgraph/agent/react/tools.py#L58-86) + +## Toa Maelezo +[Maelezo yoyote ya ziada, michoro, au mifano] diff --git a/docs/tech-specs/mcp-tool-arguments.tr.md b/docs/tech-specs/mcp-tool-arguments.tr.md new file mode 100644 index 00000000..12dea056 --- /dev/null +++ b/docs/tech-specs/mcp-tool-arguments.tr.md @@ -0,0 +1,256 @@ +# MCP Aracı Argümanları Belirtimi + +## Genel Bakış +**Özellik Adı**: MCP Aracı Argümanları Desteği +**Yazar**: Claude Code Assistant +**Tarih**: 2025-08-21 +**Durum**: Tamamlandı + +### Yönetici Özeti + +ReACT ajanlarının, argüman belirtimi desteğini MCP (Model Bağlam Protokolü) araç yapılandırmalarına ekleyerek, +doğru şekilde tanımlanmış argümanlarla MCP araçlarını çağırmasına olanak sağlayın; bu, mevcut istem şablonu araçlarının +nasıl çalıştığına benzer şekilde. + + +### Problem Tanımı + + +Şu anda, ReACT ajan çerçevesindeki MCP araçları, beklenen argümanlarını belirleyememektedir. `McpToolImpl.get_arguments()` metodu +boş bir liste döndürmektedir, bu da LLM'lerin (Büyük Dil Modelleri) yalnızca araç adlarına ve açıklamalarına dayanarak +doğru parametre yapısını tahmin etmesini gerektirmektedir. Bu, aşağıdaki sorunlara yol açmaktadır: +Parametre tahminine bağlı olarak güvenilir olmayan araç çağrıları +Yanlış argümanlar nedeniyle araçların başarısız olması durumunda kötü kullanıcı deneyimi +Yürütmeden önce araç parametrelerinin doğrulanmaması +Ajan istemlerindeki eksik parametre dokümantasyonu + +### Hedefler + +[ ] MCP araç yapılandırmalarının beklenen argümanları (ad, tür, açıklama) belirtmesine izin verin. +[ ] Ajan yöneticisini, MCP araç argümanlarını istemler aracılığıyla LLM'lere sunacak şekilde güncelleyin. +[ ] Mevcut MCP araç yapılandırmalarıyla geriye dönük uyumluluğu koruyun. +[ ] İstem şablonu araçlarına benzer şekilde argüman doğrulamasını destekleyin. + +### Kapsam Dışı Hedefler +MCP sunucularından dinamik argüman keşfi (gelecek iyileştirme) +Temel yapı dışındaki argüman türü doğrulaması +Karmaşık argüman şemaları (iç içe nesneler, diziler) + +## Arka Plan ve Bağlam + +### Mevcut Durum +MCP araçları, ReACT ajan sisteminde minimum düzeyde meta veriyle yapılandırılmaktadır: +```json +{ + "type": "mcp-tool", + "name": "get_bank_balance", + "description": "Get bank account balance", + "mcp-tool": "get_bank_balance" +} +``` + +`McpToolImpl.get_arguments()` metodu `[]` değerini döndürür, bu nedenle LLM'ler, istemlerinde argüman rehberliği almaz. + +### Sınırlamalar + +1. **Argüman belirtimi yok**: MCP araçları, beklenen + parametreleri tanımlayamaz. + +2. **LLM parametre tahmini**: Ajanlar, parametreleri araç + adlarından/açıklamalarından çıkarım yoluyla belirlemelidir. + +3. **Eksik istem bilgisi**: Ajan istemleri, MCP araçları için argüman + ayrıntılarını göstermez. + +4. **Doğrulama yok**: Geçersiz parametreler, yalnızca MCP araç + yürütme zamanında tespit edilir. + +### İlgili Bileşenler +**trustgraph-flow/agent/react/service.py**: Araç yapılandırması yükleme ve AgentManager oluşturma. +**trustgraph-flow/agent/react/tools.py**: McpToolImpl uygulaması. +**trustgraph-flow/agent/react/agent_manager.py**: Araç argümanlarıyla birlikte istem oluşturma. +**trustgraph-cli**: MCP araç yönetimi için komut satırı araçları. +**Workbench**: Ajan araç yapılandırması için harici kullanıcı arayüzü. + +## Gereksinimler + +### Fonksiyonel Gereksinimler + +1. **MCP Araç Yapılandırma Argümanları**: MCP araç yapılandırmaları, isteğe bağlı bir `arguments` dizisiyle (ad, tür ve açıklama alanları) desteklemelidir. +2. **Argüman Açıklaması**: `McpToolImpl.get_arguments()`, boş bir liste yerine yapılandırılmış argümanları döndürmelidir. +3. **İstem Entegrasyonu**: Ajan istemleri, argümanlar belirtildiğinde MCP araç argümanı ayrıntılarını içermelidir. +4. **Geriye Dönük Uyumluluk**: Argümanlar olmadan mevcut MCP araç yapılandırmaları çalışmaya devam etmelidir. +5. **Komut Satırı Desteği**: Mevcut `tg-invoke-mcp-tool` komut satırı araçları, argümanları destekler (zaten uygulanmıştır). + +### Fonksiyonel Olmayan Gereksinimler +1. **Geriye Dönük Uyumluluk**: Mevcut MCP araç yapılandırmaları için hiçbir bozucu değişiklik olmamalıdır. +2. **Performans**: Ajan istemi oluşturma üzerinde önemli bir performans etkisi olmamalıdır. +3. **Tutarlılık**: Argüman işleme, istem şablonu araç kalıplarıyla eşleşmelidir. + +### Kullanıcı Hikayeleri + +1. Bir **ajan geliştirici** olarak, LLM'lerin doğru parametrelerle araçları çağırması için MCP araç argümanlarını yapılandırmada belirtmek istiyorum. +2. Bir **workbench kullanıcısı** olarak, ajanların araçları doğru şekilde kullanması için MCP araç argümanlarını kullanıcı arayüzünde yapılandırmak istiyorum. +3. Bir **ReACT ajanı içindeki bir LLM** olarak, doğru parametreler sağlamak için istemlerdeki araç argümanı özelliklerini görmek istiyorum. + +## Tasarım + +### Yüksek Seviyeli Mimari +MCP araç yapılandırmasını, istem şablonu kalıbıyla eşleşecek şekilde aşağıdaki adımlarla genişletin: +1. MCP araç yapılandırmalarına isteğe bağlı bir `arguments` dizisi ekleyin. +2. `McpToolImpl`'nin yapılandırılmış argümanları kabul etmesini ve döndürmesini sağlayın. +3. MCP araç argümanlarını işlemek için araç yapılandırması yüklemeyi güncelleyin. +4. Ajan istemlerinin MCP araç argümanı bilgilerini içermesini sağlayın. + +### Yapılandırma Şeması +```json +{ + "type": "mcp-tool", + "name": "get_bank_balance", + "description": "Get bank account balance", + "mcp-tool": "get_bank_balance", + "arguments": [ + { + "name": "account_id", + "type": "string", + "description": "Bank account identifier" + }, + { + "name": "date", + "type": "string", + "description": "Date for balance query (optional, format: YYYY-MM-DD)" + } + ] +} +``` + +### Veri Akışı +1. **Yapılandırma Yükleme**: `on_tools_config()` ile birlikte MCP aracı yapılandırması yüklenir. +2. **Araç Oluşturma**: Argümanlar ayrıştırılır ve `McpToolImpl`'e oluşturucu aracılığıyla iletilir. +3. **İstem Oluşturma**: `agent_manager.py`, LLM istemlerine dahil etmek için `tool.arguments`'i çağırır. +4. **Araç Çağrısı**: LLM, MCP hizmetine değiştirilmeden parametreler sağlar. + +### API Değişiklikleri +Harici API değişiklikleri yok - bu tamamen içsel yapılandırma ve argüman işleme ile ilgilidir. + +### Bileşen Detayları + +#### Bileşen 1: service.py (Araç Yapılandırma Yükleme) +**Amaç**: MCP araç yapılandırmalarını ayrıştırın ve araç örnekleri oluşturun. +**Gerekli Değişiklikler**: MCP araçları için argüman ayrıştırması ekleyin (istem araçlarına benzer şekilde). +**Yeni İşlevsellik**: MCP araç yapılandırmasından `arguments` dizisini çıkarın ve `Argument` nesneleri oluşturun. + +#### Bileşen 2: tools.py (McpToolImpl) +**Amaç**: MCP araç uygulaması sarmalayıcısı. +**Gerekli Değişiklikler**: Oluşturucuda argümanları kabul edin ve bunları `get_arguments()`'den döndürün. +**Yeni İşlevsellik**: Boş bir liste döndürmek yerine yapılandırılmış argümanları saklayın ve sergileyin. + +#### Bileşen 3: Workbench (Harici Depo) +**Amaç**: Aracılar için kullanıcı arayüzü yapılandırma. +**Gerekli Değişiklikler**: MCP araçları için argüman belirtme kullanıcı arayüzü ekleyin. +**Yeni İşlevsellik**: Kullanıcıların MCP araçları için argümanları eklemesine/düzenlemesine/kaldırmasına izin verin. + +#### Bileşen 4: CLI Araçları +**Amaç**: Komut satırı aracı yönetimi. +**Gerekli Değişiklikler**: MCP araç oluşturma/güncelleme komutlarında argüman belirtimini destekleyin. +**Yeni İşlevsellik**: Araç yapılandırma komutlarında argüman parametresini kabul edin. + +## Uygulama Planı + +### 1. Aşama: Temel Ajan Çerçevesi Değişiklikleri +[ ] `McpToolImpl` oluşturucusunu `arguments` parametresini kabul edecek şekilde güncelleyin. +[ ] `McpToolImpl.get_arguments()`'ın saklanan argümanları döndürmesi için değiştirin. +[ ] `service.py` MCP araç yapılandırma ayrıştırmasını argümanları işleyecek şekilde değiştirin. +[ ] MCP araç argüman işleme için birim testleri ekleyin. +[ ] Ajan istemlerinin MCP araç argümanlarını içerdiğini doğrulayın. + +### 2. Aşama: Harici Araç Desteği +[ ] CLI araçlarını MCP araç argüman belirtimini destekleyecek şekilde güncelleyin. +[ ] Kullanıcılar için argüman yapılandırma biçimini belgeleyin. +[ ] Workbench kullanıcı arayüzünü MCP araç argüman yapılandırmasını destekleyecek şekilde güncelleyin. +[ ] Örnekler ve belgeler ekleyin. + +### Kod Değişiklikleri Özeti +| Dosya | Değişiklik Türü | Açıklama | +|------|------------|-------------| +| `tools.py` | Değiştirildi | `tools.py`'ı argümanları kabul edecek ve saklayacak şekilde güncelleyin | +| `service.py` | Değiştirildi | MCP araç yapılandırmasından argümanları ayrıştırın (satır 108-113) | +| `test_react_processor.py` | Değiştirildi | MCP araç argümanları için testler ekleyin | +| CLI araçları | Değiştirildi | Komutlarda argüman belirtimini destekleyin | +| Workbench | Değiştirildi | MCP araç argüman yapılandırması için bir kullanıcı arayüzü ekleyin | + +## Test Stratejisi + +### Birim Testleri +**MCP Araç Argüman Ayrıştırması**: `service.py`'ın MCP araç yapılandırmalarından argümanları doğru bir şekilde ayrıştırdığını test edin. +**McpToolImpl Argümanları**: `get_arguments()`'ın yapılandırılmış argümanları döndürdüğünü ve boş bir liste döndürmediğini test edin. +**Geriye Dönük Uyumluluk**: Argümanları olmayan MCP araçlarının çalışmaya devam ettiğini (boş bir liste döndürdüğünü) test edin. +**Ajan İstem Oluşturma**: Ajan istemlerinin MCP araç argümanı ayrıntılarını içerdiğini test edin. + +### Entegrasyon Testleri +**Uçtan Uca Araç Çağrısı**: MCP araç argümanlarıyla test aracısı, araçları başarıyla çağırabilir. +**Yapılandırma Yükleme**: MCP araç argümanlarıyla test yapılandırma yükleme döngüsünü tamamlayın. +**Çoklu Bileşen**: Argümanların yapılandırmadan → araç oluşturmaya → istem oluşturmaya doğru doğru şekilde aktarılmasını test edin. + +### Manuel Testler +**Ajan Davranışı**: LLM'nin ReACT döngülerinde argüman bilgilerini alıp kullandığını manuel olarak doğrulayın. +**CLI Entegrasyonu**: `tg-invoke-mcp-tool`'un yeni argüman yapılandırmalı MCP araçlarıyla çalıştığını test edin. +**Çalışma Ortamı Entegrasyonu**: Kullanıcı arayüzünün MCP araç argümanı yapılandırmasını desteklediğini test edin. + +## Göç ve Dağıtım + +### Göç Stratejisi +Göç gerektirmez - bu tamamen ek bir işlevsellik: +``arguments`` içermeyen mevcut MCP araç yapılandırmaları, herhangi bir değişiklik olmadan çalışmaya devam eder. +``McpToolImpl.get_arguments()``, eski araçlar için boş bir liste döndürür. +Yeni yapılandırmalar isteğe bağlı olarak ``arguments`` dizisini içerebilir. + +### Dağıtım Planı +1. **1. Aşama**: Çekirdek ajan çerçevesi değişikliklerini geliştirme/hazırlık ortamına dağıtın. +2. **2. Aşama**: CLI araç güncellemelerini ve belgeleri dağıtın. +3. **3. Aşama**: Argüman yapılandırması için çalışma ortamı kullanıcı arayüzü güncellemelerini dağıtın. +4. **4. Aşama**: İzleme ile üretim dağıtımı. + +### Geri Alma Planı +Çekirdek değişiklikler geriye dönük uyumludur - işlevsellik için geri alma işlemine gerek yoktur. +Sorunlar ortaya çıkarsa, MCP araç yapılandırma yükleme mantığını geri alarak argüman ayrıştırmayı devre dışı bırakın. +Çalışma ortamı ve CLI değişiklikleri bağımsızdır ve ayrı olarak geri alınabilir. + +## Güvenlik Hususları +**Yeni bir saldırı yüzeyi yok**: Argümanlar, yeni girdiler olmadan mevcut yapılandırma kaynaklarından ayrıştırılır. +**Parametre doğrulama**: Argümanlar MCP araçlarına değiştirilmeden iletilir - doğrulama MCP araç seviyesinde kalır. +**Yapılandırma bütünlüğü**: Argüman özellikleri araç yapılandırmasının bir parçasıdır - aynı güvenlik modeli uygulanır. + +## Performans Etkisi +**Minimum ek yük**: Argüman ayrıştırması yalnızca yapılandırma yükleme sırasında, her istekte değil gerçekleşir. +**İstem boyutu artışı**: Ajan istemleri, MCP araç argümanı ayrıntılarını içerecek ve bu da token kullanımını biraz artıracaktır. +**Bellek kullanımı**: Argüman özelliklerinin araç nesnelerinde depolanması için ihmal edilebilir bir artış. + +## Belgeler + +### Kullanıcı Belgeleri +[ ] Argüman örnekleriyle MCP araç yapılandırma kılavuzunu güncelleyin. +[ ] CLI araç yardım metnine argüman belirtimi ekleyin. +[ ] Yaygın MCP araç argümanı kalıplarının örneklerini oluşturun. + +### Geliştirici Belgeleri +[ ] `McpToolImpl` sınıfının belgelerini güncelleyin. +[ ] Argüman ayrıştırma mantığı için iç içe yorumlar ekleyin. +[ ] Sistem mimarisinde argüman akışını belgeleyin. + +## Açık Sorular +1. **Argüman doğrulama**: Temel yapı kontrolünün ötesinde argüman türlerini/formatlarını doğrulamalı mıyız? +2. **Dinamik keşif**: Gelecekte MCP sunucularından araç şemalarını otomatik olarak sorgulamak için bir özellik mi? + +## Göz Önünde Bulundurulan Alternatifler +1. **Dinamik MCP şema keşfi**: Çalışma zamanında araç argüman şemaları için MCP sunucularını sorgulayın - karmaşıklık ve güvenilirlik sorunları nedeniyle reddedildi. +2. **Ayrı argüman kaydı**: MCP araç argümanlarını ayrı bir yapılandırma bölümünde saklayın - başlangıç uygulamasının basit kalması için istem şablonu yaklaşımıyla tutarlılık nedeniyle reddedildi. +3. **Tip doğrulama**: Argümanlar için tam JSON şema doğrulaması - başlangıçta basit bir uygulama sağlamak için gelecekteki bir özellik olarak ertelendi. + +## Referanslar +[MCP Protokolü Özellikleri](https://github.com/modelcontextprotocol/spec) +[İstem Şablonu Araç Uygulaması](./trustgraph-flow/trustgraph/agent/react/service.py#L114-129) +[Mevcut MCP Araç Uygulaması](./trustgraph-flow/trustgraph/agent/react/tools.py#L58-86) + +## Ek +[Herhangi bir ek bilgi, diyagram veya örnek] diff --git a/docs/tech-specs/mcp-tool-bearer-token.ar.md b/docs/tech-specs/mcp-tool-bearer-token.ar.md new file mode 100644 index 00000000..615e883a --- /dev/null +++ b/docs/tech-specs/mcp-tool-bearer-token.ar.md @@ -0,0 +1,554 @@ +# مواصفات مصادقة رمز الحامل لأدوات MCP + +> **⚠️ هام: مخصص للعملاء ذوي المستأجر الواحد فقط** +> +> تصف هذه المواصفات آلية مصادقة أساسية على مستوى الخدمة لأدوات MCP. إنها **ليست** حلاً كاملاً للمصادقة وليست **مناسبة** لـ: +> - بيئات متعددة المستخدمين +> - عمليات نشر متعددة المستأجرين +> - المصادقة الموحدة +> - نقل سياق المستخدم +> - التفويض لكل مستخدم +> +> توفر هذه الميزة **رمزًا ثابتًا واحدًا لكل أداة MCP**، يتم مشاركته عبر جميع المستخدمين والجلسات. إذا كنت بحاجة إلى مصادقة لكل مستخدم أو لكل مستأجر، فهذه ليست الحل المناسب. + +## نظرة عامة +**اسم الميزة**: دعم رمز الحامل للمصادقة لأدوات MCP +**المؤلف**: مساعد كود كلود +**التاريخ**: 2025-11-11 +**الحالة**: قيد التطوير + +### ملخص تنفيذي + +قم بتمكين تكوينات أدوات MCP لتحديد رموز حامل اختيارية للمصادقة مع خوادم MCP المحمية. يتيح ذلك لـ TrustGraph استدعاء أدوات MCP المستضافة على الخوادم التي تتطلب المصادقة بشكل آمن، دون تعديل وكيل الأداة أو واجهات استدعاء الأداة. + +**هام**: هذه آلية مصادقة أساسية مصممة لسيناريوهات المصادقة من خدمة إلى خدمة، خاصة بالمستأجر الواحد. إنها **ليست** مناسبة لـ: +بيئات متعددة المستخدمين حيث يحتاج المستخدمون المختلفون إلى بيانات اعتماد مختلفة +عمليات نشر متعددة المستأجرين تتطلب عزلًا لكل مستأجر +سيناريوهات المصادقة الموحدة +مصادقة أو تفويض على مستوى المستخدم +إدارة بيانات الاعتماد الديناميكية أو تحديث الرموز + +توفر هذه الميزة رمز حامل ثابتًا على مستوى النظام لكل تكوين أداة MCP، يتم مشاركته عبر جميع المستخدمين واستدعاءات تلك الأداة. + +### بيان المشكلة + +حاليًا، يمكن لأدوات MCP الاتصال فقط بخوادم MCP التي يمكن الوصول إليها للجمهور. تتطلب العديد من عمليات نشر MCP الإنتاجية مصادقة عبر رموز الحامل لأسباب أمنية. بدون دعم المصادقة: +لا يمكن لأدوات MCP الاتصال بخوادم MCP الآمنة +يجب على المستخدمين إما تعريض خوادم MCP للجمهور أو تنفيذ وكلاء عكسيين +لا توجد طريقة موحدة لتمرير بيانات الاعتماد إلى اتصالات MCP +لا يمكن فرض أفضل ممارسات الأمان على نقاط نهاية MCP + +### الأهداف + +[ ] السماح لتكوينات أدوات MCP بتحديد معلمة `auth-token` اختيارية +[ ] تحديث خدمة أداة MCP لاستخدام رموز الحامل عند الاتصال بخوادم MCP +[ ] تحديث أدوات سطر الأوامر لدعم تعيين/عرض رموز المصادقة +[ ] الحفاظ على التوافق مع الإصدارات السابقة لتكوينات MCP غير المصادقة +[ ] توثيق اعتبارات الأمان لتخزين الرموز + +### الأهداف غير المشمولة +تحديث الرموز الديناميكي أو تدفقات OAuth (رموز ثابتة فقط) +تشفير الرموز المخزنة (أمان نظام التكوين خارج النطاق) +طرق مصادقة بديلة (المصادقة الأساسية، مفاتيح API، إلخ.) +التحقق من صحة الرموز أو انتهاء صلاحيتها +**المصادقة لكل مستخدم**: لا تدعم هذه الميزة بيانات اعتماد خاصة بالمستخدم +**عزل متعدد المستأجرين**: لا توفر هذه الميزة إدارة رموز لكل مستأجر +**المصادقة الموحدة**: لا تتكامل هذه الميزة مع موفري الهوية (SSO، OAuth، SAML، إلخ.) +**المصادقة الواعية بالسياق**: لا يتم تمرير الرموز بناءً على سياق المستخدم أو الجلسة + +## الخلفية والسياق + +### الحالة الحالية +يتم تخزين تكوينات أدوات MCP في مجموعة التكوين `mcp` بهذه البنية: +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +تتصل خدمة أداة MCP بالخوادم باستخدام `streamablehttp_client(url)` بدون أي رؤوس مصادقة. + +### القيود + +**قيود النظام الحالية:** +1. **لا يوجد دعم للمصادقة:** لا يمكن الاتصال بخوادم MCP المحمية. +2. **تعرض أمني:** يجب أن تكون خوادم MCP متاحة للجمهور أو تستخدم أمان على مستوى الشبكة فقط. +3. **مشكلات النشر في بيئة الإنتاج:** لا يمكن اتباع أفضل الممارسات الأمنية لنقاط نهاية واجهة برمجة التطبيقات. + +**قيود هذا الحل:** +1. **نظام مستأجر واحد فقط:** رمز ثابت واحد لكل أداة MCP، مشترك بين جميع المستخدمين. +2. **لا توجد بيانات اعتماد خاصة بالمستخدم:** لا يمكن المصادقة كمستخدمين مختلفين أو تمرير سياق المستخدم. +3. **لا يوجد دعم للأنظمة متعددة المستأجرين:** لا يمكن عزل بيانات الاعتماد حسب المستأجر أو المؤسسة. +4. **رموز ثابتة فقط:** لا يوجد دعم لتحديث الرموز أو تدويرها أو معالجة انتهاء صلاحيتها. +5. **مصادقة على مستوى الخدمة:** تقوم المصادقة على خدمة TrustGraph، وليس على المستخدمين الفرديين. +6. **سياق أمني مشترك:** تستخدم جميع استدعاءات أداة MCP نفس الاعتماد. + +### مدى ملاءمة حالة الاستخدام + +**✅ حالات الاستخدام المناسبة:** +عمليات نشر TrustGraph ذات المستأجر الواحد. +مصادقة من خدمة إلى خدمة (TrustGraph → خادم MCP). +بيئات التطوير والاختبار. +أدوات MCP الداخلية التي يتم الوصول إليها بواسطة نظام TrustGraph. +السيناريوهات التي يشارك فيها جميع المستخدمين نفس مستوى الوصول إلى أداة MCP. +بيانات اعتماد خدمة ثابتة وطويلة الأجل. + +**❌ حالات الاستخدام غير المناسبة:** +الأنظمة متعددة المستخدمين التي تتطلب مصادقة خاصة بالمستخدم. +عمليات نشر SaaS متعددة المستأجرين مع متطلبات عزل المستأجر. +سيناريوهات المصادقة الموحدة (SSO، OAuth، SAML). +الأنظمة التي تتطلب تمرير سياق المستخدم إلى خوادم MCP. +البيئات التي تحتاج إلى تحديث الرموز ديناميكيًا أو رموز قصيرة الأجل. +التطبيقات التي تحتاج فيها مستخدمون مختلفون إلى مستويات أذونات مختلفة. +متطلبات الامتثال لتسجيلات التدقيق على مستوى المستخدم. + +**مثال على سيناريو مناسب:** +عملية نشر TrustGraph لمنظمة واحدة حيث يستخدم جميع الموظفين نفس أداة MCP الداخلية (على سبيل المثال، البحث في قاعدة بيانات الشركة). يتطلب خادم MCP مصادقة لمنع الوصول الخارجي، ولكن جميع المستخدمين الداخليين لديهم نفس مستوى الوصول. + +**مثال على سيناريو غير مناسب:** +منصة SaaS متعددة المستأجرين لـ TrustGraph حيث يحتاج كل من المستأجر A والمستأجر B إلى الوصول إلى خوادم MCP الخاصة بهم المعزولة ببيانات اعتماد منفصلة. لا يدعم هذا الميزة إدارة الرموز الخاصة بالمستأجر. + +### المكونات ذات الصلة +**trustgraph-flow/trustgraph/agent/mcp_tool/service.py**: خدمة استدعاء أداة MCP. +**trustgraph-cli/trustgraph/cli/set_mcp_tool.py**: أداة سطر أوامر لإنشاء/تحديث تكوينات MCP. +**trustgraph-cli/trustgraph/cli/show_mcp_tools.py**: أداة سطر أوامر لعرض تكوينات MCP. +**مجموعة تطوير البرامج (SDK) لـ MCP بلغة Python**: `streamablehttp_client` من `mcp.client.streamable_http` + +## المتطلبات + +### المتطلبات الوظيفية + +1. **رمز مصادقة تكوين MCP:** يجب أن تدعم تكوينات أداة MCP حقل `auth-token` اختياري. +2. **استخدام رمز مميز:** يجب أن ترسل خدمة أداة MCP رأس `Authorization: Bearer {token}` عند تكوين رمز مميز. +3. **دعم سطر الأوامر:** يجب أن تقبل `tg-set-mcp-tool` معلمة `--auth-token` اختيارية. +4. **عرض الرمز:** يجب أن تشير `tg-show-mcp-tools` إلى متى تم تكوين رمز مميز (تم إخفاءه لأسباب أمنية). +5. **التوافق مع الإصدارات السابقة:** يجب أن تستمر تكوينات أداة MCP الحالية بدون رمز مميز في العمل. + +### المتطلبات غير الوظيفية +1. **التوافق مع الإصدارات السابقة:** لا توجد تغييرات فاصلة للإصدارات لتكوينات أداة MCP الحالية. +2. **الأداء:** لا يوجد تأثير كبير على الأداء على استدعاء أداة MCP. +3. **الأمان:** يتم تخزين الرموز في التكوين (يرجى توثيق الآثار الأمنية). + +### قصص المستخدم + +1. بصفتي **مهندس DevOps**، أريد تكوين رموز مميزة لأدوات MCP حتى أتمكن من تأمين نقاط نهاية خادم MCP. +2. بصفتي **مستخدم سطر أوامر**، أريد تعيين رموز مميزة عند إنشاء أدوات MCP حتى أتمكن من الاتصال بالخوادم المحمية. +3. بصفتي **مسؤول النظام**، أريد أن أرى أي أدوات MCP تم تكوين مصادقة لها حتى أتمكن من تدقيق إعدادات الأمان. + +## التصميم + +### البنية عالية المستوى +قم بتوسيع تكوين وخدمة أداة MCP لدعم مصادقة الرمز المميز: +1. أضف حقل `auth-token` اختياري إلى مخطط تكوين أداة MCP. +2. قم بتعديل خدمة أداة MCP لقراءة الرمز المميز وتمريره إلى عميل HTTP. +3. قم بتحديث أدوات سطر الأوامر لدعم تعيين وعرض الرموز المميزة. +4. قم بتوثيق الاعتبارات الأمنية وأفضل الممارسات. + +### مخطط التكوين + +**المخطط الحالي:** +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +**مخطط جديد** (مع رمز مصادقة اختياري): +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api", + "auth-token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} +``` + +**وصف الحقول:** +`remote-name` (اختياري): الاسم المستخدم بواسطة خادم MCP (افتراضيًا، مفتاح التكوين) +`url` (إلزامي): عنوان URL لنقطة نهاية خادم MCP +`auth-token` (اختياري): رمز مميز (Bearer token) للمصادقة + +### تدفق البيانات + +1. **تخزين التكوين:** يقوم المستخدم بتشغيل `tg-set-mcp-tool --id my-tool --tool-url http://server/api --auth-token xyz123` +2. **تحميل التكوين:** يتلقى خدمة أداة MCP تحديث التكوين عبر استدعاء رد (callback) `on_mcp_config()` +3. **استدعاء الأداة:** عند استدعاء الأداة: + تقرأ الخدمة `auth-token` من التكوين (إذا كان موجودًا) + تقوم بإنشاء قاموس الرؤوس: `{"Authorization": "Bearer {token}"}` + تمرر الرؤوس إلى `streamablehttp_client(url, headers=headers)` + يقوم خادم MCP بالتحقق من صحة الرمز المميز ومعالجة الطلب + +### تغييرات واجهة برمجة التطبيقات (API) +لا توجد تغييرات في واجهة برمجة التطبيقات الخارجية - فقط توسيع مخطط التكوين. + +### تفاصيل المكون + +#### المكون 1: service.py (خدمة أداة MCP) +**الملف:** `trustgraph-flow/trustgraph/agent/mcp_tool/service.py` + +**الغرض:** استدعاء أدوات MCP على الخوادم البعيدة + +**التغييرات المطلوبة** (في طريقة `invoke_tool()`): +1. التحقق من وجود `auth-token` في تكوين `self.mcp_services[name]` +2. إنشاء قاموس الرؤوس مع رأس "Authorization" إذا كان الرمز المميز موجودًا +3. تمرير الرؤوس إلى `streamablehttp_client(url, headers=headers)` + +**الكود الحالي** (الأسطر 42-89): +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server + async with streamablehttp_client(url) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method +``` + +**الكود المُعدَّل**: +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + # Build headers with optional bearer token + headers = {} + if "auth-token" in self.mcp_services[name]: + token = self.mcp_services[name]["auth-token"] + headers["Authorization"] = f"Bearer {token}" + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server with headers + async with streamablehttp_client(url, headers=headers) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method (unchanged) +``` + +#### المكون 2: set_mcp_tool.py (أداة تكوين سطر الأوامر) +**الملف**: `trustgraph-cli/trustgraph/cli/set_mcp_tool.py` + +**الغرض**: إنشاء/تحديث إعدادات أداة MCP + +**التغييرات المطلوبة**: +1. إضافة وسيطة اختيارية `--auth-token` إلى argparse +2. تضمين `auth-token` في ملف JSON الخاص بالتكوين عند توفره + +**الوسائط الحالية**: +`--id` (مطلوب): معرف أداة MCP +`--remote-name` (اختياري): اسم أداة MCP البعيدة +`--tool-url` (مطلوب): نقطة نهاية عنوان URL لأداة MCP +`-u, --api-url` (اختياري): عنوان URL لواجهة برمجة تطبيقات TrustGraph + +**وسيطة جديدة**: +`--auth-token` (اختياري): رمز مميز للمصادقة + +**تعديل بناء التكوين**: +```python +# Build configuration object +config = { + "url": args.tool_url, +} + +if args.remote_name: + config["remote-name"] = args.remote_name + +if args.auth_token: + config["auth-token"] = args.auth_token + +# Store configuration +api.config().put([ + ConfigValue(type="mcp", key=args.id, value=json.dumps(config)) +]) +``` + +#### المكون 3: show_mcp_tools.py (أداة العرض من سطر الأوامر) +**الملف**: `trustgraph-cli/trustgraph/cli/show_mcp_tools.py` + +**الغرض**: عرض إعدادات أدوات MCP. + +**التغييرات المطلوبة**: +1. إضافة عمود "Auth" إلى جدول الإخراج. +2. عرض "نعم" أو "لا" بناءً على وجود رمز المصادقة. +3. عدم عرض قيمة الرمز الفعلية (لأسباب أمنية). + +**الإخراج الحالي**: +``` +ID Remote Name URL +---------- ------------- ------------------------ +my-tool my-tool http://server:3000/api +``` + +**الناتج الجديد**: +``` +ID Remote Name URL Auth +---------- ------------- ------------------------ ------ +my-tool my-tool http://server:3000/api Yes +other-tool other-tool http://other:3000/api No +``` + +#### المكون 4: التوثيق +**الملف**: `docs/cli/tg-set-mcp-tool.md` + +**التغييرات المطلوبة**: +1. توثيق المعاملة الجديدة `--auth-token` +2. تقديم مثال للاستخدام مع المصادقة +3. توثيق الاعتبارات الأمنية + +## خطة التنفيذ + +### المرحلة الأولى: إنشاء المواصفات الفنية +[x] كتابة مواصفات فنية شاملة توثق جميع التغييرات + +### المرحلة الثانية: تحديث خدمة MCP +[ ] تعديل `invoke_tool()` في `service.py` لقراءة رمز المصادقة من التكوين +[ ] إنشاء قاموس الرؤوس وتمريره إلى `streamablehttp_client` +[ ] الاختبار مع خادم MCP مصادق عليه + +### المرحلة الثالثة: تحديث أدوات سطر الأوامر +[ ] إضافة المعامل `--auth-token` إلى `set_mcp_tool.py` +[ ] تضمين رمز المصادقة في ملف تكوين JSON +[ ] إضافة عمود "المصادقة" إلى إخراج `show_mcp_tools.py` +[ ] اختبار تغييرات أداة سطر الأوامر + +### المرحلة الرابعة: تحديث التوثيق +[ ] توثيق المعامل `--auth-token` في `tg-set-mcp-tool.md` +[ ] إضافة قسم للاعتبارات الأمنية +[ ] تقديم مثال للاستخدام + +### المرحلة الخامسة: الاختبار +[ ] اختبار أن خدمة MCP تقرأ رمز المصادقة وتتصل بنجاح +[ ] اختبار التوافق مع الإصدارات السابقة (الأدوات بدون رمز مصادقة لا تزال تعمل) +[ ] اختبار أن أدوات سطر الأوامر تقبل وتخزن رمز المصادقة بشكل صحيح +[ ] اختبار أن الأمر "عرض" يعرض حالة المصادقة بشكل صحيح + +### ملخص التغييرات في التعليمات البرمجية +| الملف | نوع التغيير | الأسطر | الوصف | +|------|------------|-------|-------------| +| `service.py` | تم التعديل | ~52-66 | إضافة قراءة رمز المصادقة وإنشاء الرؤوس | +| `set_mcp_tool.py` | تم التعديل | ~30-60 | إضافة وسيطة --auth-token وتخزين التكوين | +| `show_mcp_tools.py` | تم التعديل | ~40-70 | إضافة عمود المصادقة للعرض | +| `tg-set-mcp-tool.md` | تم التعديل | متنوع | توثيق المعامل الجديد | + +## استراتيجية الاختبار + +### اختبارات الوحدة +**قراءة رمز المصادقة**: اختبار ما إذا كانت `invoke_tool()` تقرأ رمز المصادقة بشكل صحيح من التكوين +**إنشاء الرؤوس**: اختبار ما إذا كان يتم إنشاء رأس التفويض بشكل صحيح مع البادئة "Bearer" +**التوافق مع الإصدارات السابقة**: اختبار ما إذا كانت الأدوات بدون رمز مصادقة تعمل دون تغيير +**تحليل وسيطات سطر الأوامر**: اختبار ما إذا كانت المعامل `--auth-token` يتم تحليلها بشكل صحيح + +### اختبارات التكامل +**الاتصال المصادق**: اختبار ما إذا كانت خدمة MCP تتصل بخادم مصادق عليه +**نهاية إلى نهاية**: اختبار تدفق سطر الأوامر → تخزين التكوين → استدعاء الخدمة باستخدام رمز المصادقة +**غير مطلوب رمز المصادقة**: اختبار الاتصال بخادم غير مصادق عليه لا يزال يعمل + +### الاختبار اليدوي +**خادم MCP حقيقي**: اختبار مع خادم MCP فعلي يتطلب مصادقة باستخدام رمز "Bearer" +**تدفق سطر الأوامر**: اختبار التدفق الكامل: تعيين الأداة باستخدام رمز مصادقة → استدعاء الأداة → التحقق من النجاح +**إخفاء العرض**: التحقق من أن حالة المصادقة معروضة ولكن قيمة الرمز غير معروضة + +## الترحيل والنشر + +### استراتيجية الترحيل +لا يلزم الترحيل - هذه وظيفة إضافية بحتة: +تكوينات أدوات MCP الحالية بدون `auth-token` تستمر في العمل دون تغيير +يمكن أن تتضمن التكوينات الجديدة اختياريًا حقل `auth-token` +تقبل أدوات سطر الأوامر ولكن لا تتطلب المعامل `--auth-token` + +### خطة النشر +1. **المرحلة 1**: نشر تغييرات الخدمة الأساسية إلى التطوير/التجريب +2. **المرحلة 2**: نشر تحديثات أدوات سطر الأوامر +3. **المرحلة 3**: تحديث التوثيق +4. **المرحلة 4**: النشر في بيئة الإنتاج مع المراقبة + +### خطة التراجع +التغييرات الأساسية متوافقة مع الإصدارات السابقة - لا تتأثر الأدوات الحالية +في حالة ظهور مشكلات، يمكن تعطيل معالجة رمز المصادقة عن طريق إزالة منطق إنشاء الرأس +يمكن التراجع عن تغييرات سطر الأوامر بشكل مستقل + +## اعتبارات الأمان + +### ⚠️ قيد حاسم: مصادقة المستأجر الواحد فقط + +**هذه آلية المصادقة غير مناسبة للبيئات متعددة المستخدمين أو متعددة المستأجرين.** + +**بيانات اعتماد مشتركة**: جميع المستخدمين والاستدعاءات يشاركون نفس الرمز لكل أداة MCP +**لا يوجد سياق مستخدم**: لا يمكن لخادم MCP التمييز بين مستخدمي TrustGraph المختلفين +**عزل المستأجر**: تشارك جميع المستأجرين نفس الاعتماد لكل أداة MCP +**قيود سجل التدقيق**: يسجل خادم MCP جميع الطلبات من نفس الاعتماد +**نطاق الأذونات**: لا يمكن فرض مستويات أذونات مختلفة لمستخدمين مختلفين + +**لا تستخدم هذه الميزة إذا:** +يخدم توزيعة TrustGraph الخاصة بك مؤسسات متعددة (متعددة المستأجرين) +تحتاج إلى تتبع المستخدم الذي قام بالوصول إلى أداة MCP +تتطلب مستخدمون مختلفون مستويات أذونات مختلفة +تحتاج إلى الامتثال لمتطلبات التدقيق على مستوى المستخدم +خادم MCP الخاص بك يفرض حدود معدل أو حصص لكل مستخدم + +**حلول بديلة لسيناريوهات المستخدمين المتعددين/العملاء المتعددين:** +تنفيذ نشر سياق المستخدم من خلال رؤوس مخصصة +نشر مثيلات TrustGraph منفصلة لكل عميل +استخدام عزل على مستوى الشبكة (VPCs، شبكات الخدمات) +تنفيذ طبقة وكيل تتعامل مع المصادقة لكل مستخدم + +### تخزين الرموز المميزة +**مخاطر**: يتم تخزين الرموز المميزة للمصادقة كنص عادي في نظام التكوين + +**تدابير تخفيفية**: +توثيق أن الرموز المميزة مخزنة بدون تشفير +يوصى باستخدام الرموز المميزة قصيرة الأجل كلما أمكن ذلك +يوصى بتطبيق ضوابط وصول مناسبة على تخزين التكوين +ضع في اعتبارك تحسينًا مستقبليًا لتخزين الرموز المميزة المشفرة + +### كشف الرموز المميزة +**مخاطر**: يمكن الكشف عن الرموز المميزة في سجلات أو مخرجات سطر الأوامر + +**تدابير تخفيفية**: +لا تقم بتسجيل قيم الرموز المميزة (قم بتسجيل "تم تكوين المصادقة: نعم/لا" فقط) +يعرض أمر "show" الخاص بسطر الأوامر الحالة "مخفية" فقط، وليس الرمز المميز الفعلي +لا تقم بتضمين الرموز المميزة في رسائل الخطأ + +### أمان الشبكة +**مخاطر**: يتم نقل الرموز المميزة عبر اتصالات غير مشفرة + +**تدابير تخفيفية**: +يوصى بتوثيق استخدام عناوين URL لبروتوكول HTTPS لخوادم MCP +تحذير المستخدمين بشأن مخاطر النقل النصي باستخدام HTTP + +### الوصول إلى التكوين +**مخاطر**: يؤدي الوصول غير المصرح به إلى نظام التكوين إلى كشف الرموز المميزة + +**تدابير تخفيفية**: +قم بتوثيق أهمية تأمين الوصول إلى نظام التكوين +يوصى بمبدأ الامتياز الأقل للوصول إلى التكوين +ضع في اعتبارك تسجيل التدقيق للتغييرات في التكوين (تحسين مستقبلي) + +### بيئات المستخدمين المتعددين +**مخاطر**: في عمليات النشر متعددة المستخدمين، يشارك جميع المستخدمين نفس بيانات اعتماد MCP + +**فهم المخاطر**: +يستخدم كل من المستخدم أ والمستخدم ب نفس الرمز المميز عند الوصول إلى أداة MCP +لا يمكن لخادم MCP التمييز بين مستخدمي TrustGraph المختلفين +لا توجد طريقة لفرض أذونات أو حدود معدل لكل مستخدم +تُظهر سجلات التدقيق على خادم MCP جميع الطلبات من نفس الاعتماد +إذا تم اختراق جلسة مستخدم واحد، يتمتع المهاجم بنفس وصول MCP مثل جميع المستخدمين + +**هذا ليس خطأ - إنه قيد أساسي لهذا التصميم.** + +## التأثير على الأداء +**نفقات عامة ضئيلة**: يضيف بناء الرأس وقت معالجة ضئيل +**تأثير الشبكة**: يضيف رأس HTTP إضافي ~ 50-200 بايت لكل طلب +**استخدام الذاكرة**: زيادة طفيفة لتخزين سلسلة الرمز المميز في التكوين + +## التوثيق + +### وثائق المستخدم +[ ] قم بتحديث `tg-set-mcp-tool.md` باستخدام معلمة `--auth-token` +[ ] أضف قسمًا للاعتبارات الأمنية +[ ] قدم مثالًا للاستخدام باستخدام رمز مميز +[ ] قم بتوثيق آثار تخزين الرمز المميز + +### وثائق المطور +[ ] أضف تعليقات مضمنة للتعامل مع الرمز المميز للمصادقة في `service.py` +[ ] وثق منطق بناء الرأس +[ ] قم بتحديث وثائق مخطط تكوين أداة MCP + +## أسئلة مفتوحة +1. **تشفير الرمز المميز**: هل يجب علينا تنفيذ تخزين مشفر للرموز المميزة في نظام التكوين؟ +2. **تحديث الرمز المميز**: دعم مستقبلي لتدفقات تحديث OAuth أو تدوير الرموز المميزة؟ +3. **طرق مصادقة بديلة**: هل يجب أن ندعم المصادقة الأساسية أو مفاتيح API أو طرق أخرى؟ + +## بدائل تم أخذها في الاعتبار + +1. **متغيرات البيئة للرموز المميزة**: قم بتخزين الرموز المميزة في متغيرات البيئة بدلاً من التكوين + **مرفوض**: يعقد النشر وإدارة التكوين + +2. **مخزن أسرار منفصل**: استخدم نظام إدارة أسرار مخصص + **مؤجل**: خارج نطاق التنفيذ الأولي، ضع في اعتبارك تحسينًا مستقبليًا + +3. **طرق مصادقة متعددة**: دعم الأساسي و API key و OAuth وما إلى ذلك + **مرفوض**: تغطي الرموز المميزة الخاصة بالحامل معظم حالات الاستخدام، حافظ على بساطة التنفيذ الأولي + +4. **تخزين مشفر للرموز المميزة**: قم بتشفير الرموز المميزة في نظام التكوين + **مؤجل**: يعد أمان نظام التكوين مصدر قلق أوسع، وتأجيله إلى عمل مستقبلي + +5. **الرموز المميزة لكل استدعاء**: اسمح بتمرير الرموز المميزة في وقت الاستدعاء + **مرفوض**: ينتهك فصل الاهتمامات، لا ينبغي للوكيل التعامل مع بيانات الاعتماد + +## المراجع +[مواصفات بروتوكول MCP](https://github.com/modelcontextprotocol/spec) +[مصادقة حامل HTTP (RFC 6750)](https://tools.ietf.org/html/rfc6750) +[خدمة أداة MCP الحالية](../trustgraph-flow/trustgraph/agent/mcp_tool/service.py) +[مواصفات وسيطات أداة MCP](./mcp-tool-arguments.md) + +## الملحق + +### مثال للاستخدام + +**إعداد أداة MCP مع المصادقة:** +```bash +tg-set-mcp-tool \ + --id secure-tool \ + --tool-url https://secure-server.example.com/mcp \ + --auth-token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +``` + +**عرض أدوات MCP:** +```bash +tg-show-mcp-tools + +ID Remote Name URL Auth +----------- ----------- ------------------------------------ ------ +secure-tool secure-tool https://secure-server.example.com/mcp Yes +public-tool public-tool http://localhost:3000/mcp No +``` + +### مثال على الإعدادات + +**مخزنة في نظام الإعدادات:** +```json +{ + "type": "mcp", + "key": "secure-tool", + "value": "{\"url\": \"https://secure-server.example.com/mcp\", \"auth-token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\"}" +} +``` + +### أفضل الممارسات الأمنية + +1. **استخدام HTTPS**: استخدم دائمًا عناوين URL لبروتوكول HTTPS لخوادم MCP التي تتطلب مصادقة. +2. **الرموز قصيرة الأجل**: استخدم الرموز التي لها تاريخ انتهاء صلاحية كلما أمكن ذلك. +3. **أقل الامتيازات**: امنح الرموز الحد الأدنى من الأذونات المطلوبة. +4. **التحكم في الوصول**: قم بتقييد الوصول إلى نظام التكوين. +5. **تغيير الرموز بشكل دوري**: قم بتغيير الرموز بانتظام. +6. **تسجيل التدقيق**: راقب تغييرات التكوين بحثًا عن أحداث أمنية. diff --git a/docs/tech-specs/mcp-tool-bearer-token.es.md b/docs/tech-specs/mcp-tool-bearer-token.es.md new file mode 100644 index 00000000..0857ea87 --- /dev/null +++ b/docs/tech-specs/mcp-tool-bearer-token.es.md @@ -0,0 +1,554 @@ +# Especificación de autenticación de tokens Bearer para herramientas MCP + +> **⚠️ IMPORTANTE: SOLO PARA UN ÚNICO ARREGLO (SINGLE-TENANT)** +> +> Esta especificación describe un **mecanismo básico de autenticación a nivel de servicio** para herramientas MCP. **NO** es una solución de autenticación completa y **NO es adecuada** para: +> - Entornos multiusuario +> - Despliegues multi-inquilino (multi-tenant) +> - Autenticación federada +> - Propagación del contexto del usuario +> - Autorización por usuario +> +> Esta función proporciona **un único token estático por herramienta MCP**, compartido entre todos los usuarios y sesiones. Si necesita autenticación por usuario o por inquilino, esta no es la solución adecuada. + +## Descripción general +**Nombre de la función**: Soporte de autenticación de tokens Bearer para herramientas MCP +**Autor**: Claude Code Assistant +**Fecha**: 2025-11-11 +**Estado**: En desarrollo + +### Resumen ejecutivo + +Permite que las configuraciones de las herramientas MCP especifiquen tokens Bearer opcionales para autenticarse con servidores MCP protegidos. Esto permite que TrustGraph invoque de forma segura las herramientas MCP alojadas en servidores que requieren autenticación, sin modificar las interfaces de invocación de agentes o herramientas. + +**IMPORTANTE**: Este es un mecanismo de autenticación básico diseñado para escenarios de autenticación de servicio a servicio en un único arreglo (single-tenant). **NO** es adecuado para: +Entornos multiusuario donde diferentes usuarios necesitan diferentes credenciales +Despliegues multi-inquilino (multi-tenant) que requieren aislamiento por inquilino +Escenarios de autenticación federada +Autenticación o autorización a nivel de usuario +Gestión dinámica de credenciales o actualización de tokens + +Esta función proporciona un token Bearer estático y a nivel de sistema por configuración de herramienta MCP, compartido entre todos los usuarios e invocaciones de esa herramienta. + +### Declaración del problema + +Actualmente, las herramientas MCP solo pueden conectarse a servidores MCP accesibles públicamente. Muchos despliegues de MCP en producción requieren autenticación mediante tokens Bearer por motivos de seguridad. Sin soporte de autenticación: +Las herramientas MCP no pueden conectarse a servidores MCP protegidos +Los usuarios deben exponer los servidores MCP públicamente o implementar proxies inversos +No existe una forma estandarizada de pasar credenciales a las conexiones MCP +No se pueden aplicar las mejores prácticas de seguridad en los puntos finales de MCP + +### Objetivos + +[ ] Permitir que las configuraciones de las herramientas MCP especifiquen un parámetro opcional `auth-token` +[ ] Actualizar el servicio de la herramienta MCP para usar tokens Bearer al conectarse a servidores MCP +[ ] Actualizar las herramientas de la CLI para admitir la configuración/visualización de tokens de autenticación +[ ] Mantener la compatibilidad con versiones anteriores con configuraciones de MCP sin autenticación +[ ] Documentar las consideraciones de seguridad para el almacenamiento de tokens + +### Objetivos no incluidos +Actualización dinámica de tokens o flujos OAuth (solo tokens estáticos) +Cifrado de tokens almacenados (la seguridad del sistema de configuración está fuera del alcance) +Métodos de autenticación alternativos (autenticación básica, claves API, etc.) +Validación o verificación de la fecha de caducidad de los tokens +**Autenticación por usuario**: Esta función **NO** admite credenciales específicas del usuario +**Aislamiento multi-inquilino (multi-tenant)**: Esta función **NO** proporciona gestión de tokens por inquilino +**Autenticación federada**: Esta función **NO** se integra con proveedores de identidad (SSO, OAuth, SAML, etc.) +**Autenticación con conocimiento del contexto**: Los tokens no se pasan en función del contexto del usuario o la sesión + +## Antecedentes y contexto + +### Estado actual +Las configuraciones de las herramientas MCP se almacenan en el grupo de configuración `mcp` con esta estructura: +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +El servicio de la herramienta MCP se conecta a los servidores utilizando `streamablehttp_client(url)` sin ningún encabezado de autenticación. + +### Limitaciones + +**Limitaciones del Sistema Actual:** +1. **Sin soporte de autenticación:** No se puede conectar a servidores MCP protegidos. +2. **Exposición de seguridad:** Los servidores MCP deben ser accesibles públicamente o utilizar solo seguridad a nivel de red. +3. **Problemas de implementación en producción:** No se pueden seguir las mejores prácticas de seguridad para los puntos finales de la API. + +**Limitaciones de Esta Solución:** +1. **Solo para un único inquilino:** Un token estático por herramienta MCP, compartido entre todos los usuarios. +2. **Sin credenciales por usuario:** No se puede autenticar como diferentes usuarios ni pasar el contexto del usuario. +3. **Sin soporte para múltiples inquilinos:** No se pueden aislar las credenciales por inquilino u organización. +4. **Solo tokens estáticos:** No hay soporte para la renovación, rotación o manejo de la expiración de los tokens. +5. **Autenticación a nivel de servicio:** Autentica el servicio TrustGraph, no a usuarios individuales. +6. **Contexto de seguridad compartido:** Todas las invocaciones de una herramienta MCP utilizan la misma credencial. + +### Aplicabilidad del Caso de Uso + +**✅ Casos de Uso Apropiados:** +Implementaciones de TrustGraph de un solo inquilino. +Autenticación de servicio a servicio (TrustGraph → Servidor MCP). +Entornos de desarrollo y pruebas. +Herramientas MCP internas a las que accede el sistema TrustGraph. +Escenarios en los que todos los usuarios comparten el mismo nivel de acceso a la herramienta MCP. +Credenciales de servicio estáticas y de larga duración. + +**❌ Casos de Uso Inapropiados:** +Sistemas multiusuario que requieren autenticación por usuario. +Implementaciones SaaS multiinquilino con requisitos de aislamiento de inquilinos. +Escenarios de autenticación federada (SSO, OAuth, SAML). +Sistemas que requieren la propagación del contexto del usuario a los servidores MCP. +Entornos que necesitan la renovación dinámica de tokens o tokens de corta duración. +Aplicaciones donde diferentes usuarios necesitan diferentes niveles de permisos. +Requisitos de cumplimiento para registros de auditoría a nivel de usuario. + +**Ejemplo de Escenario Apropiado:** +Una implementación de TrustGraph de una sola organización donde todos los empleados utilizan la misma herramienta MCP interna (por ejemplo, búsqueda de bases de datos de la empresa). El servidor MCP requiere autenticación para evitar el acceso externo, pero todos los usuarios internos tienen el mismo nivel de acceso. + +**Ejemplo de Escenario Inapropiado:** +Una plataforma SaaS multiinquilino de TrustGraph donde el inquilino A y el inquilino B necesitan acceder a sus propios servidores MCP aislados con credenciales separadas. Esta función NO admite la administración de tokens por inquilino. + +### Componentes Relacionados +**trustgraph-flow/trustgraph/agent/mcp_tool/service.py**: Servicio de invocación de la herramienta MCP. +**trustgraph-cli/trustgraph/cli/set_mcp_tool.py**: Herramienta de línea de comandos para crear/actualizar configuraciones de MCP. +**trustgraph-cli/trustgraph/cli/show_mcp_tools.py**: Herramienta de línea de comandos para mostrar configuraciones de MCP. +**SDK de Python para MCP**: `streamablehttp_client` de `mcp.client.streamable_http` + +## Requisitos + +### Requisitos Funcionales + +1. **Token de Autenticación de la Configuración de MCP:** Las configuraciones de la herramienta MCP DEBEN admitir un campo opcional `auth-token`. +2. **Uso del Token Bearer:** El servicio de la herramienta MCP DEBE enviar el encabezado `Authorization: Bearer {token}` cuando se configure un token de autenticación. +3. **Soporte de la CLI:** `tg-set-mcp-tool` DEBE aceptar un parámetro opcional `--auth-token`. +4. **Visualización del Token:** `tg-show-mcp-tools` DEBE indicar cuándo se ha configurado un token de autenticación (enmascarado por motivos de seguridad). +5. **Compatibilidad con versiones anteriores:** Las configuraciones de la herramienta MCP existentes sin un token de autenticación DEBEN seguir funcionando. + +### Requisitos No Funcionales +1. **Compatibilidad con versiones anteriores:** No hay cambios disruptivos para las configuraciones de la herramienta MCP existentes. +2. **Rendimiento:** No hay un impacto significativo en el rendimiento de la invocación de la herramienta MCP. +3. **Seguridad:** Los tokens se almacenan en la configuración (documentar las implicaciones de seguridad). + +### Historias de Usuario + +1. Como **ingeniero de DevOps**, quiero configurar tokens de portador para las herramientas MCP para que pueda asegurar los puntos finales del servidor MCP. +2. Como **usuario de la CLI**, quiero establecer tokens de autenticación al crear herramientas MCP para que pueda conectarme a servidores protegidos. +3. Como **administrador del sistema**, quiero ver qué herramientas MCP tienen la autenticación configurada para que pueda auditar la configuración de seguridad. + +## Diseño + +### Arquitectura de Alto Nivel +Extender la configuración y el servicio de la herramienta MCP para admitir la autenticación con token de portador: +1. Agregar un campo opcional `auth-token` al esquema de configuración de la herramienta MCP. +2. Modificar el servicio de la herramienta MCP para leer el token de autenticación y pasarlo al cliente HTTP. +3. Actualizar las herramientas de la CLI para admitir la configuración y visualización de tokens de autenticación. +4. Documentar las consideraciones de seguridad y las mejores prácticas. + +### Esquema de Configuración + +**Esquema Actual:** +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +**Nuevo Esquema** (con token de autenticación opcional): +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api", + "auth-token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} +``` + +**Descripciones de campos:** +`remote-name` (opcional): Nombre utilizado por el servidor MCP (por defecto, la clave de configuración). +`url` (obligatorio): URL del punto final del servidor MCP. +`auth-token` (opcional): Token de tipo Bearer para la autenticación. + +### Flujo de datos + +1. **Almacenamiento de la configuración:** El usuario ejecuta `tg-set-mcp-tool --id my-tool --tool-url http://server/api --auth-token xyz123`. +2. **Carga de la configuración:** El servicio de la herramienta MCP recibe la actualización de la configuración a través de la devolución de llamada `on_mcp_config()`. +3. **Invocación de la herramienta:** Cuando se invoca la herramienta: + El servicio lee `auth-token` de la configuración (si está presente). + Crea un diccionario de encabezados: `{"Authorization": "Bearer {token}"}`. + Pasa los encabezados a `streamablehttp_client(url, headers=headers)`. + El servidor MCP valida el token y procesa la solicitud. + +### Cambios en la API +No hay cambios en la API externa, solo una extensión del esquema de configuración. + +### Detalles del componente + +#### Componente 1: service.py (Servicio de la herramienta MCP) +**Archivo:** `trustgraph-flow/trustgraph/agent/mcp_tool/service.py` + +**Propósito:** Invocar herramientas MCP en servidores remotos. + +**Cambios requeridos** (en el método `invoke_tool()`): +1. Comprobar si `auth-token` está presente en la configuración `self.mcp_services[name]`. +2. Crear un diccionario de encabezados con el encabezado de autorización si existe un token. +3. Pasar los encabezados a `streamablehttp_client(url, headers=headers)`. + +**Código actual** (líneas 42-89): +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server + async with streamablehttp_client(url) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method +``` + +**Código Modificado**: +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + # Build headers with optional bearer token + headers = {} + if "auth-token" in self.mcp_services[name]: + token = self.mcp_services[name]["auth-token"] + headers["Authorization"] = f"Bearer {token}" + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server with headers + async with streamablehttp_client(url, headers=headers) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method (unchanged) +``` + +#### Componente 2: set_mcp_tool.py (Herramienta de Configuración de Línea de Comandos) +**Archivo**: `trustgraph-cli/trustgraph/cli/set_mcp_tool.py` + +**Propósito**: Crear/actualizar configuraciones de la herramienta MCP. + +**Cambios Requeridos**: +1. Agregar un argumento opcional `--auth-token` a argparse. +2. Incluir `auth-token` en el archivo JSON de configuración cuando se proporciona. + +**Argumentos Actuales**: +`--id` (requerido): Identificador de la herramienta MCP. +`--remote-name` (opcional): Nombre de la herramienta MCP remota. +`--tool-url` (requerido): Punto final de la URL de la herramienta MCP. +`-u, --api-url` (opcional): URL de la API de TrustGraph. + +**Nuevo Argumento**: +`--auth-token` (opcional): Token Bearer para la autenticación. + +**Construcción de Configuración Modificada**: +```python +# Build configuration object +config = { + "url": args.tool_url, +} + +if args.remote_name: + config["remote-name"] = args.remote_name + +if args.auth_token: + config["auth-token"] = args.auth_token + +# Store configuration +api.config().put([ + ConfigValue(type="mcp", key=args.id, value=json.dumps(config)) +]) +``` + +#### Componente 3: show_mcp_tools.py (Herramienta de visualización de línea de comandos) +**Archivo**: `trustgraph-cli/trustgraph/cli/show_mcp_tools.py` + +**Propósito**: Mostrar configuraciones de la herramienta MCP. + +**Cambios requeridos**: +1. Agregar columna "Auth" a la tabla de salida. +2. Mostrar "Sí" o "No" según la presencia de un token de autenticación. +3. No mostrar el valor real del token (seguridad). + +**Salida actual**: +``` +ID Remote Name URL +---------- ------------- ------------------------ +my-tool my-tool http://server:3000/api +``` + +**Nueva Salida**: +``` +ID Remote Name URL Auth +---------- ------------- ------------------------ ------ +my-tool my-tool http://server:3000/api Yes +other-tool other-tool http://other:3000/api No +``` + +#### Componente 4: Documentación +**Archivo**: `docs/cli/tg-set-mcp-tool.md` + +**Cambios Requeridos**: +1. Documentar el nuevo parámetro `--auth-token` +2. Proporcionar un ejemplo de uso con autenticación +3. Documentar las consideraciones de seguridad + +## Plan de Implementación + +### Fase 1: Crear Especificación Técnica +[x] Escribir una especificación técnica completa que documente todos los cambios + +### Fase 2: Actualizar el Servicio MCP Tool +[ ] Modificar `invoke_tool()` en `service.py` para leer el token de autenticación desde la configuración +[ ] Construir un diccionario de encabezados y pasarlo a `streamablehttp_client` +[ ] Probar con un servidor MCP autenticado + +### Fase 3: Actualizar las Herramientas CLI +[ ] Agregar el argumento `--auth-token` a `set_mcp_tool.py` +[ ] Incluir el token de autenticación en la configuración JSON +[ ] Agregar una columna "Auth" a la salida de `show_mcp_tools.py` +[ ] Probar los cambios de la herramienta CLI + +### Fase 4: Actualizar la Documentación +[ ] Documentar el parámetro `--auth-token` en `tg-set-mcp-tool.md` +[ ] Agregar una sección de consideraciones de seguridad +[ ] Proporcionar un ejemplo de uso + +### Fase 5: Pruebas +[ ] Probar que la herramienta MCP se conecta correctamente con el token de autenticación +[ ] Probar la compatibilidad con versiones anteriores (las herramientas sin token de autenticación aún funcionan) +[ ] Probar que las herramientas CLI aceptan y almacenan correctamente el token de autenticación +[ ] Probar que el comando "show" muestra el estado de la autenticación correctamente + +### Resumen de Cambios en el Código +| Archivo | Tipo de Cambio | Líneas | Descripción | +|------|------------|-------|-------------| +| `service.py` | Modificado | ~52-66 | Agregar la lectura del token de autenticación y la construcción de encabezados | +| `set_mcp_tool.py` | Modificado | ~30-60 | Agregar el argumento --auth-token y el almacenamiento en la configuración | +| `show_mcp_tools.py` | Modificado | ~40-70 | Agregar la columna Auth a la visualización | +| `tg-set-mcp-tool.md` | Modificado | Varios | Documentar el nuevo parámetro | + +## Estrategia de Pruebas + +### Pruebas Unitarias +**Lectura del Token de Autenticación**: Probar que `invoke_tool()` lee correctamente el token de autenticación desde la configuración +**Construcción de Encabezados**: Probar que el encabezado de Autorización se construye correctamente con el prefijo Bearer +**Compatibilidad con Versiones Anteriores**: Probar que las herramientas sin token de autenticación funcionan sin cambios +**Análisis de Argumentos de la CLI**: Probar que el argumento `--auth-token` se analiza correctamente + +### Pruebas de Integración +**Conexión Autenticada**: Probar que el servicio de la herramienta MCP se conecta a un servidor autenticado +**De Extremo a Extremo**: Probar el flujo CLI → almacenamiento de configuración → invocación del servicio con el token de autenticación +**Token No Requerido**: Probar que la conexión a un servidor no autenticado aún funciona + +### Pruebas Manuales +**Servidor MCP Real**: Probar con un servidor MCP real que requiere la autenticación con token Bearer +**Flujo de Trabajo de la CLI**: Probar el flujo de trabajo completo: configurar la herramienta con la autenticación → invocar la herramienta → verificar el éxito +**Enmascaramiento de la Autenticación**: Verificar que el estado de la autenticación se muestra, pero el valor del token no se expone + +## Migración e Implementación + +### Estrategia de Migración +No se requiere migración: esta es una funcionalidad puramente adicional: +Las configuraciones existentes de la herramienta MCP que no tienen `auth-token` siguen funcionando sin cambios +Las nuevas configuraciones pueden incluir opcionalmente el campo `auth-token` +Las herramientas CLI aceptan, pero no requieren, el parámetro `--auth-token` + +### Plan de Implementación +1. **Fase 1**: Implementar los cambios principales del servicio en el entorno de desarrollo/pruebas +2. **Fase 2**: Implementar las actualizaciones de las herramientas CLI +3. **Fase 3**: Actualizar la documentación +4. **Fase 4**: Implementación en producción con monitoreo + +### Plan de Reversión +Los cambios principales son compatibles con versiones anteriores: las herramientas existentes no se ven afectadas +Si surgen problemas, el manejo del token de autenticación se puede deshabilitar eliminando la lógica de construcción de encabezados +Los cambios de la CLI son independientes y se pueden revertir por separado + +## Consideraciones de Seguridad + +### ⚠️ Limitación Crítica: Solo Autenticación de Un Solo Inquilino + +**Este mecanismo de autenticación NO es adecuado para entornos multiusuario o multiinquilino.** + +**Credenciales compartidas**: Todos los usuarios e invocaciones comparten el mismo token por herramienta MCP +**Sin contexto de usuario**: El servidor MCP no puede distinguir entre diferentes usuarios de TrustGraph +**Sin aislamiento de inquilinos**: Todos los inquilinos comparten la misma credencial para cada herramienta MCP +**Limitación del registro de auditoría**: El servidor MCP muestra todas las solicitudes de la misma credencial +**Ámbito de permisos**: No se pueden hacer cumplir diferentes niveles de permiso para diferentes usuarios + +**NO use esta función si:** +Su implementación de TrustGraph sirve a múltiples organizaciones (multiinquilino) +Necesita realizar un seguimiento de qué usuario accedió a qué herramienta MCP +Diferentes usuarios requieren diferentes niveles de permiso +Necesita cumplir con los requisitos de auditoría a nivel de usuario +Su servidor MCP aplica límites de velocidad o cuotas por usuario + +**Soluciones alternativas para escenarios multiusuario/multitenant:** +Implementar la propagación del contexto del usuario a través de encabezados personalizados +Implementar instancias de TrustGraph separadas por tenant +Utilizar aislamiento a nivel de red (VPCs, service meshes) +Implementar una capa de proxy que gestione la autenticación por usuario + +### Almacenamiento de tokens +**Riesgo**: Los tokens de autenticación se almacenan en texto plano en el sistema de configuración + +**Mitigación**: +Documentar que los tokens se almacenan sin cifrar +Recomendar el uso de tokens de corta duración siempre que sea posible +Recomendar un control de acceso adecuado en el almacenamiento de la configuración +Considerar una mejora futura para el almacenamiento de tokens cifrados + +### Exposición de tokens +**Riesgo**: Los tokens podrían exponerse en registros o en la salida de la línea de comandos + +**Mitigación**: +No registrar los valores de los tokens (solo registrar "autenticación configurada: sí/no") +El comando "show" de la línea de comandos muestra solo el estado enmascarado, no el token real +No incluir tokens en los mensajes de error + +### Seguridad de la red +**Riesgo**: Los tokens se transmiten a través de conexiones no cifradas + +**Mitigación**: +Documentar la recomendación de utilizar URL HTTPS para los servidores MCP +Advertir a los usuarios sobre el riesgo de transmisión en texto plano con HTTP + +### Acceso a la configuración +**Riesgo**: El acceso no autorizado al sistema de configuración expone los tokens + +**Mitigación**: +Documentar la importancia de asegurar el acceso al sistema de configuración +Recomendar el principio de mínimo privilegio para el acceso a la configuración +Considerar el registro de auditoría para los cambios de configuración (mejora futura) + +### Entornos multiusuario +**Riesgo**: En las implementaciones multiusuario, todos los usuarios comparten las mismas credenciales de MCP + +**Comprensión del riesgo**: +El usuario A y el usuario B utilizan el mismo token al acceder a una herramienta de MCP +El servidor MCP no puede distinguir entre diferentes usuarios de TrustGraph +No hay forma de aplicar permisos o límites de velocidad por usuario +Los registros de auditoría en el servidor MCP muestran todas las solicitudes del mismo identificador +Si la sesión de un usuario se ve comprometida, el atacante tiene el mismo acceso a MCP que todos los usuarios + +**Esto NO es un error; es una limitación fundamental de este diseño.** + +## Impacto en el rendimiento +**Bajo sobrecosto**: La construcción de encabezados agrega un tiempo de procesamiento insignificante +**Impacto en la red**: El encabezado HTTP adicional agrega ~50-200 bytes por solicitud +**Uso de memoria**: Aumento insignificante para almacenar la cadena de token en la configuración + +## Documentación + +### Documentación para el usuario +[ ] Actualizar `tg-set-mcp-tool.md` con el parámetro `--auth-token` +[ ] Agregar una sección de consideraciones de seguridad +[ ] Proporcionar un ejemplo de uso con un token de tipo "bearer" +[ ] Documentar las implicaciones del almacenamiento de tokens + +### Documentación para el desarrollador +[ ] Agregar comentarios en línea para el manejo de tokens de autenticación en `service.py` +[ ] Documentar la lógica de construcción de encabezados +[ ] Actualizar la documentación del esquema de configuración de la herramienta MCP + +## Preguntas abiertas +1. **Cifrado de tokens**: ¿Debemos implementar el almacenamiento de tokens cifrados en el sistema de configuración? +2. **Actualización de tokens**: ¿Soporte futuro para flujos de actualización de OAuth o rotación de tokens? +3. **Métodos de autenticación alternativos**: ¿Debemos admitir la autenticación básica, las claves API u otros métodos? + +## Alternativas consideradas + +1. **Variables de entorno para tokens**: Almacenar tokens en variables de entorno en lugar de en la configuración + **Rechazada**: Complica la implementación y la gestión de la configuración + +2. **Almacén de secretos separado**: Utilizar un sistema de gestión de secretos dedicado + **Aplazada**: Fuera del alcance de la implementación inicial, considerar una mejora futura + +3. **Múltiples métodos de autenticación**: Admitir Basic, API key, OAuth, etc. + **Rechazada**: Los tokens de tipo "bearer" cubren la mayoría de los casos de uso, mantener la implementación inicial simple + +4. **Almacenamiento de tokens cifrado**: Cifrar los tokens en el sistema de configuración + **Aplazada**: La seguridad del sistema de configuración es una preocupación más amplia, posponer a un trabajo futuro + +5. **Tokens por invocación**: Permitir que los tokens se pasen en el momento de la invocación + **Rechazada**: Viola la separación de responsabilidades, el agente no debe manejar las credenciales + +## Referencias +[Especificación del protocolo MCP](https://github.com/modelcontextprotocol/spec) +[Autenticación Bearer HTTP (RFC 6750)](https://tools.ietf.org/html/rfc6750) +[Servicio de la herramienta MCP actual](../trustgraph-flow/trustgraph/agent/mcp_tool/service.py) +[Especificación de argumentos de la herramienta MCP](./mcp-tool-arguments.md) + +## Apéndice + +### Ejemplo de uso + +**Configuración de la herramienta MCP con autenticación:** +```bash +tg-set-mcp-tool \ + --id secure-tool \ + --tool-url https://secure-server.example.com/mcp \ + --auth-token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +``` + +**Mostrando herramientas de MCP:** +```bash +tg-show-mcp-tools + +ID Remote Name URL Auth +----------- ----------- ------------------------------------ ------ +secure-tool secure-tool https://secure-server.example.com/mcp Yes +public-tool public-tool http://localhost:3000/mcp No +``` + +### Ejemplo de configuración + +**Almacenado en el sistema de configuración**: +```json +{ + "type": "mcp", + "key": "secure-tool", + "value": "{\"url\": \"https://secure-server.example.com/mcp\", \"auth-token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\"}" +} +``` + +### Mejores prácticas de seguridad + +1. **Utilice HTTPS**: Siempre utilice URL HTTPS para los servidores MCP con autenticación +2. **Tokens de corta duración**: Utilice tokens con fecha de caducidad siempre que sea posible +3. **Privilegios mínimos**: Conceda a los tokens los permisos mínimos requeridos +4. **Control de acceso**: Restrinja el acceso al sistema de configuración +5. **Rotación de tokens**: Rote los tokens regularmente +6. **Registro de auditoría**: Supervise los cambios de configuración para detectar eventos de seguridad diff --git a/docs/tech-specs/mcp-tool-bearer-token.he.md b/docs/tech-specs/mcp-tool-bearer-token.he.md new file mode 100644 index 00000000..1b695ff8 --- /dev/null +++ b/docs/tech-specs/mcp-tool-bearer-token.he.md @@ -0,0 +1,554 @@ +# מפרט אימות טוקן עבור כלי MCP + +> **⚠️ חשוב: רק עבור סביבות עם משתמש יחיד** +> +> מפרט זה מתאר מנגנון אימות בסיסי ברמת השירות עבור כלי MCP. זה **אינו** פתרון אימות שלם ו**אינו מתאים** עבור: +> - סביבות מרובות משתמשים +> - פריסות מרובות דיירים +> - אימות פדרטיבי +> - העברת הקשר משתמש +> - הרשאה ברמת המשתמש +> +> תכונה זו מספקת **טוקן סטטי אחד לכל כלי MCP**, המשותף לכל המשתמשים והסשנים. אם אתם זקוקים לאימות ברמת המשתמש או הדייר, זו אינה הפתרון הנכון. + +## סקירה כללית +**שם התכונה**: תמיכה באימות טוקן עבור כלי MCP +**כותב**: Claude Code Assistant +**תאריך**: 2025-11-11 +**סטטוס**: בפיתוח + +### תקציר + +אפשר תצורות של כלי MCP לציין טוקנים סטטיים אופציונליים לאימות עם שרתי MCP מוגנים. זה מאפשר ל-TrustGraph להפעיל כלי MCP המאוחסנים בשרתים הדורשים אימות, מבלי לשנות את סוכן או ממשקי הפעלה של הכלי. + +**חשוב**: זוהי מנגנון אימות בסיסי המיועדת לתסריטי אימות בין שירותים בסביבות עם משתמש יחיד. זה **אינו** מתאים עבור: +סביבות מרובות משתמשים שבהן משתמשים שונים צריכים אישורים שונים +פריסות מרובות דיירים הדורשות בידוד לדייר +תרחישי אימות פדרטיביים +אימות או הרשאה ברמת המשתמש +ניהול או רענון אישורים דינמיים + +תכונה זו מספקת טוקן סטטי, ברמת המערכת, עבור כל תצורת כלי MCP, המשותף לכל המשתמשים וההפעלה של כלי זה. + +### הצגת הבעיה + +כיום, כלי MCP יכולים להתחבר רק לשרתי MCP נגישים לציבור. פריסות MCP רבות בייצור דורשות אימות באמצעות טוקנים עבור אבטחה. ללא תמיכה באימות: +כלי MCP לא יכולים להתחבר לשרתי MCP מאובטחים +משתמשים חייבים או לחשוף שרתי MCP לציבור או ליישם שרתי הפוך +אין דרך סטנדרטית להעביר אישורים לחיבורי MCP +לא ניתן לאכוף שיטות עבודה מומלצות לאבטחה בקצוות MCP + +### מטרות + +[ ] לאפשר לתצורות של כלי MCP לציין פרמטר אופציונלי `auth-token` +[ ] לעדכן את שירות כלי MCP כדי להשתמש בטוקנים בעת חיבור לשרתי MCP +[ ] לעדכן כלים בשורת הפקודה לתמיכה בהגדרת/הצגת טוקני אימות +[ ] לשמור על תאימות לאחור עם תצורות MCP ללא אימות +[ ] לתעד שיקולים אבטחתיים עבור אחסון טוקנים + +### לא מטרות +רענון טוקנים דינמי או זרימות OAuth (רק טוקנים סטטיים) +הצפנה של טוקנים המאוחסנים (אבטחת מערכת התצורה אינה בתחום) +שיטות אימות חלופיות (אימות בסיסי, מפתחות API, וכו') +אימות או בדיקת תפוגה של טוקנים +**אימות ברמת המשתמש**: תכונה זו **אינה** תומכת באישורים ספציפיים למשתמש +**בידוד מרובה דיירים**: תכונה זו **אינה** מספקת ניהול טוקנים ברמת הדייר +**אימות פדרטיבי**: תכונה זו **אינה** משתלבת עם ספקי זהות (SSO, OAuth, SAML, וכו') +**אימות מודע הקשר**: טוקנים אינם מועברים בהתבסס על הקשר משתמש או סשן + +## רקע והקשר + +### מצב נוכחי +תצורות של כלי MCP מאוחסנות בקבוצת התצורה `mcp` עם המבנה הבא: +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +שירות הכלי MCP מתחבר לשרתים באמצעות `streamablehttp_client(url)` ללא כותרות אימות. + +### מגבלות + +**מגבלות מערכת נוכחיות:** +1. **ללא תמיכה באימות:** לא ניתן להתחבר לשרתי MCP מאובטחים. +2. **חשיפה אבטחתיות:** שרתי MCP חייבים להיות נגישים לציבור או להשתמש באבטחה ברמת הרשת בלבד. +3. **בעיות פריסה בסביבת ייצור:** לא ניתן לעקוב אחר שיטות עבודה מומלצות לאבטחת נקודות קצה של API. + +**מגבלות של פתרון זה:** +1. **מתאים רק למערכת משתמש יחיד:** טוקן סטטי אחד לכל כלי MCP, משותף לכל המשתמשים. +2. **ללא אישורים מבוססי משתמש:** לא ניתן לאמת כמשתמשים שונים או להעביר הקשר משתמש. +3. **ללא תמיכה בריבוי משתמשים:** לא ניתן לבודד אישורים לפי משתמש או ארגון. +4. **טוקנים סטטיים בלבד:** ללא תמיכה בחידוש טוקנים, רוטציה או טיפול בתפוגה. +5. **אימות ברמת השירות:** מאמת את שירות TrustGraph, ולא משתמשים בודדים. +6. **הקשר אבטחה משותף:** כל שימוש בכלי MCP משתמש באותו אישור. + +### התאמת מקרי שימוש + +**✅ מקרי שימוש מתאימים:** +פריסות TrustGraph עם משתמש יחיד. +אימות בין שירותים (TrustGraph → שרת MCP). +סביבות פיתוח ובדיקה. +כלי MCP פנימיים שאליהם ניגש מערכת TrustGraph. +תרחישים שבהם כל המשתמשים חולקים את אותו רמת גישה לכלי MCP. +אישורים שירותיים סטטיים, בעלי אורך חיים ארוך. + +**❌ מקרי שימוש לא מתאימים:** +מערכות מרובות משתמשים הדורשות אימות מבוסס משתמש. +פריסות SaaS מרובות משתמשים עם דרישות בידוד משתמשים. +תרחישי אימות מאוחדים (SSO, OAuth, SAML). +מערכות הדורשות העברת הקשר משתמש לשרתי MCP. +סביבות הזקוקות לחידוש טוקנים דינמי או טוקנים בעלי אורך חיים קצר. +יישומים שבהם משתמשים שונים צריכים רמות הרשאות שונות. +דרישות תאימות לרישומי ביקורת ברמת המשתמש. + +**תרחיש מתאים לדוגמה:** +פריסה של TrustGraph עבור ארגון יחיד שבהם כל העובדים משתמשים באותו כלי MCP פנימי (לדוגמה, שאילתת מסד נתונים של החברה). שרת ה-MCP דורש אימות כדי למנוע גישה חיצונית, אך לכל המשתמשים הפנימיים יש את אותו רמת גישה. + +**תרחיש לא מתאים לדוגמה:** +פלטפורמת SaaS מרובת משתמשים של TrustGraph שבה כל אחד מ-Tenant A ו-Tenant B צריך לגשת לשרתי MCP מבודדים משלהם עם אישורים נפרדים. תכונה זו אינה תומכת בניהול טוקנים ברמת ה-Tenant. + +### רכיבים קשורים +**trustgraph-flow/trustgraph/agent/mcp_tool/service.py**: שירות הפעלת כלי MCP. +**trustgraph-cli/trustgraph/cli/set_mcp_tool.py**: כלי שורת פקודה ליצירת/עדכון תצורות MCP. +**trustgraph-cli/trustgraph/cli/show_mcp_tools.py**: כלי שורת פקודה להצגת תצורות MCP. +**MCP Python SDK**: `streamablehttp_client` מ- `mcp.client.streamable_http` + +## דרישות + +### דרישות פונקציונליות + +1. **טוקן אימות לתצורה של MCP:** תצורות כלי MCP חייבות לתמוך בשדה אופציונלי `auth-token`. +2. **שימוש בטוקן Bearer:** שירות כלי MCP חייב לשלוח כותרת `Authorization: Bearer {token}` כאשר טוקן אימות מוגדר. +3. **תמיכה בשורת הפקודה:** `tg-set-mcp-tool` חייב לקבל פרמטר אופציונלי `--auth-token`. +4. **הצגת טוקן:** `tg-show-mcp-tools` חייב לציין מתי טוקן אימות מוגדר (מוסתר מטעמי אבטחה). +5. **תאימות לאחור:** תצורות כלי MCP קיימות ללא טוקן אימות חייבות להמשיך לעבוד. + +### דרישות לא פונקציונליות +1. **תאימות לאחור:** ללא שינויים משמעותיים עבור תצורות כלי MCP קיימות. +2. **ביצועים:** ללא השפעה משמעותית על ביצועי הפעלת כלי MCP. +3. **אבטחה:** טוקנים המאוחסנים בתצורה (יש להבין את השלכות האבטחה). + +### סיפורי משתמש + +1. כ-**מהנדס DevOps**, אני רוצה להגדיר טוקני Bearer עבור כלי MCP כך שאוכל לאבטח נקודות קצה של שרתי MCP. +2. כ-**משתמש שורת פקודה**, אני רוצה להגדיר טוקני אימות בעת יצירת כלי MCP כך שאוכל להתחבר לשרתים מוגנים. +3. כ-**מנהל מערכת**, אני רוצה לראות אילו כלי MCP מוגדרים עם אימות כך שאוכל לבדוק הגדרות אבטחה. + +## עיצוב + +### ארכיטקטורה ברמה גבוהה +הרחבת תצורת כלי MCP ושירות כדי לתמוך באימות טוקן Bearer: +1. הוספת שדה אופציונלי `auth-token` לתבנית תצורה של כלי MCP. +2. שנה את שירות הכלי MCP כדי לקרוא את הטוקן האימות ולהעביר אותו ללקוח HTTP. +3. עדכן את כלי שורת הפקודה (CLI) כדי לתמוך בהגדרת והצגת טוקני אימות. +4. תעד שיקולי אבטחה ושיטות עבודה מומלצות. + +### סכימת תצורה + +**הסכימה הנוכחית**: +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +**סכימה חדשה** (עם טוקן אימות אופציונלי): +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api", + "auth-token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} +``` + +**תיאורי שדות**: +`remote-name` (אופציונלי): שם המשמש את שרת ה-MCP (ברירת מחדל היא מפתח התצורה) +`url` (חובה): כתובת URL של נקודת הקצה של שרת ה-MCP +`auth-token` (אופציונלי): טוקן Bearer לאימות + +### זרימת נתונים + +1. **אחסון תצורה**: המשתמש מריץ את `tg-set-mcp-tool --id my-tool --tool-url http://server/api --auth-token xyz123` +2. **טעינת תצורה**: שירות הכלי ה-MCP מקבל עדכון תצורה באמצעות קריאה חוזרת (callback) של `on_mcp_config()` +3. **הפעלת כלי**: כאשר הכלי מופעל: + השירות קורא את `auth-token` מהתצורה (אם קיים) + יוצר מילון כותרות: `{"Authorization": "Bearer {token}"}` + מעביר את הכותרות ל-`streamablehttp_client(url, headers=headers)` + שרת ה-MCP מאמת את הטוקן ומעבד את הבקשה + +### שינויי API +אין שינויי API חיצוניים - רק הרחבת סכימת התצורה. + +### פרטי רכיב + +#### רכיב 1: service.py (שירות כלי MCP) +**קובץ**: `trustgraph-flow/trustgraph/agent/mcp_tool/service.py` + +**מטרה**: הפעלת כלי MCP על שרתים מרוחקים + +**שינויים נדרשים** (בשיטה `invoke_tool()`): +1. בדוק אם קיים `auth-token` בתצורת `self.mcp_services[name]` +2. בנה מילון כותרות עם כותרת Authorization אם קיים טוקן +3. העבר את הכותרות ל-`streamablehttp_client(url, headers=headers)` + +**קוד נוכחי** (שורות 42-89): +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server + async with streamablehttp_client(url) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method +``` + +**קוד שעבר שינוי:** +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + # Build headers with optional bearer token + headers = {} + if "auth-token" in self.mcp_services[name]: + token = self.mcp_services[name]["auth-token"] + headers["Authorization"] = f"Bearer {token}" + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server with headers + async with streamablehttp_client(url, headers=headers) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method (unchanged) +``` + +#### רכיב 2: set_mcp_tool.py (כלי תצורה דרך שורת הפקודה) +**קובץ**: `trustgraph-cli/trustgraph/cli/set_mcp_tool.py` + +**מטרה**: יצירת/עדכון תצורות לכלי MCP + +**שינויים נדרשים**: +1. הוספת ארגומנט אופציונלי `--auth-token` ל-argparse +2. הכללת `auth-token` בקובץ JSON של התצורה כאשר הוא מסופק + +**ארגומנטים נוכחיים**: +`--id` (חובה): מזהה של כלי MCP +`--remote-name` (אופציונלי): שם של כלי MCP מרוחק +`--tool-url` (חובה): נקודת קצה של כתובת URL של כלי MCP +`-u, --api-url` (אופציונלי): כתובת URL של ממשק API של TrustGraph + +**ארגומנט חדש**: +`--auth-token` (אופציונלי): טוקן bearer לאימות + +**שינוי בבניית התצורה**: +```python +# Build configuration object +config = { + "url": args.tool_url, +} + +if args.remote_name: + config["remote-name"] = args.remote_name + +if args.auth_token: + config["auth-token"] = args.auth_token + +# Store configuration +api.config().put([ + ConfigValue(type="mcp", key=args.id, value=json.dumps(config)) +]) +``` + +#### רכיב 3: show_mcp_tools.py (כלי תצוגה בשורת הפקודה) +**קובץ**: `trustgraph-cli/trustgraph/cli/show_mcp_tools.py` + +**מטרה**: הצגת תצורות של כלי MCP + +**שינויים נדרשים**: +1. הוספת עמודה "אימות" (Auth) לטבלת הפלט +2. הצגת "כן" או "לא" בהתאם לנוכחות של טוקן אימות +3. אין להציג את ערך הטוקן בפועל (אבטחה) + +**פלט נוכחי**: +``` +ID Remote Name URL +---------- ------------- ------------------------ +my-tool my-tool http://server:3000/api +``` + +**פלט חדש**: +``` +ID Remote Name URL Auth +---------- ------------- ------------------------ ------ +my-tool my-tool http://server:3000/api Yes +other-tool other-tool http://other:3000/api No +``` + +#### רכיב 4: תיעוד +**קובץ**: `docs/cli/tg-set-mcp-tool.md` + +**שינויים נדרשים**: +1. לתעד את הפרמטר החדש `--auth-token` +2. לספק דוגמה לשימוש עם אימות +3. לתעד שיקולי אבטחה + +## תוכנית יישום + +### שלב 1: יצירת מפרט טכני +[x] לכתוב מפרט טכני מקיף המתעד את כל השינויים + +### שלב 2: עדכון שירות כלי MCP +[ ] לשנות את `invoke_tool()` ב-`service.py` כדי לקרוא את auth-token מקובץ התצורה +[ ] לבנות מילון כותרות ולהעביר ל-`streamablehttp_client` +[ ] לבדוק עם שרת MCP מאומת + +### שלב 3: עדכון כלי שורת הפקודה +[ ] להוסיף את הארגומנט `--auth-token` ל-`set_mcp_tool.py` +[ ] לכלול את auth-token בקובץ JSON של התצורה +[ ] להוסיף עמודה "אימות" לפלט של `show_mcp_tools.py` +[ ] לבדוק את השינויים בכלי שורת הפקודה + +### שלב 4: עדכון תיעוד +[ ] לתעד את הפרמטר `--auth-token` ב-`tg-set-mcp-tool.md` +[ ] להוסיף סעיף של שיקולי אבטחה +[ ] לספק דוגמה לשימוש + +### שלב 5: בדיקות +[ ] לבדוק שכלי ה-MCP מתחבר בהצלחה עם auth-token +[ ] לבדוק תאימות לאחור (כלים ללא auth-token עדיין עובדים) +[ ] לבדוק שכלי שורת הפקודה מקבלים ושומרים את auth-token כראוי +[ ] לבדוק שפקודת ה-show מציגה את סטטוס האימות כראוי + +### סיכום שינויים בקוד +| קובץ | סוג שינוי | שורות | תיאור | +|------|------------|-------|-------------| +| `service.py` | שינוי | ~52-66 | הוספת קריאת auth-token ובניית כותרות | +| `set_mcp_tool.py` | שינוי | ~30-60 | הוספת ארגומנט --auth-token ואחסון בתצורה | +| `show_mcp_tools.py` | שינוי | ~40-70 | הוספת עמודה "אימות" לתצוגה | +| `tg-set-mcp-tool.md` | שינוי | שונות | תיעוד פרמטר חדש | + +## אסטרטגיית בדיקות + +### בדיקות יחידה +**קריאת סיסמת אימות**: לבדוק ש-`invoke_tool()` קורא כראוי את סיסמת האימות מקובץ התצורה +**בניית כותרות**: לבדוק שכותרת ה-Authorization נבנית כראוי עם הקידומת Bearer +**תאימות לאחור**: לבדוק שכלי ללא סיסמת אימות עובדים ללא שינוי +**ניתוח ארגומנטים בשורת הפקודה**: לבדוק שהארגומנט `--auth-token` מנותח כראוי + +### בדיקות אינטגרציה +**חיבור מאומת**: בדיקת חיבור שירות כלי MCP לשרת מאומת +**מקיף (End-to-End)**: בדיקת CLI → אחסון תצורה → הפעלת שירות עם טוקן אימות +**טוקן לא נדרש**: בדיקת חיבור לשרת לא מאומת עדיין עובד + +### בדיקות ידניות +**שרת MCP אמיתי**: בדיקה עם שרת MCP אמיתי הדורש אימות באמצעות טוקן +**זרימת עבודה של CLI**: בדיקת זרימת עבודה מלאה: הגדרת כלי עם אימות → הפעלת כלי → אימות הצלחה +**הסתרת תצוגה**: ודאו שמצב האימות מוצג אך ערך הטוקן אינו נחשף + +## מעבר ושילוב + +### אסטרטגיית מעבר +אין צורך במעבר - זו פונקציונליות נוספת בלבד: +תצורות כלי MCP קיימות ללא `auth-token` ממשיכות לעבוד ללא שינוי +ניתן לכלול את השדה `auth-token` בתצורות חדשות, אופציונלית +כלי CLI מקבלים אך אינם דורשים את הפרמטר `--auth-token` + +### תוכנית שילוב +1. **שלב 1**: פריסת שינויים בסיסיים בשירות לסביבות פיתוח/בדיקות +2. **שלב 2**: פריסת עדכוני כלי CLI +3. **שלב 3**: עדכון תיעוד +4. **שלב 4**: שילוב בסביבת ייצור עם ניטור + +### תוכנית חזרה אחורה +השינויים הבסיסיים תואמים לאחור - כלים קיימים אינם מושפעים +אם מתעוררות בעיות, ניתן להשבית את הטיפול בטוקן אימות על ידי הסרת הלוגיקה לבניית כותרות +שינויים ב-CLI הם עצמאיים וניתן לבטל אותם בנפרד + +## שיקולי אבטחה + +### ⚠️ מגבלה קריטית: אימות רק עבור לקוח יחיד + +**מנגנון אימות זה אינו מתאים לסביבות מרובות משתמשים או מרובות לקוחות.** + +**אישורים משותפים**: כל המשתמשים וההפעלה חולקים את אותו טוקן עבור כל כלי MCP +**ללא הקשר משתמש**: שרת ה-MCP אינו יכול להבחין בין משתמשי TrustGraph שונים +**ללא בידוד לקוחות**: כל הלקוחות חולקים את אותו אישור עבור כל כלי MCP +**מגבלת מעקב**: שרת ה-MCP רושם את כל הבקשות מאותו אישור +**היקף הרשאות**: לא ניתן לאכוף רמות הרשאות שונות עבור משתמשים שונים + +**אל תשתמשו בתכונה זו אם:** +הפריסה של TrustGraph שלכם משרתת מספר ארגונים (מרובת לקוחות) +אתם צריכים לעקוב אילו משתמשים גשו לאילו כלי MCP +משתמשים שונים דורשים רמות הרשאות שונות +אתם צריכים לעמוד בדרישות מעקב ברמת המשתמש +שרת ה-MCP שלכם מאכף מגבלות קצב או מכסות ברמת המשתמש + +**פתרונות חלופיים עבור תרחישי משתמשים/לקוחות מרובים:** +הטמעת העברת הקשר משתמש באמצעות כותרות מותאמות אישית +פריסת מופעי TrustGraph נפרדים עבור כל לקוח +שימוש בבידוד ברמת הרשת (VPCs, רשתות שירות) +הטמעת שכבת פרוקסי המטפלת באימות מבוסס משתמש + +### אחסון טוקנים +**סיכון**: טוקנים של אימות מאוחסנים בטקסט רגיל במערכת התצורה + +**הפחתה**: +תיעוד העובדה שטוקנים מאוחסנים ללא הצפנה +המלצה על שימוש בטוקנים קצרי טווח במידת האפשר +המלצה על בקרת גישה מתאימה לאחסון התצורה +שקילת שיפור עתידי לאחסון מוצפן של טוקנים + +### חשיפת טוקנים +**סיכון**: טוקנים עלולים להיחשף ביומני רישום או בפלט של שורת הפקודה + +**הפחתה**: +אין לרשום ערכי טוקנים (לרשום רק "אימות מוגדר: כן/לא") +פקודת ה-CLI להצגה מציגה סטטוס מוסתר בלבד, ולא את הטוקן בפועל +אין לכלול טוקנים בהודעות שגיאה + +### אבטחת רשת +**סיכון**: טוקנים מועברים על גבי חיבורים לא מוצפנים + +**הפחתה**: +המלצה לשימוש בכתובות URL של HTTPS עבור שרתי MCP +אזהרת משתמשים לגבי סיכון השידור בטקסט רגיל עם HTTP + +### גישה לתצורה +**סיכון**: גישה לא מורשית למערכת התצורה חושפת טוקנים + +**הפחתה**: +תיעוד החשיבות של אבטחת גישה למערכת התצורה +המלצה על עקרון ההרשאה המינימלית לגישה לתצורה +שקילת רישום ביקורת עבור שינויים בתצורה (שיפור עתידי) + +### סביבות מרובות משתמשים +**סיכון**: בסביבות מרובות משתמשים, כל המשתמשים חולקים את אותם פרטי כניסה של MCP + +**הבנת הסיכון**: +משתמש א' ומשתמש ב' משתמשים באותו טוקן בעת גישה לכלי MCP +שרת ה-MCP אינו יכול להבחין בין משתמשי TrustGraph שונים +אין דרך לאכוף הרשאות או מגבלות קצב מבוססות משתמש +יומני רישום בשרת ה-MCP מציגים את כל הבקשות מאותה פרטי כניסה +אם הסשן של משתמש אחד נפגע, לתוקף יש את אותה גישה ל-MCP כמו לכל המשתמשים + +**זהו לא באג - זהו מגבלה יסודית של עיצוב זה.** + +## השפעה על ביצועים +**תקורה מינימלית**: בניית כותרת מוסיפה זמן עיבוד זניח +**השפעה על הרשת**: כותרת HTTP נוספת מוסיפה ~50-200 בתים לכל בקשה +**שימוש בזיכרון**: עלייה זניחה עבור אחסון מחרוזת הטוקן בתצורה + +## תיעוד + +### תיעוד למשתמש +[ ] עדכון `tg-set-mcp-tool.md` עם פרמטר `--auth-token` +[ ] הוספת סעיף שיקולי אבטחה +[ ] מתן דוגמה לשימוש עם טוקן bearer +[ ] תיעוד השלכות אחסון טוקנים + +### תיעוד למפתחים +[ ] הוספת הערות שורה לטיפול בטוקן אימות ב-`service.py` +[ ] תיעוד לוגיקת בניית כותרות +[ ] עדכון תיעוד סכימת התצורה של כלי MCP + +## שאלות פתוחות +1. **הצפנת טוקנים**: האם עלינו ליישם אחסון מוצפן של טוקנים במערכת התצורה? +2. **רענון טוקנים**: תמיכה עתידית בזרמי רענון OAuth או סיבוב טוקנים? +3. **שיטות אימות חלופיות**: האם עלינו לתמוך באימות בסיסי, מפתחות API או שיטות אחרות? + +## חלופות שנשקלו + +1. **משתני סביבה עבור טוקנים**: אחסון טוקנים במשתני סביבה במקום בתצורה + **נדחה**: מסבך פריסה וניהול תצורה + +2. **מאגר סודות נפרד**: שימוש במערכת ניהול סודות ייעודית + **נדחה**: מחוץ להיקף היישום הראשוני, לשקול שיפור עתידי + +3. **שיטות אימות מרובות**: תמיכה בסיסי, מפתח API, OAuth וכו'. + **נדחה**: טוקני bearer מכסים את רוב מקרי השימוש, לשמור על יישום ראשוני פשוט + +4. **אחסון מוצפן של טוקנים**: הצפנת טוקנים במערכת התצורה + **נדחה**: אבטחת מערכת התצורה היא דאגה רחבה יותר, לדחות לעבודה עתידית + +5. **טוקנים לכל קריאה**: לאפשר העברת טוקנים בזמן ההפעלה + **נדחה**: מפר את הפרדת האחריות, סוכן לא צריך לטפל באישורים + +## הפניות +[מפרט פרוטוקול MCP](https://github.com/modelcontextprotocol/spec) +[אימות Bearer HTTP (RFC 6750)](https://tools.ietf.org/html/rfc6750) +[כלי שירות MCP נוכחי](../trustgraph-flow/trustgraph/agent/mcp_tool/service.py) +[מפרט ארגומנטים של כלי MCP](./mcp-tool-arguments.md) + +## נספח + +### שימוש לדוגמה +פלט חוזה (יש לעקוב בדיוק אחר הפורמט הבא). +**הגדרת כלי MCP עם אימות:** +```bash +tg-set-mcp-tool \ + --id secure-tool \ + --tool-url https://secure-server.example.com/mcp \ + --auth-token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +``` + +**הצגת כלי MCP:** +```bash +tg-show-mcp-tools + +ID Remote Name URL Auth +----------- ----------- ------------------------------------ ------ +secure-tool secure-tool https://secure-server.example.com/mcp Yes +public-tool public-tool http://localhost:3000/mcp No +``` + +### דוגמה לתצורה + +**מאוחסן במערכת התצורה:** +```json +{ + "type": "mcp", + "key": "secure-tool", + "value": "{\"url\": \"https://secure-server.example.com/mcp\", \"auth-token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\"}" +} +``` + +### שיטות עבודה מומלצות לאבטחה + +1. **שימוש ב-HTTPS**: השתמשו תמיד בכתובות HTTPS עבור שרתי MCP עם אימות. +2. **אסימונים קצרי טווח**: השתמשו באסימונים עם תאריך תפוגה כאשר אפשר. +3. **הרשאות מינימליות**: העניקו לאסימונים את ההרשאות המינימליות הנדרשות. +4. **בקרת גישה**: הגבילו את הגישה למערכת התצורה. +5. **החלפת אסימונים**: החליפו אסימונים באופן קבוע. +6. **רישום ביקורת**: עקבו אחר שינויים בתצורה לאירועי אבטחה. diff --git a/docs/tech-specs/mcp-tool-bearer-token.hi.md b/docs/tech-specs/mcp-tool-bearer-token.hi.md new file mode 100644 index 00000000..a6c528b2 --- /dev/null +++ b/docs/tech-specs/mcp-tool-bearer-token.hi.md @@ -0,0 +1,554 @@ +# एमसीपी टूल बेयरर टोकन प्रमाणीकरण विनिर्देश + +> **⚠️ महत्वपूर्ण: केवल सिंगल-टेनेन्ट** +> +> यह विनिर्देश एमसीपी टूल के लिए एक **बुनियादी, सेवा-स्तर प्रमाणीकरण तंत्र** का वर्णन करता है। यह एक पूर्ण प्रमाणीकरण समाधान **नहीं** है और यह निम्नलिखित के लिए **उपयुक्त नहीं** है: +> - मल्टी-यूजर वातावरण +> - मल्टी-टेनेन्ट परिनियोजन +> - फेडरेटेड प्रमाणीकरण +> - यूजर संदर्भ का प्रसार +> - प्रति-उपयोगकर्ता प्राधिकरण +> +> यह सुविधा प्रत्येक एमसीपी टूल के लिए **एक स्थिर टोकन** प्रदान करती है, जो सभी उपयोगकर्ताओं और सत्रों में साझा किया जाता है। यदि आपको प्रति-उपयोगकर्ता या प्रति-टेनेन्ट प्रमाणीकरण की आवश्यकता है, तो यह सही समाधान नहीं है। + +## अवलोकन +**सुविधा का नाम**: एमसीपी टूल बेयरर टोकन प्रमाणीकरण समर्थन +**लेखक**: क्लाउड कोड असिस्टेंट +**तिथि**: 2025-11-11 +**स्थिति**: विकास के अधीन + +### कार्यकारी सारांश + +एमसीपी टूल कॉन्फ़िगरेशन को सुरक्षित एमसीपी सर्वरों के साथ प्रमाणीकरण के लिए वैकल्पिक बेयरर टोकन निर्दिष्ट करने की अनुमति दें। यह ट्रस्टग्राफ को उन सर्वरों पर होस्ट किए गए एमसीपी टूल को सुरक्षित रूप से आमंत्रित करने की अनुमति देता है जिनके लिए प्रमाणीकरण की आवश्यकता होती है, एजेंट या टूल इनवोकेशन इंटरफेस को संशोधित किए बिना। + +**महत्वपूर्ण**: यह एक बुनियादी प्रमाणीकरण तंत्र है जिसे सिंगल-टेनेन्ट, सेवा-से-सेवा प्रमाणीकरण परिदृश्यों के लिए डिज़ाइन किया गया है। यह निम्नलिखित के लिए **उपयुक्त नहीं** है: +मल्टी-यूजर वातावरण जहां विभिन्न उपयोगकर्ताओं को अलग-अलग क्रेडेंशियल की आवश्यकता होती है +मल्टी-टेनेन्ट परिनियोजन जिसके लिए प्रति-टेनेन्ट अलगाव की आवश्यकता होती है +फेडरेटेड प्रमाणीकरण परिदृश्य +यूजर-स्तरीय प्रमाणीकरण या प्राधिकरण +गतिशील क्रेडेंशियल प्रबंधन या टोकन रीफ़्रेश + +यह सुविधा प्रत्येक एमसीपी टूल कॉन्फ़िगरेशन के लिए एक स्थिर, सिस्टम-व्यापी बेयरर टोकन प्रदान करती है, जो उस टूल के सभी उपयोगकर्ताओं और इनवोकेशन में साझा किया जाता है। + +### समस्या विवरण + +वर्तमान में, एमसीपी टूल केवल सार्वजनिक रूप से सुलभ एमसीपी सर्वरों से जुड़ सकते हैं। कई उत्पादन एमसीपी परिनियोजन सुरक्षा के लिए बेयरर टोकन के माध्यम से प्रमाणीकरण की आवश्यकता होती है। प्रमाणीकरण समर्थन के बिना: +एमसीपी टूल सुरक्षित एमसीपी सर्वरों से कनेक्ट नहीं हो सकते +उपयोगकर्ताओं को या तो एमसीपी सर्वरों को सार्वजनिक रूप से उजागर करना होगा या रिवर्स प्रॉक्सी लागू करना होगा +एमसीपी कनेक्शनों को क्रेडेंशियल पास करने का कोई मानकीकृत तरीका नहीं है +एमसीपी एंडपॉइंट पर सुरक्षा सर्वोत्तम प्रथाओं को लागू नहीं किया जा सकता है + +### लक्ष्य + +[ ] एमसीपी टूल कॉन्फ़िगरेशन को वैकल्पिक `auth-token` पैरामीटर निर्दिष्ट करने की अनुमति दें +[ ] एमसीपी टूल सेवा को एमसीपी सर्वरों से कनेक्ट करते समय बेयरर टोकन का उपयोग करने के लिए अपडेट करें +[ ] CLI टूल को ऑथ टोकन सेट/डिस्प्ले करने के लिए अपडेट करें +[ ] अप्रामाणित एमसीपी कॉन्फ़िगरेशन के साथ बैकवर्ड संगतता बनाए रखें +[ ] टोकन स्टोरेज के लिए सुरक्षा विचारों का दस्तावेजीकरण करें + +### गैर-लक्ष्य +गतिशील टोकन रीफ़्रेश या OAuth प्रवाह (केवल स्थिर टोकन) +संग्रहीत टोकन का एन्क्रिप्शन (कॉन्फ़िगरेशन सिस्टम सुरक्षा दायरे से बाहर है) +वैकल्पिक प्रमाणीकरण विधियाँ (बेसिक ऑथ, एपीआई कुंजियाँ, आदि) +टोकन सत्यापन या समाप्ति जांच +**प्रति-उपयोगकर्ता प्रमाणीकरण**: यह सुविधा उपयोगकर्ता-विशिष्ट क्रेडेंशियल का समर्थन नहीं करती है +**मल्टी-टेनेन्ट अलगाव**: यह सुविधा प्रति-टेनेन्ट टोकन प्रबंधन प्रदान नहीं करती है +**फेडरेटेड प्रमाणीकरण**: यह सुविधा पहचान प्रदाताओं (एसएसओ, OAuth, SAML, आदि) के साथ एकीकृत नहीं होती है +**संदर्भ-जागरूक प्रमाणीकरण**: टोकन उपयोगकर्ता संदर्भ या सत्र के आधार पर पास नहीं किए जाते हैं + +## पृष्ठभूमि और संदर्भ + +### वर्तमान स्थिति +एमसीपी टूल कॉन्फ़िगरेशन `mcp` कॉन्फ़िगरेशन समूह में इस संरचना के साथ संग्रहीत हैं: +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +MCP टूल सेवा `streamablehttp_client(url)` का उपयोग करके सर्वरों से कनेक्ट होती है, बिना किसी प्रमाणीकरण हेडर के। + +### सीमाएँ + +**वर्तमान सिस्टम सीमाएँ:** +1. **कोई प्रमाणीकरण समर्थन नहीं:** सुरक्षित MCP सर्वरों से कनेक्ट नहीं किया जा सकता। +2. **सुरक्षा जोखिम:** MCP सर्वर सार्वजनिक रूप से सुलभ होने चाहिए या केवल नेटवर्क-स्तरीय सुरक्षा का उपयोग करना चाहिए। +3. **उत्पादन परिनियोजन मुद्दे:** API एंडपॉइंट्स के लिए सुरक्षा सर्वोत्तम प्रथाओं का पालन नहीं किया जा सकता। + +**इस समाधान की सीमाएँ:** +1. **केवल सिंगल-टेनेन्ट:** प्रत्येक MCP टूल के लिए एक स्थिर टोकन, सभी उपयोगकर्ताओं में साझा। +2. **प्रति-उपयोगकर्ता क्रेडेंशियल्स नहीं:** विभिन्न उपयोगकर्ताओं के रूप में प्रमाणीकरण नहीं किया जा सकता या उपयोगकर्ता संदर्भ नहीं भेजा जा सकता। +3. **कोई मल्टी-टेनेन्ट समर्थन नहीं:** क्रेडेंशियल्स को टेनेन्ट या संगठन द्वारा अलग नहीं किया जा सकता। +4. **केवल स्थिर टोकन:** टोकन रीफ़्रेश, रोटेशन या समाप्ति प्रबंधन का कोई समर्थन नहीं। +5. **सेवा-स्तरीय प्रमाणीकरण:** ट्रस्टग्राफ सेवा को प्रमाणित करता है, व्यक्तिगत उपयोगकर्ताओं को नहीं। +6. **साझा सुरक्षा संदर्भ:** MCP टूल के सभी आह्वान एक ही क्रेडेंशियल का उपयोग करते हैं। + +### उपयोग मामला प्रयोज्यता + +**✅ उपयुक्त उपयोग मामले:** +सिंगल-टेनेन्ट ट्रस्टग्राफ परिनियोजन। +सेवा-से-सेवा प्रमाणीकरण (ट्रस्टग्राफ → MCP सर्वर)। +विकास और परीक्षण वातावरण। +ट्रस्टग्राफ सिस्टम द्वारा एक्सेस किए जाने वाले आंतरिक MCP टूल। +ऐसे परिदृश्य जहां सभी उपयोगकर्ताओं के पास MCP टूल तक समान पहुंच स्तर हो। +स्थिर, लंबे समय तक चलने वाले सेवा क्रेडेंशियल्स। + +**❌ अनुपयुक्त उपयोग मामले:** +प्रति-उपयोगकर्ता प्रमाणीकरण की आवश्यकता वाले मल्टी-यूजर सिस्टम। +टेनेन्ट अलगाव आवश्यकताओं वाले मल्टी-टेनेन्ट SaaS परिनियोजन। +फेडरेटेड प्रमाणीकरण परिदृश्य (SSO, OAuth, SAML)। +ऐसे सिस्टम जिनके लिए MCP सर्वरों पर उपयोगकर्ता संदर्भ का प्रसार आवश्यक है। +ऐसे वातावरण जिन्हें गतिशील टोकन रीफ़्रेश या अल्पकालिक टोकन की आवश्यकता होती है। +ऐसे एप्लिकेशन जहां विभिन्न उपयोगकर्ताओं को अलग-अलग अनुमति स्तरों की आवश्यकता होती है। +उपयोगकर्ता-स्तरीय ऑडिट ट्रेल्स के लिए अनुपालन आवश्यकताएं। + +**उदाहरण उपयुक्त परिदृश्य:** +एक सिंगल-संगठन ट्रस्टग्राफ परिनियोजन जहां सभी कर्मचारी एक ही आंतरिक MCP टूल का उपयोग करते हैं (उदाहरण के लिए, कंपनी डेटाबेस लुकअप)। MCP सर्वर को बाहरी पहुंच को रोकने के लिए प्रमाणीकरण की आवश्यकता होती है, लेकिन सभी आंतरिक उपयोगकर्ताओं के पास समान पहुंच स्तर होता है। + +**उदाहरण अनुपयुक्त परिदृश्य:** +एक मल्टी-टेनेन्ट ट्रस्टग्राफ SaaS प्लेटफ़ॉर्म जहां टेनेन्ट A और टेनेन्ट B को अलग-अलग क्रेडेंशियल्स के साथ अपने स्वयं के अलग-अलग MCP सर्वरों तक पहुंचने की आवश्यकता होती है। यह सुविधा प्रति-टेनेन्ट टोकन प्रबंधन का समर्थन नहीं करती है। + +### संबंधित घटक +**trustgraph-flow/trustgraph/agent/mcp_tool/service.py**: MCP टूल इनवोकेशन सेवा। +**trustgraph-cli/trustgraph/cli/set_mcp_tool.py**: MCP कॉन्फ़िगरेशन बनाने/अपडेट करने के लिए CLI टूल। +**trustgraph-cli/trustgraph/cli/show_mcp_tools.py**: MCP कॉन्फ़िगरेशन प्रदर्शित करने के लिए CLI टूल। +**MCP Python SDK**: `streamablehttp_client` from `mcp.client.streamable_http` + +## आवश्यकताएँ + +### कार्यात्मक आवश्यकताएँ + +1. **MCP कॉन्फ़िगरेशन ऑथ टोकन:** MCP टूल कॉन्फ़िगरेशन को एक वैकल्पिक `auth-token` फ़ील्ड का समर्थन करना चाहिए। +2. **बियरर टोकन उपयोग:** MCP टूल सेवा को `Authorization: Bearer {token}` हेडर भेजना चाहिए जब ऑथ-टोकन कॉन्फ़िगर किया गया हो। +3. **CLI समर्थन:** `tg-set-mcp-tool` को एक वैकल्पिक `--auth-token` पैरामीटर स्वीकार करना चाहिए। +4. **टोकन प्रदर्शन:** `tg-show-mcp-tools` को यह इंगित करना चाहिए कि ऑथ-टोकन कॉन्फ़िगर किया गया है (सुरक्षा के लिए मास्क किया गया)। +5. **पिछला अनुकूलता:** ऑथ-टोकन के बिना मौजूदा MCP टूल कॉन्फ़िगरेशन को काम करना जारी रखना चाहिए। + +### गैर-कार्यात्मक आवश्यकताएँ +1. **पिछला अनुकूलता:** मौजूदा MCP टूल कॉन्फ़िगरेशन के लिए कोई ब्रेकिंग परिवर्तन नहीं। +2. **प्रदर्शन:** MCP टूल इनवोकेशन पर कोई महत्वपूर्ण प्रदर्शन प्रभाव नहीं। +3. **सुरक्षा:** कॉन्फ़िगरेशन में संग्रहीत टोकन (सुरक्षा निहितार्थों का दस्तावेजीकरण करें)। + +### उपयोगकर्ता कहानियाँ + +1. एक **DevOps इंजीनियर** के रूप में, मैं MCP टूल के लिए बियरर टोकन कॉन्फ़िगर करना चाहता हूं ताकि मैं MCP सर्वर एंडपॉइंट्स को सुरक्षित कर सकूं। +2. एक **CLI उपयोगकर्ता** के रूप में, मैं MCP टूल बनाते समय ऑथ टोकन सेट करना चाहता हूं ताकि मैं संरक्षित सर्वरों से कनेक्ट कर सकूं। +3. एक **सिस्टम प्रशासक** के रूप में, मैं यह देखना चाहता हूं कि किन MCP टूल में प्रमाणीकरण कॉन्फ़िगर किया गया है ताकि मैं सुरक्षा सेटिंग्स का ऑडिट कर सकूं। + +## डिज़ाइन + +### उच्च-स्तरीय आर्किटेक्चर +MCP टूल कॉन्फ़िगरेशन और सेवा को बियरर टोकन प्रमाणीकरण का समर्थन करने के लिए विस्तारित करें: +1. MCP टूल कॉन्फ़िगरेशन स्कीमा में एक वैकल्पिक `auth-token` फ़ील्ड जोड़ें। +2. MCP टूल सेवा को ऑथ-टोकन पढ़ने और इसे HTTP क्लाइंट को पास करने के लिए संशोधित करें। +3. ऑथ टोकन सेट करने और प्रदर्शित करने के लिए CLI टूल को अपडेट करें। +4. सुरक्षा विचारों और सर्वोत्तम प्रथाओं का दस्तावेजीकरण करें। + +### कॉन्फ़िगरेशन स्कीमा + +**वर्तमान स्कीमा:** +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +**नया स्कीमा** (वैकल्पिक ऑथ-टोकन के साथ): +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api", + "auth-token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} +``` + +**फ़ील्ड विवरण:** +`remote-name` (वैकल्पिक): एमसीपी सर्वर द्वारा उपयोग किया जाने वाला नाम (डिफ़ॉल्ट रूप से कॉन्फ़िगरेशन कुंजी) +`url` (आवश्यक): एमसीपी सर्वर एंडपॉइंट यूआरएल +`auth-token` (वैकल्पिक): प्रमाणीकरण के लिए बेयरर टोकन + +### डेटा प्रवाह + +1. **कॉन्फ़िगरेशन संग्रहण:** उपयोगकर्ता `tg-set-mcp-tool --id my-tool --tool-url http://server/api --auth-token xyz123` चलाता है +2. **कॉन्फ़िगरेशन लोडिंग:** एमसीपी टूल सेवा `on_mcp_config()` कॉलबैक के माध्यम से कॉन्फ़िगरेशन अपडेट प्राप्त करती है +3. **टूल इनवोकेशन:** जब टूल को बुलाया जाता है: + सेवा कॉन्फ़िगरेशन से `auth-token` पढ़ती है (यदि मौजूद है) + हेडर डिक्ट बनाता है: `{"Authorization": "Bearer {token}"}` + हेडर को `streamablehttp_client(url, headers=headers)` में पास करता है + एमसीपी सर्वर टोकन को मान्य करता है और अनुरोध को संसाधित करता है + +### एपीआई परिवर्तन +कोई बाहरी एपीआई परिवर्तन नहीं - केवल कॉन्फ़िगरेशन स्कीमा एक्सटेंशन। + +### घटक विवरण + +#### घटक 1: service.py (एमसीपी टूल सेवा) +**फ़ाइल:** `trustgraph-flow/trustgraph/agent/mcp_tool/service.py` + +**उद्देश्य:** दूरस्थ सर्वरों पर एमसीपी टूल को इनवोक करना + +**आवश्यक परिवर्तन** (`invoke_tool()` विधि में): +1. `self.mcp_services[name]` कॉन्फ़िगरेशन में `auth-token` की जाँच करें +2. यदि टोकन मौजूद है तो ऑथराइजेशन हेडर के साथ हेडर डिक्ट बनाएं +3. हेडर को `streamablehttp_client(url, headers=headers)` में पास करें + +**वर्तमान कोड** (पंक्तियाँ 42-89): +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server + async with streamablehttp_client(url) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method +``` + +**संशोधित कोड:** +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + # Build headers with optional bearer token + headers = {} + if "auth-token" in self.mcp_services[name]: + token = self.mcp_services[name]["auth-token"] + headers["Authorization"] = f"Bearer {token}" + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server with headers + async with streamablehttp_client(url, headers=headers) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method (unchanged) +``` + +#### घटक 2: set_mcp_tool.py (सीएलआई कॉन्फ़िगरेशन टूल) +**फ़ाइल**: `trustgraph-cli/trustgraph/cli/set_mcp_tool.py` + +**उद्देश्य**: एमसीपी टूल कॉन्फ़िगरेशन बनाना/अपडेट करना + +**आवश्यक परिवर्तन**: +1. आर्गुमेंटपार्सर में `--auth-token` वैकल्पिक तर्क जोड़ें +2. प्रदान किए जाने पर कॉन्फ़िगरेशन JSON में `auth-token` शामिल करें + +**वर्तमान तर्क**: +`--id` (आवश्यक): एमसीपी टूल पहचानकर्ता +`--remote-name` (वैकल्पिक): रिमोट एमसीपी टूल नाम +`--tool-url` (आवश्यक): एमसीपी टूल यूआरएल एंडपॉइंट +`-u, --api-url` (वैकल्पिक): ट्रस्टग्राफ एपीआई यूआरएल + +**नया तर्क**: +`--auth-token` (वैकल्पिक): प्रमाणीकरण के लिए बेयरर टोकन + +**संशोधित कॉन्फ़िगरेशन निर्माण**: +```python +# Build configuration object +config = { + "url": args.tool_url, +} + +if args.remote_name: + config["remote-name"] = args.remote_name + +if args.auth_token: + config["auth-token"] = args.auth_token + +# Store configuration +api.config().put([ + ConfigValue(type="mcp", key=args.id, value=json.dumps(config)) +]) +``` + +#### घटक 3: show_mcp_tools.py (सीएलआई डिस्प्ले टूल) +**फ़ाइल**: `trustgraph-cli/trustgraph/cli/show_mcp_tools.py` + +**उद्देश्य**: एमसीपी टूल कॉन्फ़िगरेशन प्रदर्शित करना + +**आवश्यक परिवर्तन**: +1. आउटपुट तालिका में "Auth" कॉलम जोड़ें +2. "हाँ" या "नहीं" प्रदर्शित करें, यह इस आधार पर कि क्या auth-token मौजूद है +3. वास्तविक टोकन मान प्रदर्शित न करें (सुरक्षा) + +**वर्तमान आउटपुट**: +``` +ID Remote Name URL +---------- ------------- ------------------------ +my-tool my-tool http://server:3000/api +``` + +**नया आउटपुट**: +``` +ID Remote Name URL Auth +---------- ------------- ------------------------ ------ +my-tool my-tool http://server:3000/api Yes +other-tool other-tool http://other:3000/api No +``` + +#### घटक 4: दस्तावेज़ +**फ़ाइल**: `docs/cli/tg-set-mcp-tool.md` + +**आवश्यक परिवर्तन**: +1. नए `--auth-token` पैरामीटर का दस्तावेज़ बनाएं +2. प्रमाणीकरण के साथ उपयोग का उदाहरण प्रदान करें +3. सुरक्षा संबंधी विचारों का दस्तावेज़ बनाएं + +## कार्यान्वयन योजना + +### चरण 1: तकनीकी विनिर्देश बनाएं +[x] सभी परिवर्तनों का दस्तावेज़ बनाने वाला व्यापक तकनीकी विनिर्देश लिखें + +### चरण 2: MCP टूल सर्विस को अपडेट करें +[ ] `service.py` में `invoke_tool()` को संशोधित करें ताकि कॉन्फ़िगरेशन से auth-token पढ़ा जा सके +[ ] हेडर डिक्ट बनाएं और इसे `streamablehttp_client` में पास करें +[ ] प्रमाणित MCP सर्वर के साथ परीक्षण करें + +### चरण 3: CLI टूल को अपडेट करें +[ ] `set_mcp_tool.py` में `--auth-token` तर्क जोड़ें +[ ] कॉन्फ़िगरेशन JSON में auth-token शामिल करें +[ ] `show_mcp_tools.py` आउटपुट में "Auth" कॉलम जोड़ें +[ ] CLI टूल परिवर्तनों का परीक्षण करें + +### चरण 4: दस्तावेज़ को अपडेट करें +[ ] `tg-set-mcp-tool.md` में `--auth-token` पैरामीटर का दस्तावेज़ बनाएं +[ ] सुरक्षा संबंधी विचारों का अनुभाग जोड़ें +[ ] उपयोग का उदाहरण प्रदान करें + +### चरण 5: परीक्षण +[ ] MCP टूल auth-token के साथ सफलतापूर्वक कनेक्ट होता है +[ ] पिछड़े अनुकूलता का परीक्षण (auth-token के बिना टूल अभी भी काम करते हैं) +[ ] CLI टूल auth-token को स्वीकार और संग्रहीत करते हैं, इसका परीक्षण करें +[ ] "शो" कमांड auth स्थिति को सही ढंग से प्रदर्शित करता है, इसका परीक्षण करें + +### कोड परिवर्तनों का सारांश +| फ़ाइल | परिवर्तन का प्रकार | पंक्तियाँ | विवरण | +|------|------------|-------|-------------| +| `service.py` | संशोधित | ~52-66 | auth-token पढ़ने और हेडर बनाने के लिए जोड़ा गया | +| `set_mcp_tool.py` | संशोधित | ~30-60 | --auth-token तर्क और कॉन्फ़िगरेशन स्टोरेज जोड़ने के लिए | +| `show_mcp_tools.py` | संशोधित | ~40-70 | प्रदर्शन के लिए Auth कॉलम जोड़ने के लिए | +| `tg-set-mcp-tool.md` | संशोधित | विभिन्न | नए पैरामीटर का दस्तावेज़ बनाने के लिए | + +## परीक्षण रणनीति + +### यूनिट परीक्षण +**ऑथ टोकन रीडिंग**: परीक्षण करें कि `invoke_tool()` कॉन्फ़िगरेशन से auth-token को सही ढंग से पढ़ता है या नहीं +**हेडर बिल्डिंग**: परीक्षण करें कि प्राधिकरण हेडर सही ढंग से Bearer उपसर्ग के साथ बनाया गया है या नहीं +**पिछड़ी अनुकूलता**: परीक्षण करें कि auth-token के बिना टूल अपरिवर्तित रूप से काम करते हैं या नहीं +**CLI तर्क पार्सिंग**: परीक्षण करें कि `--auth-token` तर्क को सही ढंग से पार्स किया गया है या नहीं + +### एकीकरण परीक्षण +**प्रमाणित कनेक्शन**: परीक्षण करें कि MCP टूल सर्विस प्रमाणित सर्वर से कनेक्ट होती है या नहीं +**एंड-टू-एंड**: CLI → कॉन्फ़िगरेशन स्टोरेज → auth टोकन के साथ सेवा इनवोकेशन का परीक्षण करें +**टोकन की आवश्यकता नहीं है**: परीक्षण करें कि अनधिकृत सर्वर से कनेक्शन अभी भी काम करता है या नहीं + +### मैनुअल परीक्षण +**वास्तविक MCP सर्वर**: वास्तविक MCP सर्वर के साथ परीक्षण करें जिसके लिए Bearer टोकन प्रमाणीकरण की आवश्यकता होती है +**CLI वर्कफ़्लो**: परीक्षण करें कि टूल को auth के साथ सेट करें → टूल को इनवोक करें → सफलता की पुष्टि करें +**डिस्प्ले मास्किंग**: सत्यापित करें कि auth स्थिति दिखाई जाती है लेकिन टोकन मान प्रदर्शित नहीं होता है + +## माइग्रेशन और रोलआउट + +### माइग्रेशन रणनीति +माइग्रेशन की आवश्यकता नहीं है - यह विशुद्ध रूप से एक अतिरिक्त कार्यक्षमता है: +`auth-token` के बिना मौजूदा MCP टूल कॉन्फ़िगरेशन अपरिवर्तित रूप से काम करना जारी रखते हैं +नए कॉन्फ़िगरेशन वैकल्पिक रूप से `auth-token` फ़ील्ड शामिल कर सकते हैं +CLI टूल `--auth-token` पैरामीटर को स्वीकार करते हैं लेकिन इसकी आवश्यकता नहीं होती है + +### रोलआउट योजना +1. **चरण 1**: विकास/स्टेजिंग पर मुख्य सेवा परिवर्तनों को तैनात करें +2. **चरण 2**: CLI टूल अपडेट तैनात करें +3. **चरण 3**: दस्तावेज़ को अपडेट करें +4. **चरण 4**: निगरानी के साथ उत्पादन रोलआउट + +### रोलबैक योजना +मुख्य परिवर्तन पिछड़े संगत हैं - मौजूदा टूल अप्रभावित हैं +यदि कोई समस्या उत्पन्न होती है, तो auth-token हैंडलिंग को हेडर बिल्डिंग लॉजिक को हटाकर अक्षम किया जा सकता है +CLI परिवर्तन स्वतंत्र हैं और उन्हें अलग से वापस रोल किया जा सकता है + +## सुरक्षा संबंधी विचार + +### ⚠️ महत्वपूर्ण सीमा: केवल सिंगल-टेनेंट प्रमाणीकरण + +**यह प्रमाणीकरण तंत्र मल्टी-यूजर या मल्टी-टेनेंट वातावरण के लिए उपयुक्त नहीं है।** + +**साझा क्रेडेंशियल**: सभी उपयोगकर्ता और इनवोकेशन प्रत्येक MCP टूल के लिए एक ही टोकन साझा करते हैं +**कोई उपयोगकर्ता संदर्भ नहीं**: MCP सर्वर विभिन्न TrustGraph उपयोगकर्ताओं के बीच अंतर नहीं कर सकता है +**कोई किरायेदार अलगाव नहीं**: सभी किरायेदार प्रत्येक MCP टूल के लिए एक ही क्रेडेंशियल साझा करते हैं +**ऑडिट ट्रेल सीमा**: MCP सर्वर लॉग समान क्रेडेंशियल से सभी अनुरोध दिखाते हैं +**अनुमति दायरा**: विभिन्न उपयोगकर्ताओं के लिए विभिन्न अनुमति स्तरों को लागू नहीं किया जा सकता है + +**इस सुविधा का उपयोग न करें यदि:** +आपका TrustGraph परिनियोजन कई संगठनों (मल्टी-टेनेंट) को सेवा प्रदान करता है +आपको यह ट्रैक करने की आवश्यकता है कि किस उपयोगकर्ता ने किस MCP टूल तक पहुंच की +विभिन्न उपयोगकर्ताओं को विभिन्न अनुमति स्तरों की आवश्यकता होती है +आपको उपयोगकर्ता-स्तरीय ऑडिट आवश्यकताओं का अनुपालन करने की आवश्यकता है +आपका MCP सर्वर प्रति-उपयोगकर्ता दर सीमा या कोटा लागू करता है + +**बहु-उपयोगकर्ता/बहु-किरायेदार परिदृश्यों के लिए वैकल्पिक समाधान:** +कस्टम हेडर के माध्यम से उपयोगकर्ता संदर्भ का प्रचार लागू करें +प्रत्येक किरायेदार के लिए अलग-अलग TrustGraph इंस्टेंस तैनात करें +नेटवर्क-स्तरीय अलगाव का उपयोग करें (वीपीसी, सेवा जाल) +एक प्रॉक्सी परत लागू करें जो प्रति-उपयोगकर्ता प्रमाणीकरण को संभालती है + +### टोकन भंडारण +**जोखिम**: टोकन कॉन्फ़िगरेशन सिस्टम में सादे पाठ में संग्रहीत हैं + +**शमन**: +दस्तावेज़ करें कि टोकन एन्क्रिप्टेड के बिना संग्रहीत हैं +जहां संभव हो, कम अवधि के टोकन का उपयोग करने की अनुशंसा करें +कॉन्फ़िगरेशन भंडारण पर उचित पहुंच नियंत्रण का उपयोग करने की अनुशंसा करें +एन्क्रिप्टेड टोकन भंडारण के लिए भविष्य के सुधार पर विचार करें + +### टोकन एक्सपोजर +**जोखिम**: टोकन लॉग या CLI आउटपुट में उजागर हो सकते हैं + +**शमन**: +टोकन मानों को लॉग न करें (केवल "auth कॉन्फ़िगर किया गया: हाँ/नहीं" लॉग करें) +CLI शो कमांड केवल मास्क की स्थिति प्रदर्शित करता है, वास्तविक टोकन नहीं +त्रुटि संदेशों में टोकन शामिल न करें + +### नेटवर्क सुरक्षा +**जोखिम**: टोकन एन्क्रिप्टेड कनेक्शन पर प्रसारित होते हैं + +**शमन**: +MCP सर्वरों के लिए HTTPS URL का उपयोग करने की अनुशंसा करने वाला दस्तावेज़ +HTTP के साथ प्लेनटेक्स्ट ट्रांसमिशन जोखिम के बारे में उपयोगकर्ताओं को चेतावनी दें + +### कॉन्फ़िगरेशन एक्सेस +**जोखिम**: कॉन्फ़िगरेशन सिस्टम तक अनधिकृत पहुंच टोकन को उजागर करती है + +**शमन**: +कॉन्फ़िगरेशन सिस्टम एक्सेस को सुरक्षित करने के महत्व का दस्तावेज़ करें +कॉन्फ़िगरेशन एक्सेस के लिए न्यूनतम विशेषाधिकार के सिद्धांत की अनुशंसा करें +कॉन्फ़िगरेशन परिवर्तनों के लिए ऑडिट लॉगिंग पर विचार करें (भविष्य का सुधार) + +### बहु-उपयोगकर्ता वातावरण +**जोखिम**: बहु-उपयोगकर्ता परिनियोजन में, सभी उपयोगकर्ता समान MCP क्रेडेंशियल्स साझा करते हैं + +**जोखिम को समझना**: +उपयोगकर्ता ए और उपयोगकर्ता बी दोनों एक ही टोकन का उपयोग MCP टूल तक पहुंचने के लिए करते हैं +MCP सर्वर विभिन्न TrustGraph उपयोगकर्ताओं के बीच अंतर नहीं कर सकता है +प्रति-उपयोगकर्ता अनुमतियों या दर सीमाओं को लागू करने का कोई तरीका नहीं है +MCP सर्वर पर ऑडिट लॉग समान क्रेडेंशियल से सभी अनुरोध दिखाते हैं +यदि एक उपयोगकर्ता का सत्र समझौता किया जाता है, तो हमलावर के पास सभी उपयोगकर्ताओं के समान MCP एक्सेस होता है + +**यह कोई बग नहीं है - यह इस डिज़ाइन की एक मूलभूत सीमा है।** + +## प्रदर्शन प्रभाव +**न्यूनतम ओवरहेड**: हेडर निर्माण में नगण्य प्रसंस्करण समय लगता है +**नेटवर्क प्रभाव**: अतिरिक्त HTTP हेडर प्रति अनुरोध लगभग 50-200 बाइट जोड़ता है +**मेमोरी उपयोग**: कॉन्फ़िगरेशन में टोकन स्ट्रिंग को संग्रहीत करने के लिए नगण्य वृद्धि + +## दस्तावेज़ + +### उपयोगकर्ता दस्तावेज़ +[ ] `tg-set-mcp-tool.md` को `--auth-token` पैरामीटर के साथ अपडेट करें +[ ] सुरक्षा विचारों अनुभाग जोड़ें +[ ] बेयरर टोकन के साथ उपयोग के उदाहरण प्रदान करें +[ ] टोकन भंडारण निहितार्थों का दस्तावेज़ करें + +### डेवलपर दस्तावेज़ +[ ] `service.py` में auth टोकन हैंडलिंग के लिए इनलाइन टिप्पणियाँ जोड़ें +[ ] हेडर निर्माण तर्क का दस्तावेज़ करें +[ ] MCP टूल कॉन्फ़िगरेशन स्कीमा दस्तावेज़ को अपडेट करें + +## खुले प्रश्न +1. **टोकन एन्क्रिप्शन**: क्या हमें कॉन्फ़िगरेशन सिस्टम में एन्क्रिप्टेड टोकन भंडारण लागू करना चाहिए? +2. **टोकन रिफ्रेश**: OAuth रिफ्रेश प्रवाह या टोकन रोटेशन के लिए भविष्य का समर्थन? +3. **वैकल्पिक auth विधियाँ**: क्या हमें बेसिक auth, API कुंजियाँ, या अन्य विधियों का समर्थन करना चाहिए? + +## विचारे गए विकल्प + +1. **टोकन के लिए पर्यावरण चर**: कॉन्फ़िगरेशन के बजाय env चर में टोकन संग्रहीत करें + **अस्वीकृत**: परिनियोजन और कॉन्फ़िगरेशन प्रबंधन को जटिल बनाता है + +2. **अलग सीक्रेट स्टोर**: समर्पित सीक्रेट प्रबंधन प्रणाली का उपयोग करें + **स्थगित**: प्रारंभिक कार्यान्वयन के लिए दायरे से बाहर, भविष्य के सुधार पर विचार करें + +3. **एकाधिक auth विधियाँ**: बेसिक, API कुंजी, OAuth, आदि का समर्थन करें + **अस्वीकृत**: बेयरर टोकन अधिकांश उपयोग मामलों को कवर करते हैं, प्रारंभिक कार्यान्वयन को सरल रखें + +4. **एन्क्रिप्टेड टोकन भंडारण**: कॉन्फ़िगरेशन सिस्टम में टोकन एन्क्रिप्ट करें + **स्थगित**: कॉन्फ़िगरेशन सिस्टम सुरक्षा एक व्यापक चिंता है, भविष्य के कार्य पर स्थगित करें + +5. **प्रति-आवाहन टोकन**: टोकन को आह्वान के समय पास करने की अनुमति दें + **अस्वीकृत**: अलगाव के सिद्धांतों का उल्लंघन करता है, एजेंट को क्रेडेंशियल्स को संभालने में नहीं होना चाहिए + +## संदर्भ +[MCP प्रोटोकॉल विनिर्देश](https://github.com/modelcontextprotocol/spec) +[HTTP बेयरर प्रमाणीकरण (RFC 6750)](https://tools.ietf.org/html/rfc6750) +[वर्तमान MCP टूल सेवा](../trustgraph-flow/trustgraph/agent/mcp_tool/service.py) +[MCP टूल तर्क विनिर्देश](./mcp-tool-arguments.md) + +## परिशिष्ट + +### उपयोग उदाहरण + +**एमसीपी टूल को प्रमाणीकरण के साथ स्थापित करना**: +```bash +tg-set-mcp-tool \ + --id secure-tool \ + --tool-url https://secure-server.example.com/mcp \ + --auth-token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +``` + +**एमसीपी उपकरणों को प्रदर्शित करना**: +```bash +tg-show-mcp-tools + +ID Remote Name URL Auth +----------- ----------- ------------------------------------ ------ +secure-tool secure-tool https://secure-server.example.com/mcp Yes +public-tool public-tool http://localhost:3000/mcp No +``` + +### कॉन्फ़िगरेशन का उदाहरण + +**कॉन्फ़िगरेशन प्रणाली में संग्रहीत**: +```json +{ + "type": "mcp", + "key": "secure-tool", + "value": "{\"url\": \"https://secure-server.example.com/mcp\", \"auth-token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\"}" +} +``` + +### सुरक्षा सर्वोत्तम अभ्यास + +1. **HTTPS का उपयोग करें**: प्रमाणीकरण वाले MCP सर्वरों के लिए हमेशा HTTPS URL का उपयोग करें। +2. **अल्पकालिक टोकन**: जहां संभव हो, समाप्ति तिथि वाले टोकन का उपयोग करें। +3. **न्यूनतम विशेषाधिकार**: टोकन को आवश्यक न्यूनतम अनुमतियाँ प्रदान करें। +4. **पहुंच नियंत्रण**: कॉन्फ़िगरेशन सिस्टम तक पहुंच को प्रतिबंधित करें। +5. **टोकन रोटेशन**: टोकन को नियमित रूप से बदलें। +6. **ऑडिट लॉगिंग**: सुरक्षा घटनाओं के लिए कॉन्फ़िगरेशन परिवर्तनों की निगरानी करें। diff --git a/docs/tech-specs/mcp-tool-bearer-token.pt.md b/docs/tech-specs/mcp-tool-bearer-token.pt.md new file mode 100644 index 00000000..0eff93a1 --- /dev/null +++ b/docs/tech-specs/mcp-tool-bearer-token.pt.md @@ -0,0 +1,554 @@ +# Especificação de Autenticação de Token Bearer para Ferramentas MCP + +> **⚠️ IMPORTANTE: APENAS PARA AMBIENTES DE ÚNICO LOCATÁRIO** +> +> Esta especificação descreve um mecanismo de autenticação básico, de nível de serviço, para ferramentas MCP. Não é uma solução de autenticação completa e não é adequada para: +> - Ambientes multiusuário +> - Implantações multi-tenant +> - Autenticação federada +> - Propagação do contexto do usuário +> - Autorização por usuário +> +> Este recurso fornece **um token estático por ferramenta MCP**, compartilhado entre todos os usuários e sessões. Se você precisar de autenticação por usuário ou por tenant, esta não é a solução certa. + +## Visão Geral +**Nome do Recurso**: Suporte para Autenticação de Token Bearer para Ferramentas MCP +**Autor**: Claude Code Assistant +**Data**: 2025-11-11 +**Status**: Em Desenvolvimento + +### Resumo Executivo + +Permite que as configurações de ferramentas MCP especifiquem tokens bearer opcionais para autenticar com servidores MCP protegidos. Isso permite que o TrustGraph invoque ferramentas MCP hospedadas em servidores que exigem autenticação, sem modificar as interfaces de invocação de agentes ou ferramentas. + +**IMPORTANTE**: Este é um mecanismo de autenticação básico projetado para cenários de autenticação de serviço para serviço, de único tenant. Não é adequado para: +Ambientes multiusuário onde diferentes usuários precisam de credenciais diferentes +Implantações multi-tenant que requerem isolamento por tenant +Cenários de autenticação federada +Autenticação ou autorização em nível de usuário +Gerenciamento de credenciais dinâmico ou atualização de tokens + +Este recurso fornece um token bearer estático e de sistema amplo por configuração de ferramenta MCP, compartilhado entre todos os usuários e invocações dessa ferramenta. + +### Declaração do Problema + +Atualmente, as ferramentas MCP só podem se conectar a servidores MCP acessíveis publicamente. Muitas implantações de produção de MCP exigem autenticação por meio de tokens bearer para segurança. Sem suporte de autenticação: +As ferramentas MCP não podem se conectar a servidores MCP protegidos +Os usuários devem expor servidores MCP publicamente ou implementar proxies reversos +Não há uma maneira padronizada de passar credenciais para conexões MCP +As melhores práticas de segurança não podem ser aplicadas aos endpoints MCP + +### Objetivos + +[ ] Permitir que as configurações de ferramentas MCP especifiquem um parâmetro opcional `auth-token` +[ ] Atualizar o serviço de ferramenta MCP para usar tokens bearer ao se conectar a servidores MCP +[ ] Atualizar as ferramentas de linha de comando para suportar a configuração/exibição de tokens de autenticação +[ ] Manter a compatibilidade com versões anteriores com configurações MCP sem autenticação +[ ] Documentar as considerações de segurança para o armazenamento de tokens + +### Não Objetivos +Atualização dinâmica de tokens ou fluxos OAuth (apenas tokens estáticos) +Criptografia de tokens armazenados (a segurança do sistema de configuração está fora do escopo) +Métodos de autenticação alternativos (autenticação básica, chaves de API, etc.) +Validação ou verificação de expiração de tokens +**Autenticação por usuário**: Este recurso NÃO suporta credenciais específicas do usuário +**Isolamento multi-tenant**: Este recurso NÃO fornece gerenciamento de tokens por tenant +**Autenticação federada**: Este recurso NÃO se integra com provedores de identidade (SSO, OAuth, SAML, etc.) +**Autenticação com contexto**: Os tokens não são passados com base no contexto do usuário ou na sessão + +## Contexto e Informações Adicionais + +### Estado Atual +As configurações de ferramentas MCP são armazenadas no grupo de configuração `mcp` com esta estrutura: +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +O serviço da ferramenta MCP conecta-se a servidores usando `streamablehttp_client(url)` sem nenhum cabeçalho de autenticação. + +### Limitações + +**Limitações do Sistema Atual:** +1. **Sem suporte para autenticação**: Não é possível conectar-se a servidores MCP protegidos. +2. **Exposição de segurança**: Os servidores MCP devem ser acessíveis publicamente ou usar apenas segurança em nível de rede. +3. **Problemas de implantação em produção**: Não é possível seguir as melhores práticas de segurança para endpoints de API. + +**Limitações desta Solução:** +1. **Apenas para um único tenant**: Um token estático por ferramenta MCP, compartilhado entre todos os usuários. +2. **Sem credenciais por usuário**: Não é possível autenticar-se como diferentes usuários ou passar o contexto do usuário. +3. **Sem suporte para multi-tenant**: Não é possível isolar as credenciais por tenant ou organização. +4. **Apenas tokens estáticos**: Sem suporte para atualização, rotação ou tratamento de expiração de tokens. +5. **Autenticação em nível de serviço**: Autentica o serviço TrustGraph, não usuários individuais. +6. **Contexto de segurança compartilhado**: Todas as invocações de uma ferramenta MCP usam a mesma credencial. + +### Aplicabilidade do Caso de Uso + +**✅ Casos de Uso Adequados:** +Implantações TrustGraph de um único tenant. +Autenticação de serviço para serviço (TrustGraph → Servidor MCP). +Ambientes de desenvolvimento e teste. +Ferramentas MCP internas acessadas pelo sistema TrustGraph. +Cenários em que todos os usuários compartilham o mesmo nível de acesso à ferramenta MCP. +Credenciais de serviço estáticas e de longa duração. + +**❌ Casos de Uso Inadequados:** +Sistemas multiusuário que requerem autenticação por usuário. +Implantações SaaS multi-tenant com requisitos de isolamento de tenant. +Cenários de autenticação federada (SSO, OAuth, SAML). +Sistemas que requerem a propagação do contexto do usuário para os servidores MCP. +Ambientes que precisam de atualização dinâmica de tokens ou tokens de curta duração. +Aplicações em que diferentes usuários precisam de diferentes níveis de permissão. +Requisitos de conformidade para rastreamento de auditoria em nível de usuário. + +**Exemplo de Cenário Adequado:** +Uma implantação TrustGraph de uma única organização em que todos os funcionários usam a mesma ferramenta MCP interna (por exemplo, consulta de banco de dados da empresa). O servidor MCP requer autenticação para evitar acesso externo, mas todos os usuários internos têm o mesmo nível de acesso. + +**Exemplo de Cenário Inadequado:** +Uma plataforma SaaS TrustGraph multi-tenant em que o Tenant A e o Tenant B precisam acessar seus próprios servidores MCP isolados com credenciais separadas. Este recurso NÃO suporta o gerenciamento de tokens por tenant. + +### Componentes Relacionados +**trustgraph-flow/trustgraph/agent/mcp_tool/service.py**: Serviço de invocação da ferramenta MCP. +**trustgraph-cli/trustgraph/cli/set_mcp_tool.py**: Ferramenta de linha de comando para criar/atualizar configurações de MCP. +**trustgraph-cli/trustgraph/cli/show_mcp_tools.py**: Ferramenta de linha de comando para exibir configurações de MCP. +**SDK Python para MCP**: `streamablehttp_client` de `mcp.client.streamable_http` + +## Requisitos + +### Requisitos Funcionais + +1. **Token de Autenticação da Configuração MCP**: As configurações da ferramenta MCP DEVEM suportar um campo opcional `auth-token`. +2. **Uso do Token Bearer**: O serviço da ferramenta MCP DEVE enviar o cabeçalho `Authorization: Bearer {token}` quando um token de autenticação estiver configurado. +3. **Suporte da CLI**: `tg-set-mcp-tool` DEVE aceitar um parâmetro opcional `--auth-token`. +4. **Exibição do Token**: `tg-show-mcp-tools` DEVE indicar quando um token de autenticação está configurado (mascarado por segurança). +5. **Compatibilidade com versões anteriores**: As configurações de ferramentas MCP existentes sem token de autenticação DEVEM continuar a funcionar. + +### Requisitos Não Funcionais +1. **Compatibilidade com versões anteriores**: Nenhuma alteração disruptiva para as configurações de ferramentas MCP existentes. +2. **Desempenho**: Nenhum impacto significativo no desempenho da invocação da ferramenta MCP. +3. **Segurança**: Tokens armazenados na configuração (documentar as implicações de segurança). + +### Histórias de Usuário + +1. Como um **engenheiro de DevOps**, quero configurar tokens bearer para ferramentas MCP para que eu possa proteger os endpoints do servidor MCP. +2. Como um **usuário da CLI**, quero definir tokens de autenticação ao criar ferramentas MCP para que eu possa conectar-me a servidores protegidos. +3. Como um **administrador do sistema**, quero ver quais ferramentas MCP têm a autenticação configurada para que eu possa auditar as configurações de segurança. + +## Design + +### Arquitetura de Alto Nível +Estender a configuração e o serviço da ferramenta MCP para suportar a autenticação por token bearer: +1. Adicionar um campo opcional `auth-token` ao esquema de configuração da ferramenta MCP. +2. Modificar o serviço da ferramenta MCP para ler o token de autenticação e passá-lo para o cliente HTTP. +3. Atualizar as ferramentas da CLI para suportar a definição e a exibição de tokens de autenticação. +4. Documentar as considerações de segurança e as melhores práticas. + +### Esquema de Configuração + +**Esquema Atual**: +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +**Novo Esquema** (com token de autenticação opcional): +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api", + "auth-token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} +``` + +**Descrições dos Campos**: +`remote-name` (opcional): Nome usado pelo servidor MCP (o padrão é a chave de configuração). +`url` (obrigatório): URL do endpoint do servidor MCP. +`auth-token` (opcional): Token Bearer para autenticação. + +### Fluxo de Dados + +1. **Armazenamento de Configuração**: O usuário executa `tg-set-mcp-tool --id my-tool --tool-url http://server/api --auth-token xyz123`. +2. **Carregamento da Configuração**: O serviço da ferramenta MCP recebe a atualização da configuração via callback `on_mcp_config()`. +3. **Invocar a Ferramenta**: Quando a ferramenta é invocada: + O serviço lê `auth-token` da configuração (se presente). + Cria um dicionário de cabeçalhos: `{"Authorization": "Bearer {token}"}`. + Passa os cabeçalhos para `streamablehttp_client(url, headers=headers)`. + O servidor MCP valida o token e processa a solicitação. + +### Alterações na API +Nenhuma alteração na API externa - apenas extensão do esquema de configuração. + +### Detalhes do Componente + +#### Componente 1: service.py (Serviço da Ferramenta MCP) +**Arquivo**: `trustgraph-flow/trustgraph/agent/mcp_tool/service.py` + +**Propósito**: Invocar ferramentas MCP em servidores remotos. + +**Alterações Necessárias** (no método `invoke_tool()`): +1. Verificar se `auth-token` está presente em `self.mcp_services[name]` config. +2. Criar um dicionário de cabeçalhos com o cabeçalho Authorization, se o token existir. +3. Passar os cabeçalhos para `streamablehttp_client(url, headers=headers)`. + +**Código Atual** (linhas 42-89): +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server + async with streamablehttp_client(url) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method +``` + +**Código Modificado**: +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + # Build headers with optional bearer token + headers = {} + if "auth-token" in self.mcp_services[name]: + token = self.mcp_services[name]["auth-token"] + headers["Authorization"] = f"Bearer {token}" + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server with headers + async with streamablehttp_client(url, headers=headers) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method (unchanged) +``` + +#### Componente 2: set_mcp_tool.py (Ferramenta de Configuração de Linha de Comando) +**Arquivo**: `trustgraph-cli/trustgraph/cli/set_mcp_tool.py` + +**Propósito**: Criar/atualizar configurações da ferramenta MCP + +**Alterações Necessárias**: +1. Adicionar argumento opcional `--auth-token` a argparse +2. Incluir `auth-token` na configuração JSON quando fornecido + +**Argumentos Atuais**: +`--id` (obrigatório): Identificador da ferramenta MCP +`--remote-name` (opcional): Nome da ferramenta MCP remota +`--tool-url` (obrigatório): Endpoint da URL da ferramenta MCP +`-u, --api-url` (opcional): URL da API TrustGraph + +**Novo Argumento**: +`--auth-token` (opcional): Token Bearer para autenticação + +**Construção de Configuração Modificada**: +```python +# Build configuration object +config = { + "url": args.tool_url, +} + +if args.remote_name: + config["remote-name"] = args.remote_name + +if args.auth_token: + config["auth-token"] = args.auth_token + +# Store configuration +api.config().put([ + ConfigValue(type="mcp", key=args.id, value=json.dumps(config)) +]) +``` + +#### Componente 3: show_mcp_tools.py (Ferramenta de Exibição de Linha de Comando) +**Arquivo**: `trustgraph-cli/trustgraph/cli/show_mcp_tools.py` + +**Propósito**: Exibir configurações da ferramenta MCP + +**Alterações Necessárias**: +1. Adicionar coluna "Auth" à tabela de saída +2. Exibir "Sim" ou "Não" com base na presença de auth-token +3. Não exibir o valor real do token (segurança) + +**Saída Atual**: +``` +ID Remote Name URL +---------- ------------- ------------------------ +my-tool my-tool http://server:3000/api +``` + +**Nova Saída**: +``` +ID Remote Name URL Auth +---------- ------------- ------------------------ ------ +my-tool my-tool http://server:3000/api Yes +other-tool other-tool http://other:3000/api No +``` + +#### Componente 4: Documentação +**Arquivo**: `docs/cli/tg-set-mcp-tool.md` + +**Alterações Necessárias**: +1. Documentar o novo parâmetro `--auth-token` +2. Fornecer um exemplo de uso com autenticação +3. Documentar as considerações de segurança + +## Plano de Implementação + +### Fase 1: Criar Especificação Técnica +[x] Escrever uma especificação técnica abrangente documentando todas as alterações + +### Fase 2: Atualizar o Serviço MCP Tool +[ ] Modificar `invoke_tool()` em `service.py` para ler o token de autenticação da configuração +[ ] Criar um dicionário de cabeçalhos e passá-lo para `streamablehttp_client` +[ ] Testar com um servidor MCP autenticado + +### Fase 3: Atualizar as Ferramentas CLI +[ ] Adicionar o argumento `--auth-token` a `set_mcp_tool.py` +[ ] Incluir o token de autenticação no arquivo de configuração JSON +[ ] Adicionar a coluna "Auth" à saída de `show_mcp_tools.py` +[ ] Testar as alterações nas ferramentas CLI + +### Fase 4: Atualizar a Documentação +[ ] Documentar o parâmetro `--auth-token` em `tg-set-mcp-tool.md` +[ ] Adicionar uma seção de considerações de segurança +[ ] Fornecer um exemplo de uso + +### Fase 5: Testes +[ ] Testar se a ferramenta MCP se conecta com sucesso usando o token de autenticação +[ ] Testar a compatibilidade com versões anteriores (ferramentas sem token de autenticação ainda funcionam) +[ ] Testar se as ferramentas CLI aceitam e armazenam corretamente o token de autenticação +[ ] Testar se o comando "show" exibe o status de autenticação corretamente + +### Resumo das Alterações no Código +| Arquivo | Tipo de Alteração | Linhas | Descrição | +|------|------------|-------|-------------| +| `service.py` | Modificado | ~52-66 | Adicionar leitura do token de autenticação e construção de cabeçalhos | +| `set_mcp_tool.py` | Modificado | ~30-60 | Adicionar argumento --auth-token e armazenamento na configuração | +| `show_mcp_tools.py` | Modificado | ~40-70 | Adicionar coluna Auth à exibição | +| `tg-set-mcp-tool.md` | Modificado | Várias | Documentar novo parâmetro | + +## Estratégia de Testes + +### Testes Unitários +**Leitura do Token de Autenticação**: Testar se `invoke_tool()` lê corretamente o token de autenticação da configuração +**Construção de Cabeçalhos**: Testar se o cabeçalho de Autorização é construído corretamente com o prefixo Bearer +**Compatibilidade com Versões Anteriores**: Testar se as ferramentas sem token de autenticação funcionam inalteradas +**Análise de Argumentos da CLI**: Testar se o argumento `--auth-token` é analisado corretamente + +### Testes de Integração +**Conexão Autenticada**: Testar se o serviço da ferramenta MCP se conecta a um servidor autenticado +**Teste de Ponta a Ponta**: Testar o fluxo da CLI → armazenamento na configuração → invocação do serviço com o token de autenticação +**Token Não Necessário**: Testar a conexão com um servidor não autenticado ainda funciona + +### Testes Manuais +**Servidor MCP Real**: Testar com um servidor MCP real que requer autenticação com token Bearer +**Fluxo de Trabalho da CLI**: Testar o fluxo de trabalho completo: configurar a ferramenta com autenticação → invocar a ferramenta → verificar o sucesso +**Mascaramento de Autenticação**: Verificar se o status de autenticação é exibido, mas o valor do token não é exposto + +## Migração e Implantação + +### Estratégia de Migração +Não é necessária migração - esta é uma funcionalidade puramente adicional: +As configurações existentes da ferramenta MCP sem `auth-token` continuam a funcionar inalteradas +Novas configurações podem incluir opcionalmente o campo `auth-token` +As ferramentas CLI aceitam, mas não exigem o parâmetro `--auth-token` + +### Plano de Implantação +1. **Fase 1**: Implantar as alterações principais do serviço no desenvolvimento/ambiente de teste +2. **Fase 2**: Implantar as atualizações das ferramentas CLI +3. **Fase 3**: Atualizar a documentação +4. **Fase 4**: Implantação em produção com monitoramento + +### Plano de Reversão +As alterações principais são compatíveis com versões anteriores - as ferramentas existentes não são afetadas +Se surgirem problemas, o tratamento do token de autenticação pode ser desativado removendo a lógica de construção de cabeçalhos +As alterações da CLI são independentes e podem ser revertidas separadamente + +## Considerações de Segurança + +### ⚠️ Limitação Crítica: Apenas Autenticação para um Único Inquilino + +**Este mecanismo de autenticação NÃO é adequado para ambientes multiusuário ou multi-inquilino.** + +**Credenciais compartilhadas**: Todos os usuários e invocações compartilham o mesmo token por ferramenta MCP +**Sem contexto de usuário**: O servidor MCP não pode distinguir entre diferentes usuários do TrustGraph +**Sem isolamento de inquilino**: Todos os inquilinos compartilham a mesma credencial para cada ferramenta MCP +**Limitação do registro de auditoria**: O servidor MCP registra todas as solicitações da mesma credencial +**Escopo de permissão**: Não é possível impor diferentes níveis de permissão para diferentes usuários + +**NÃO use este recurso se:** +Seu deployment do TrustGraph atende a várias organizações (multi-inquilino) +Você precisa rastrear qual usuário acessou qual ferramenta MCP +Diferentes usuários precisam de diferentes níveis de permissão +Você precisa cumprir requisitos de auditoria em nível de usuário +Seu servidor MCP impõe limites de taxa ou cotas por usuário + +**Soluções alternativas para cenários multiusuário/multilocatário:** +Implementar a propagação do contexto do usuário por meio de cabeçalhos personalizados +Implantar instâncias separadas do TrustGraph por locatário +Usar isolamento em nível de rede (VPCs, malhas de serviço) +Implementar uma camada de proxy que lida com a autenticação por usuário + +### Armazenamento de Tokens +**Risco**: Tokens de autenticação armazenados em texto simples no sistema de configuração + +**Mitigação**: +Documentar que os tokens são armazenados sem criptografia +Recomendar o uso de tokens de curta duração sempre que possível +Recomendar controles de acesso adequados no armazenamento de configuração +Considerar uma melhoria futura para o armazenamento de tokens criptografados + +### Exposição de Tokens +**Risco**: Tokens podem ser expostos em logs ou na saída da linha de comando + +**Mitigação**: +Não registrar os valores dos tokens (registrar apenas "autenticação configurada: sim/não") +O comando de exibição da linha de comando mostra apenas o status mascarado, não o token real +Não incluir tokens em mensagens de erro + +### Segurança da Rede +**Risco**: Tokens transmitidos por conexões não criptografadas + +**Mitigação**: +Documentar a recomendação de usar URLs HTTPS para servidores MCP +Alertar os usuários sobre o risco de transmissão em texto simples com HTTP + +### Acesso à Configuração +**Risco**: Acesso não autorizado ao sistema de configuração expõe tokens + +**Mitigação**: +Documentar a importância de proteger o acesso ao sistema de configuração +Recomendar o princípio do menor privilégio para o acesso à configuração +Considerar o registro de auditoria para alterações na configuração (melhoria futura) + +### Ambientes Multiusuário +**Risco**: Em implantações multiusuário, todos os usuários compartilham as mesmas credenciais do MCP + +**Entendendo o Risco**: +O usuário A e o usuário B usam o mesmo token ao acessar uma ferramenta MCP +O servidor MCP não consegue distinguir entre diferentes usuários do TrustGraph +Não há como impor permissões ou limites de taxa por usuário +Os logs de auditoria no servidor MCP mostram todos os pedidos da mesma credencial +Se a sessão de um usuário for comprometida, o invasor terá o mesmo acesso ao MCP que todos os usuários + +**Isso NÃO é um bug - é uma limitação fundamental deste design.** + +## Impacto no Desempenho +**Sobrecarga mínima**: A construção do cabeçalho adiciona um tempo de processamento insignificante +**Impacto na rede**: O cabeçalho HTTP adicional adiciona ~50-200 bytes por solicitação +**Uso de memória**: Aumento insignificante para armazenar a string do token na configuração + +## Documentação + +### Documentação do Usuário +[ ] Atualizar `tg-set-mcp-tool.md` com o parâmetro `--auth-token` +[ ] Adicionar seção de considerações de segurança +[ ] Fornecer exemplo de uso com token de portador +[ ] Documentar as implicações do armazenamento de tokens + +### Documentação para Desenvolvedores +[ ] Adicionar comentários inline para o tratamento de tokens de autenticação em `service.py` +[ ] Documentar a lógica de construção de cabeçalhos +[ ] Atualizar a documentação do esquema de configuração da ferramenta MCP + +## Perguntas Abertas +1. **Criptografia de tokens**: Devemos implementar o armazenamento de tokens criptografados no sistema de configuração? +2. **Atualização de tokens**: Suporte futuro para fluxos de atualização OAuth ou rotação de tokens? +3. **Métodos de autenticação alternativos**: Devemos suportar autenticação básica, chaves de API ou outros métodos? + +## Alternativas Consideradas + +1. **Variáveis de ambiente para tokens**: Armazenar tokens em variáveis de ambiente em vez de configuração + **Rejeitado**: Complica o gerenciamento de implantação e configuração + +2. **Armazenamento de segredos separado**: Usar um sistema dedicado de gerenciamento de segredos + **Adiado**: Fora do escopo da implementação inicial, considerar uma melhoria futura + +3. **Múltiplos métodos de autenticação**: Suportar Basic, API key, OAuth, etc. + **Rejeitado**: Tokens de portador cobrem a maioria dos casos de uso, manter a implementação inicial simples + +4. **Armazenamento de tokens criptografado**: Criptografar tokens no sistema de configuração + **Adiado**: A segurança do sistema de configuração é uma preocupação mais ampla, adiar para trabalhos futuros + +5. **Tokens por invocação**: Permitir que os tokens sejam passados no momento da invocação + **Rejeitado**: Viola a separação de responsabilidades, o agente não deve lidar com credenciais + +## Referências +[Especificação do Protocolo MCP](https://github.com/modelcontextprotocol/spec) +[Autenticação Bearer HTTP (RFC 6750)](https://tools.ietf.org/html/rfc6750) +[Serviço da Ferramenta MCP Atual](../trustgraph-flow/trustgraph/agent/mcp_tool/service.py) +[Especificação de Argumentos da Ferramenta MCP](./mcp-tool-arguments.md) + +## Apêndice + +### Exemplo de Uso + +**Configuração da ferramenta MCP com autenticação**: +```bash +tg-set-mcp-tool \ + --id secure-tool \ + --tool-url https://secure-server.example.com/mcp \ + --auth-token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +``` + +**Exibindo ferramentas MCP:** +```bash +tg-show-mcp-tools + +ID Remote Name URL Auth +----------- ----------- ------------------------------------ ------ +secure-tool secure-tool https://secure-server.example.com/mcp Yes +public-tool public-tool http://localhost:3000/mcp No +``` + +### Exemplo de Configuração + +**Armazenado no sistema de configuração**: +```json +{ + "type": "mcp", + "key": "secure-tool", + "value": "{\"url\": \"https://secure-server.example.com/mcp\", \"auth-token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\"}" +} +``` + +### Melhores Práticas de Segurança + +1. **Use HTTPS**: Utilize sempre URLs HTTPS para servidores MCP com autenticação. +2. **Tokens de curta duração**: Utilize tokens com data de expiração sempre que possível. +3. **Privilégios mínimos**: Conceda aos tokens as permissões mínimas necessárias. +4. **Controle de acesso**: Restrinja o acesso ao sistema de configuração. +5. **Rotação de tokens**: Rotacione os tokens regularmente. +6. **Registro de auditoria**: Monitore as alterações de configuração para eventos de segurança. diff --git a/docs/tech-specs/mcp-tool-bearer-token.ru.md b/docs/tech-specs/mcp-tool-bearer-token.ru.md new file mode 100644 index 00000000..44ad85c2 --- /dev/null +++ b/docs/tech-specs/mcp-tool-bearer-token.ru.md @@ -0,0 +1,554 @@ +# Спецификация аутентификации токенов Bearer для инструментов MCP + +> **⚠️ ВАЖНО: ТОЛЬКО ДЛЯ ОДНОГО АРЕНДАТОРА** +> +> Эта спецификация описывает **базовый механизм аутентификации на уровне сервиса** для инструментов MCP. Это **НЕ** полное решение для аутентификации и **НЕ подходит** для: +> - Многопользовательских сред +> - Многоарендных развертываний +> - Федеративной аутентификации +> - Распространения контекста пользователя +> - Авторизации на уровне пользователя +> +> Эта функция предоставляет **один статический токен для каждого инструмента MCP**, который используется всеми пользователями и сеансами. Если вам требуется аутентификация на уровне пользователя или арендатора, это не подходящее решение. + +## Обзор +**Название функции**: Поддержка аутентификации токенов Bearer для инструментов MCP +**Автор**: Claude Code Assistant +**Дата**: 2025-11-11 +**Статус**: В разработке + +### Краткое описание + +Позволяет конфигурациям инструментов MCP указывать необязательные токены Bearer для аутентификации с защищенными серверами MCP. Это позволяет TrustGraph безопасно вызывать инструменты MCP, размещенные на серверах, требующих аутентификации, без изменения интерфейсов агента или вызова инструментов. + +**ВАЖНО**: Это базовый механизм аутентификации, предназначенный для сценариев аутентификации от сервиса к сервису в одноарендной среде. Он **НЕ подходит** для: +Многопользовательских сред, где разные пользователи нуждаются в разных учетных данных +Многоарендных развертываний, требующих изоляции на уровне арендатора +Сценариев федеративной аутентификации +Аутентификации или авторизации на уровне пользователя +Динамического управления учетными данными или обновления токенов + +Эта функция предоставляет статический, системный токен Bearer для каждой конфигурации инструмента MCP, который используется всеми пользователями и вызовами этого инструмента. + +### Описание проблемы + +В настоящее время инструменты MCP могут подключаться только к общедоступным серверам MCP. Многие производственные развертывания MCP требуют аутентификации с помощью токенов Bearer для обеспечения безопасности. Без поддержки аутентификации: +Инструменты MCP не могут подключаться к защищенным серверам MCP +Пользователям приходится либо предоставлять доступ к серверам MCP в общедоступном режиме, либо использовать обратные прокси +Нет стандартизированного способа передачи учетных данных для подключений MCP +Невозможно применять лучшие практики безопасности к конечным точкам MCP + +### Цели + +[ ] Разрешить конфигурациям инструментов MCP указывать необязательный параметр `auth-token` +[ ] Обновить сервис инструмента MCP для использования токенов Bearer при подключении к серверам MCP +[ ] Обновить инструменты командной строки для поддержки установки/отображения токенов аутентификации +[ ] Сохранить обратную совместимость с конфигурациями MCP без аутентификации +[ ] Задокументировать соображения безопасности для хранения токенов + +### Не включено +Динамическое обновление токенов или потоки OAuth (только статические токены) +Шифрование хранимых токенов (безопасность системы конфигураций не входит в область) +Альтернативные методы аутентификации (базовая аутентификация, ключи API и т. д.) +Проверка срока действия или истечения срока действия токенов +**Аутентификация на уровне пользователя**: Эта функция **НЕ поддерживает** учетные данные, специфичные для пользователя +**Изоляция на уровне арендатора**: Эта функция **НЕ предоставляет** управление токенами на уровне арендатора +**Федеративная аутентификация**: Эта функция **НЕ интегрируется** с поставщиками идентификации (SSO, OAuth, SAML и т. д.) +**Аутентификация, зависящая от контекста**: Токены не передаются на основе контекста пользователя или сеанса + +## Предыстория и контекст + +### Текущее состояние +Конфигурации инструментов MCP хранятся в группе конфигураций `mcp` со следующей структурой: +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +Сервис инструмента MCP подключается к серверам, используя `streamablehttp_client(url)`, без каких-либо заголовков аутентификации. + +### Ограничения + +**Текущие ограничения системы:** +1. **Отсутствие поддержки аутентификации:** Невозможно подключиться к защищенным серверам MCP. +2. **Риски безопасности:** Серверы MCP должны быть общедоступными или использовать только сетевую безопасность. +3. **Проблемы при развертывании в производственной среде:** Невозможно соблюдать лучшие практики безопасности для API-интерфейсов. + +**Ограничения данного решения:** +1. **Только для однопользовательской системы:** Один статический токен для каждого инструмента MCP, общий для всех пользователей. +2. **Отсутствие учетных данных для каждого пользователя:** Невозможно аутентифицироваться как разные пользователи или передавать контекст пользователя. +3. **Отсутствие поддержки многопользовательской системы:** Невозможно изолировать учетные данные по арендатору или организации. +4. **Только статические токены:** Нет поддержки обновления, ротации или обработки истечения срока действия токенов. +5. **Аутентификация на уровне сервиса:** Аутентифицируется сервис TrustGraph, а не отдельные пользователи. +6. **Общий контекст безопасности:** Все вызовы инструмента MCP используют одни и те же учетные данные. + +### Область применения + +**✅ Подходящие сценарии использования:** +Развертывания TrustGraph для одного арендатора. +Аутентификация от сервиса к сервису (TrustGraph → MCP Server). +Среды разработки и тестирования. +Внутренние инструменты MCP, доступные системе TrustGraph. +Сценарии, в которых все пользователи имеют одинаковый уровень доступа к инструменту MCP. +Статические, долгоживущие учетные данные сервиса. + +**❌ Неподходящие сценарии использования:** +Системы с несколькими пользователями, требующие аутентификацию для каждого пользователя. +Многопользовательские SaaS-платформы с требованиями к изоляции арендаторов. +Сценарии федеративной аутентификации (SSO, OAuth, SAML). +Системы, требующие передачу контекста пользователя на серверы MCP. +Среды, требующие динамическое обновление токенов или короткоживущие токены. +Приложения, в которых разные пользователи должны иметь разные уровни разрешений. +Требования соответствия для аудиторских журналов на уровне пользователя. + +**Пример подходящего сценария:** +Развертывание TrustGraph для одной организации, в котором все сотрудники используют один и тот же внутренний инструмент MCP (например, поиск информации в корпоративной базе данных). Сервер MCP требует аутентификации для предотвращения внешнего доступа, но все внутренние пользователи имеют одинаковый уровень доступа. + +**Пример неподходящего сценария:** +Многопользовательская SaaS-платформа TrustGraph, в которой арендатор A и арендатор B должны получать доступ к своим собственным изолированным серверам MCP с отдельными учетными данными. Эта функция НЕ поддерживает управление токенами на уровне арендатора. + +### Связанные компоненты +**trustgraph-flow/trustgraph/agent/mcp_tool/service.py**: Сервис вызова инструмента MCP. +**trustgraph-cli/trustgraph/cli/set_mcp_tool.py**: Инструмент командной строки для создания/обновления конфигураций MCP. +**trustgraph-cli/trustgraph/cli/show_mcp_tools.py**: Инструмент командной строки для отображения конфигураций MCP. +**MCP Python SDK**: `streamablehttp_client` из `mcp.client.streamable_http`. + +## Требования + +### Функциональные требования + +1. **Токен аутентификации для конфигурации MCP:** Конфигурации инструмента MCP ДОЛЖНЫ поддерживать необязательное поле `auth-token`. +2. **Использование токена Bearer:** Сервис инструмента MCP ДОЛЖЕН отправлять заголовок `Authorization: Bearer {token}` при настройке аутентификации. +3. **Поддержка CLI:** `tg-set-mcp-tool` ДОЛЖЕН принимать необязательный параметр `--auth-token`. +4. **Отображение токена:** `tg-show-mcp-tools` ДОЛЖЕН указывать, когда настроена аутентификация (маскируется для безопасности). +5. **Обратная совместимость:** Существующие конфигурации инструмента MCP без аутентификации ДОЛЖНЫ продолжать работать. + +### Нефункциональные требования +1. **Обратная совместимость:** Отсутствие изменений, нарушающих работу существующих конфигураций инструмента MCP. +2. **Производительность:** Отсутствие значительного влияния на производительность вызова инструмента MCP. +3. **Безопасность:** Токены хранятся в конфигурации (учитывайте последствия для безопасности). + +### Пользовательские истории + +1. Как **инженеру DevOps**, я хочу настроить токены Bearer для инструментов MCP, чтобы я мог защитить конечные точки серверов MCP. +2. Как **пользователю CLI**, я хочу устанавливать токены аутентификации при создании инструментов MCP, чтобы я мог подключаться к защищенным серверам. +3. Как **системному администратору**, я хочу видеть, какие инструменты MCP имеют настроенную аутентификацию, чтобы я мог проверять настройки безопасности. + +## Проектирование + +### Архитектура высокого уровня +Расширение конфигурации и сервиса инструмента MCP для поддержки аутентификации с помощью токена Bearer: +1. Добавление необязательного поля `auth-token` в схему конфигурации инструмента MCP. +2. Изменение сервиса инструмента MCP для чтения токена аутентификации и передачи его в HTTP-клиент. +3. Обновление инструментов командной строки для поддержки установки и отображения токенов аутентификации. +4. Документирование соображений безопасности и лучших практик. + +### Схема конфигурации + +**Текущая схема:** +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +**Новая схема** (с необязательным токеном авторизации): +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api", + "auth-token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} +``` + +**Описание полей**: +`remote-name` (необязательно): Имя, используемое сервером MCP (по умолчанию - ключ конфигурации). +`url` (обязательно): URL-адрес конечной точки сервера MCP. +`auth-token` (необязательно): Токен для аутентификации. + +### Поток данных + +1. **Хранение конфигурации**: Пользователь запускает `tg-set-mcp-tool --id my-tool --tool-url http://server/api --auth-token xyz123`. +2. **Загрузка конфигурации**: Сервис инструмента MCP получает обновление конфигурации через обратный вызов `on_mcp_config()`. +3. **Вызов инструмента**: Когда инструмент вызывается: + Сервис считывает `auth-token` из конфигурации (если он присутствует). + Создает словарь заголовков: `{"Authorization": "Bearer {token}"}`. + Передает заголовки в `streamablehttp_client(url, headers=headers)`. + Сервер MCP проверяет токен и обрабатывает запрос. + +### Изменения API +Отсутствуют внешние изменения API - только расширение схемы конфигурации. + +### Детали компонента + +#### Компонент 1: service.py (Сервис инструмента MCP) +**Файл**: `trustgraph-flow/trustgraph/agent/mcp_tool/service.py`. + +**Назначение**: Вызов инструментов MCP на удаленных серверах. + +**Необходимые изменения** (в методе `invoke_tool()`): +1. Проверить наличие `auth-token` в конфигурации `self.mcp_services[name]`. +2. Создать словарь заголовков с заголовком Authorization, если токен существует. +3. Передать заголовки в `streamablehttp_client(url, headers=headers)`. + +**Текущий код** (строки 42-89): +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server + async with streamablehttp_client(url) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method +``` + +**Измененный код**: +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + # Build headers with optional bearer token + headers = {} + if "auth-token" in self.mcp_services[name]: + token = self.mcp_services[name]["auth-token"] + headers["Authorization"] = f"Bearer {token}" + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server with headers + async with streamablehttp_client(url, headers=headers) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method (unchanged) +``` + +#### Компонент 2: set_mcp_tool.py (Инструмент конфигурации командной строки) +**Файл**: `trustgraph-cli/trustgraph/cli/set_mcp_tool.py` + +**Назначение**: Создание/обновление конфигураций инструмента MCP. + +**Необходимые изменения**: +1. Добавить необязательный аргумент `--auth-token` в argparse. +2. Включить `auth-token` в конфигурационный JSON, если он предоставлен. + +**Текущие аргументы**: +`--id` (обязательный): Идентификатор инструмента MCP. +`--remote-name` (необязательный): Удаленное имя инструмента MCP. +`--tool-url` (обязательный): URL-адрес конечной точки инструмента MCP. +`-u, --api-url` (необязательный): URL-адрес API TrustGraph. + +**Новый аргумент**: +`--auth-token` (необязательный): Токен Bearer для аутентификации. + +**Измененное построение конфигурации**: +```python +# Build configuration object +config = { + "url": args.tool_url, +} + +if args.remote_name: + config["remote-name"] = args.remote_name + +if args.auth_token: + config["auth-token"] = args.auth_token + +# Store configuration +api.config().put([ + ConfigValue(type="mcp", key=args.id, value=json.dumps(config)) +]) +``` + +#### Компонент 3: show_mcp_tools.py (Инструмент отображения командной строки) +**Файл**: `trustgraph-cli/trustgraph/cli/show_mcp_tools.py` + +**Назначение**: Отображение конфигураций инструмента MCP. + +**Необходимые изменения**: +1. Добавить столбец "Auth" в таблицу вывода. +2. Отображать "Да" или "Нет" в зависимости от наличия auth-токена. +3. Не отображать фактическое значение токена (безопасность). + +**Текущий вывод**: +``` +ID Remote Name URL +---------- ------------- ------------------------ +my-tool my-tool http://server:3000/api +``` + +**Новый вывод**: +``` +ID Remote Name URL Auth +---------- ------------- ------------------------ ------ +my-tool my-tool http://server:3000/api Yes +other-tool other-tool http://other:3000/api No +``` + +#### Компонент 4: Документация +**Файл**: `docs/cli/tg-set-mcp-tool.md` + +**Необходимые изменения**: +1. Документировать новый параметр `--auth-token` +2. Предоставить пример использования с аутентификацией +3. Документировать соображения безопасности + +## План реализации + +### Фаза 1: Создание технической спецификации +[x] Написать подробную техническую спецификацию, документирующую все изменения + +### Фаза 2: Обновление сервиса MCP Tool +[ ] Изменить `invoke_tool()` в `service.py` для чтения auth-token из конфигурации +[ ] Создать словарь заголовков и передать его в `streamablehttp_client` +[ ] Протестировать с аутентифицированным сервером MCP + +### Фаза 3: Обновление инструментов командной строки +[ ] Добавить аргумент `--auth-token` в `set_mcp_tool.py` +[ ] Включить auth-token в конфигурационный JSON +[ ] Добавить столбец "Auth" в вывод `show_mcp_tools.py` +[ ] Протестировать изменения в инструментах командной строки + +### Фаза 4: Обновление документации +[ ] Документировать параметр `--auth-token` в `tg-set-mcp-tool.md` +[ ] Добавить раздел "Соображения безопасности" +[ ] Предоставить пример использования + +### Фаза 5: Тестирование +[ ] Проверить, что сервис MCP tool успешно подключается с использованием auth-token +[ ] Проверить обратную совместимость (инструменты без auth-token по-прежнему работают) +[ ] Проверить, что инструменты командной строки правильно принимают и сохраняют auth-token +[ ] Проверить, что команда "show" правильно отображает статус аутентификации + +### Краткое описание изменений в коде +| Файл | Тип изменения | Строки | Описание | +|------|------------|-------|-------------| +| `service.py` | Изменено | ~52-66 | Добавлено чтение auth-token и построение заголовков | +| `set_mcp_tool.py` | Изменено | ~30-60 | Добавлен аргумент --auth-token и хранение в конфигурации | +| `show_mcp_tools.py` | Изменено | ~40-70 | Добавлен столбец Auth в отображение | +| `tg-set-mcp-tool.md` | Изменено | Различные | Документирован новый параметр | + +## Стратегия тестирования + +### Юнит-тесты +**Чтение токена аутентификации**: Проверить, что `invoke_tool()` правильно считывает auth-token из конфигурации +**Построение заголовков**: Проверить, что заголовок Authorization строится правильно с префиксом Bearer +**Обратная совместимость**: Проверить, что инструменты без auth-token работают без изменений +**Разбор аргументов командной строки**: Проверить, что аргумент `--auth-token` разбирается правильно + +### Интеграционные тесты +**Аутентифицированное подключение**: Проверить, что сервис MCP tool подключается к аутентифицированному серверу +**Комплексное тестирование**: Проверить взаимодействие командной строки → хранилище конфигурации → вызов сервиса с auth token +**Подключение без токена**: Проверить, что подключение к неаутентифицированному серверу по-прежнему работает + +### Ручное тестирование +**Реальный сервер MCP**: Проверить с фактическим сервером MCP, требующим аутентификацию с использованием токена bearer +**Рабочий процесс командной строки**: Проверить полный рабочий процесс: настройка инструмента с auth → вызов инструмента → проверка успешного выполнения +**Маскировка отображения**: Убедиться, что статус аутентификации отображается, но значение токена не отображается + +## Миграция и развертывание + +### Стратегия миграции +Миграция не требуется - это чисто дополнительная функциональность: +Существующие конфигурации MCP tool без `auth-token` продолжают работать без изменений +Новые конфигурации могут опционально включать поле `auth-token` +Инструменты командной строки принимают, но не требуют параметр `--auth-token` + +### План развертывания +1. **Фаза 1**: Развернуть основные изменения сервиса в среде разработки/тестирования +2. **Фаза 2**: Развернуть обновления инструментов командной строки +3. **Фаза 3**: Обновить документацию +4. **Фаза 4**: Развертывание в производственной среде с мониторингом + +### План отката +Основные изменения обратно совместимы - существующие инструменты не затронуты +В случае возникновения проблем обработку auth-token можно отключить, удалив логику построения заголовков +Изменения в инструментах командной строки являются независимыми и могут быть отменены отдельно + +## Соображения безопасности + +### ⚠️ Критическое ограничение: Поддержка только однопользовательской аутентификации + +**Этот механизм аутентификации НЕ подходит для многопользовательских или многопользовательских сред.** + +**Общие учетные данные**: Все пользователи и вызовы используют один и тот же токен для каждого инструмента MCP +**Отсутствие контекста пользователя**: Сервер MCP не может различать разных пользователей TrustGraph +**Отсутствие изоляции арендаторов**: Все арендаторы используют одни и те же учетные данные для каждого инструмента MCP +**Ограничение журнала аудита**: Сервер MCP отображает все запросы от одних и тех же учетных данных +**Область разрешений**: Невозможно применять разные уровни разрешений для разных пользователей + +**Не используйте эту функцию, если:** +Ваша развертка TrustGraph обслуживает несколько организаций (многопользовательская среда) +Вам необходимо отслеживать, какой пользователь получил доступ к какому инструменту MCP +Разным пользователям требуются разные уровни разрешений +Вам необходимо соблюдать требования аудита на уровне пользователей +Ваш сервер MCP применяет ограничения скорости или квоты на уровне пользователя + +**Альтернативные решения для сценариев с несколькими пользователями/многопользовательской средой:** +Реализовать распространение контекста пользователя через пользовательские заголовки +Развернуть отдельные экземпляры TrustGraph для каждого арендатора +Использовать сетевую изоляцию (VPCs, service meshes) +Реализовать прокси-слой, который обрабатывает аутентификацию для каждого пользователя + +### Хранение токенов +**Риск**: Токены аутентификации хранятся в открытом виде в системе конфигурации + +**Меры по снижению риска**: +Задокументировать, что токены хранятся без шифрования +Рекомендовать использовать токены с коротким сроком действия, когда это возможно +Рекомендовать надлежащий контроль доступа к хранилищу конфигурации +Рассмотреть возможность будущей реализации для зашифрованного хранения токенов + +### Раскрытие токенов +**Риск**: Токены могут быть раскрыты в журналах или в выходных данных командной строки + +**Меры по снижению риска**: +Не записывать значения токенов в журналы (записывать только "аутентификация настроена: да/нет") +Команда `show` в командной строке отображает только маскированный статус, а не фактический токен +Не включать токены в сообщения об ошибках + +### Сетевая безопасность +**Риск**: Токены передаются по незашифрованным соединениям + +**Меры по снижению риска**: +Рекомендовать использовать HTTPS-URL-адреса для серверов MCP +Предупреждать пользователей о риске передачи данных в открытом виде по протоколу HTTP + +### Доступ к конфигурации +**Риск**: Несанкционированный доступ к системе конфигурации раскрывает токены + +**Меры по снижению риска**: +Подчеркнуть важность защиты доступа к системе конфигурации +Рекомендовать принцип наименьших привилегий для доступа к конфигурации +Рассмотреть возможность ведения журналов аудита для изменений конфигурации (будущая реализация) + +### Многопользовательские среды +**Риск**: В многопользовательских развертываниях все пользователи используют одни и те же учетные данные MCP + +**Понимание риска**: +Пользователь A и пользователь B используют один и тот же токен при доступе к инструменту MCP +Сервер MCP не может различать разных пользователей TrustGraph +Нет возможности применить права доступа или ограничения скорости для каждого пользователя +Журналы аудита на сервере MCP показывают все запросы от одних и тех же учетных данных +Если сессия одного пользователя скомпрометирована, злоумышленник получает тот же доступ к MCP, что и все пользователи + +**Это НЕ ошибка - это фундаментальное ограничение этой архитектуры.** + +## Влияние на производительность +**Минимальные накладные расходы**: Создание заголовка добавляет незначительное время обработки +**Влияние на сеть**: Дополнительный HTTP-заголовок добавляет ~50-200 байт на запрос +**Использование памяти**: Незначительное увеличение объема памяти для хранения строки токена в конфигурации + +## Документация + +### Пользовательская документация +[ ] Обновить `tg-set-mcp-tool.md` с параметром `--auth-token` +[ ] Добавить раздел о соображениях безопасности +[ ] Предоставить пример использования с токеном типа bearer +[ ] Задокументировать последствия хранения токенов + +### Документация для разработчиков +[ ] Добавить встроенные комментарии для обработки токенов аутентификации в `service.py` +[ ] Задокументировать логику создания заголовков +[ ] Обновить документацию схемы конфигурации инструмента MCP + +## Открытые вопросы +1. **Шифрование токенов**: Следует ли нам реализовать зашифрованное хранение токенов в системе конфигурации? +2. **Обновление токенов**: Будущая поддержка потоков OAuth для обновления токенов или ротации токенов? +3. **Альтернативные методы аутентификации**: Следует ли нам поддерживать Basic auth, API-ключи или другие методы? + +## Рассмотренные альтернативы + +1. **Переменные среды для токенов**: Хранить токены в переменных среды вместо конфигурации + **Отклонено**: Усложняет развертывание и управление конфигурацией + +2. **Отдельное хранилище секретов**: Использовать специализированную систему управления секретами + **Отложено**: Выходит за рамки первоначальной реализации, рассмотреть возможность будущей реализации + +3. **Несколько методов аутентификации**: Поддержка Basic, API-ключей, OAuth и т.д. + **Отклонено**: Токены типа bearer охватывают большинство сценариев использования, сохраняем простоту первоначальной реализации + +4. **Зашифрованное хранение токенов**: Шифровать токены в системе конфигурации + **Отложено**: Безопасность системы конфигурации является более широкой проблемой, отложить до будущей работы + +5. **Токены для каждого вызова**: Разрешить передачу токенов во время вызова + **Отклонено**: Нарушает разделение ответственности, агент не должен обрабатывать учетные данные + +## Ссылки +[Спецификация протокола MCP](https://github.com/modelcontextprotocol/spec) +[HTTP Bearer Authentication (RFC 6750)](https://tools.ietf.org/html/rfc6750) +[Текущий сервис инструмента MCP](../trustgraph-flow/trustgraph/agent/mcp_tool/service.py) +[Спецификация аргументов инструмента MCP](./mcp-tool-arguments.md) + +## Приложение + +### Пример использования + +**Настройка инструмента MCP с аутентификацией**: +```bash +tg-set-mcp-tool \ + --id secure-tool \ + --tool-url https://secure-server.example.com/mcp \ + --auth-token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +``` + +**Отображение инструментов MCP:** +```bash +tg-show-mcp-tools + +ID Remote Name URL Auth +----------- ----------- ------------------------------------ ------ +secure-tool secure-tool https://secure-server.example.com/mcp Yes +public-tool public-tool http://localhost:3000/mcp No +``` + +### Пример конфигурации + +**Хранится в системе конфигурации**: +```json +{ + "type": "mcp", + "key": "secure-tool", + "value": "{\"url\": \"https://secure-server.example.com/mcp\", \"auth-token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\"}" +} +``` + +### Лучшие практики безопасности + +1. **Использование HTTPS**: Всегда используйте HTTPS-адреса для серверов MCP с аутентификацией. +2. **Кратковременные токены**: Используйте токены с истечением срока действия, когда это возможно. +3. **Принцип наименьших привилегий**: Предоставляйте токенам минимально необходимые разрешения. +4. **Контроль доступа**: Ограничьте доступ к системе конфигурации. +5. **Ротация токенов**: Регулярно обновляйте токены. +6. **Журналирование аудита**: Отслеживайте изменения конфигурации для выявления событий безопасности. diff --git a/docs/tech-specs/mcp-tool-bearer-token.sw.md b/docs/tech-specs/mcp-tool-bearer-token.sw.md new file mode 100644 index 00000000..f2d05498 --- /dev/null +++ b/docs/tech-specs/mcp-tool-bearer-token.sw.md @@ -0,0 +1,554 @@ +# MCP Tool Bearer Token Authentication Specification + +> **⚠️ MUHIMU: INATUMIWA TU KWA MASHARTI MOJA** +> +> Maelezo haya yanaelezea **mfumo msingi wa uthibitishaji wa kiwango cha huduma** kwa zana za MCP. Haikuwa **suluhisho kamili** la uthibitishaji na **haifai** kwa: +> - Mazingira ya watumiaji wengi +> - Matumizi mengi ya wateja +> - Uthibitishaji uliounganishwa +> - Usambazaji wa muktadha wa mtumiaji +> - Ruhusa kwa kila mtumiaji +> +> Kipengele hiki hutoa **simu moja ya tuli kwa kila zana ya MCP**, ambayo inashirikiwa na watumiaji wote na vipindi vyote. Ikiwa unahitaji uthibitishaji kwa kila mtumiaji au kwa kila mteja, hii si suluhisho sahihi. + +## Maelezo +**Jina la Kipengele**: Usaidizi wa Uthibitishaji wa Simu ya Bearer ya Zana ya MCP +**Mwandishi**: Claude Code Assistant +**Tarehe**: 2025-11-11 +**Hali**: Katika Maendeleo + +### Muhtasari + +Ruhusu usanidi wa zana za MCP kubainisha simu za hiari za bearer kwa uthibitishaji na seva za MCP zilizolindwa. Hii inaruhusu TrustGraph kuita zana za MCP zilizohifadhiwa kwenye seva ambazo zinahitaji uthibitishaji, bila kubadilisha wakala au interfaces za kutumia zana. + +**MUHIMU**: Hii ni mfumo msingi wa uthibitishaji ulioundwa kwa hali za uthibitishaji wa huduma hadi huduma kwa mteja mmoja. Haifai kwa: +Mazingira ya watumiaji wengi ambapo watumiaji tofauti wanahitaji anwani tofauti +Matumizi mengi ya wateja yanayohitaji kutengwa kwa kila mteja +Hali za uthibitishaji zilizounganishwa +Uthibitishaji au ruhusa za kiwango cha mtumiaji +Usimamizi wa anwani ya kipekee au urekebishaji wa simu + +Kipengele hiki hutoa simu ya tuli, ya kimfumo kwa usanidi wa kila zana ya MCP, ambayo inashirikiwa na watumiaji wote na matumizi ya zana hiyo. + +### Tatizo + +Kwa sasa, zana za MCP zinaweza kuunganisha tu kwa seva za MCP zinazopatikana kwa umma. Matumizi mengi ya uzalishaji ya MCP yanahitaji uthibitishaji kupitia simu za bearer kwa usalama. Bila usaidizi wa uthibitishaji: +Zana za MCP haziwezi kuunganisha kwa seva za MCP zilizolindwa +Watumiaji lazima iweze kufungua seva za MCP kwa umma au kutumia viboreshaji vya kurudi nyuma +Hakuna njia iliyoanzishwa ya kupitisha anwani kwa miunganisho ya MCP +Mazoea bora ya usalama hayawezi kutekelezwa kwenye mwisho wa MCP + +### Lengo + +[ ] Ruhusu usanidi wa zana za MCP kubainisha parameter ya `auth-token` ya hiari +[ ] Sasisha huduma ya zana ya MCP ili itumie simu za bearer wakati inapo na seva za MCP +[ ] Sasisha zana za CLI ili kusaidia kuweka/kuonyesha anwani +[ ] Dumishe utangamano wa nyuma na usanidi usio na uthibitishaji wa MCP +[ ] Andika masuala ya usalama ya uhifadhi wa simu + +### Lengo Lisilofikiwa +Urekebishaji wa simu ya kipekee au mtiririko wa OAuth (simu za tuli tu) +Usifungishaji wa simu zilizohifadhiwa (usalama wa mfumo wa usanidi uko nje ya wigo) +Njia zingine za uthibitishaji (uthibitishaji wa Msingi, ufunguo wa API, n.k.) +Uthibitishaji au ukaguzi wa kumalizika wa simu +**Uthibitishaji wa kila mtumiaji**: Kipengele hiki hakisaidii anwani maalum za mtumiaji +**Kutengwa kwa mteja mwingi**: Kipengele hiki hakutoa usimamizi wa simu kwa kila mteja +**Uthibitishaji uliounganishwa**: Kipengele hiki hakujumuisha na watoa utambulisho (SSO, OAuth, SAML, n.k.) +**Uthibitishaji unaohusiana na muktadha**: Simu hazipitishwe kulingana na muktadha wa mtumiaji au kikao + +## Asili na Mfumo + +### Hali ya Sasa +Usanidi wa zana za MCP huhifadhiwa katika kikundi cha usanidi cha `mcp` na muundo huu: +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +Huduma ya zana ya MCP inaunganisha na seva kwa kutumia `streamablehttp_client(url)` bila vichwa vya uthibitishaji. + +### Marekebisho + +**Marekebisho ya Sasa ya Mfumo:** +1. **Hakuna usaidizi wa uthibitishaji**: Haiwezi kuunganisha na seva za MCP zilizolindwa. +2. **Ufafanuzi wa usalama**: Seva za MCP lazima ziwe zinapatikana kwa umma au zitumie usalama wa kiwango cha mtandao pekee. +3. **Matatizo ya matumizi katika mazingira ya uzalishaji**: Haiwezi kufuata mbinu bora za usalama kwa vidokezo vya API. + +**Marekebisho ya Suluhisho Hili:** +1. **Kwa watumiaji mmoja tu**: Ishara moja ya tuli kwa kila zana ya MCP, inayoshirikiwa na watumiaji wote. +2. **Hakuna anwani za mtumiaji binafsi**: Haiwezi kuthibitisha kama watumiaji tofauti au kupitisha muktadha wa mtumiaji. +3. **Hakuna usaidizi wa watumiaji wengi**: Haiwezi kutenganisha anwani kwa kila mhakiki au shirika. +4. **Ishara za tuli tu**: Hakuna usaidizi kwa sasisho, mzunguko, au utunzaji wa kumalizika kwa ishara. +5. **Uthibitishaji wa huduma**: Inathibitisha huduma ya TrustGraph, sio watumiaji binafsi. +6. **Muktadha wa usalama unaoshirikiwa**: Matumizi yote ya zana ya MCP hutumia anwani sawa. + +### Ufaa wa Matumizi + +**✅ Matumizi Yanayofaa:** +Uwekaji wa TrustGraph kwa watumiaji mmoja. +Uthibitishaji kutoka kwa huduma hadi huduma (TrustGraph → Seva ya MCP). +Mazingira ya maendeleo na majaribio. +Zana za ndani za MCP zinazopatikana na mfumo wa TrustGraph. +Matukio ambamo watumiaji wote wana kiwango sawa cha ufikiaji wa zana ya MCP. +Anwani za huduma za tuli, za muda mrefu. + +**❌ Matumizi Yasiyofaa:** +Mifumo ya watumiaji wengi inayohitaji uthibitishaji wa kila mtumiaji. +Uwekaji wa SaaS wa watumiaji wengi wenye mahitaji ya kutenganisha kila mhakiki. +Matukio ya uthibitishaji uliounganishwa (SSO, OAuth, SAML). +Mifumo inayohitaji kupitisha muktadha wa mtumiaji kwa seva za MCP. +Mazingira yanayohitaji sasisho za ishara za nguvu au ishara za muda mfupi. +Programu ambamo watumiaji tofauti wanahitaji viwango tofauti vya ruhusa. +Mahitaji ya utiifu kwa njia za ukaguzi za kiwango cha mtumiaji. + +**Mfano wa Matumizi Yanayofaa:** +Uwekaji wa TrustGraph wa shirika moja ambamo wafanyakazi wote hutumia zana sawa ya ndani ya MCP (k.m., utafutaji wa hifadhi ya kampuni). Seva ya MCP inahitaji uthibitishaji ili kuzuia ufikiaji wa nje, lakini watumiaji wote wa ndani wana kiwango sawa cha ufikiaji. + +**Mfano wa Matumizi Yasiyofaa:** +Jukwaa la SaaS la TrustGraph la watumiaji wengi ambamo Mhakiki A na Mhakiki B kila mmoja anahitaji kufikia seva zao zilizotenganishwa za MCP na anwani tofauti. Kipengele hiki hakitumii usimamizi wa anwani wa kila mhakiki. + +### Vipengele Vinavyohusiana +**trustgraph-flow/trustgraph/agent/mcp_tool/service.py**: Huduma ya utekelezaji wa zana ya MCP. +**trustgraph-cli/trustgraph/cli/set_mcp_tool.py**: Zana ya CLI ya kuunda/kusasisha mipangilio ya MCP. +**trustgraph-cli/trustgraph/cli/show_mcp_tools.py**: Zana ya CLI ya kuonyesha mipangilio ya MCP. +**SDK ya Python ya MCP**: `streamablehttp_client` kutoka `mcp.client.streamable_http` + +## Mahitaji + +### Mahitaji ya Kifaa + +1. **Ishara ya Uthibitishaji ya Mipangilio ya MCP**: Mipangilio ya zana ya MCP INAWEZA kuwa na `auth-token`. +2. **Matumizi ya Ishara ya Bearer**: Huduma ya zana ya MCP INAWEZA kutuma `Authorization: Bearer {token}` wakati ishara ya uthibitishaji imewekwa. +3. **Usaidizi wa CLI**: `tg-set-mcp-tool` INAWEZA kukubali parameter ya `--auth-token`. +4. **Uonyesho wa Ishara**: `tg-show-mcp-tools` INAWEZA kuonyesha wakati ishara ya uthibitishaji imewekwa (imeficha kwa usalama). +5. **Ulinganishaji na Mifumo ya Zamani**: Mipangilio ya zana ya MCP iliyopo bila uthibitishaji INAWEZA kuendelea kufanya kazi. + +### Mahitaji Yasiyo ya Kifaa +1. **Ulinganishaji na Mifumo ya Zamani**: Hakuna mabadiliko yoyote yanayoweza kusababisha migogoro kwa mipangilio ya zana ya MCP iliyopo. +2. **Utendaji**: Hakuna athari kubwa ya utendaji kwenye utekelezaji wa zana ya MCP. +3. **Usalama**: Anwani zinaohifadhiwa katika mipangilio (angalia masuala ya usalama). + +### Hadithi za Mtumiaji + +1. Kama **mhandisi wa DevOps**, ningependa kusanidi anwani za bearer kwa zana za MCP ili niweze kulinda vidokezo vya seva za MCP. +2. Kama **mtumiaji wa CLI**, ningependa kuweka anwani za uthibitishaji wakati ninaunda zana za MCP ili niweze kuunganisha na seva zilizolindwa. +3. Kama **mhasibu wa mfumo**, ningependa kuona zana gani za MCP zilizosanidiwa na uthibitishaji ili niweze kukagua mipangilio ya usalama. + +## Muundo + +### Muundo wa Juu +Panua mipangilio ya zana ya MCP na huduma ili kusaidia uthibitishaji wa ishara ya bearer: +1. Ongeza `auth-token` kwenye schema ya mipangilio ya zana ya MCP. +2. Badilisha huduma ya zana ya MCP ili kusoma ishara ya uthibitishaji na kuipitisha kwa mteja wa HTTP. +3. Sasisha zana za CLI ili kusaidia kuweka na kuonyesha anwani za uthibitishaji. +4. Andika masuala ya usalama na mbinu bora. + +### Schema ya Mipangilio + +**Schema ya Sasa**: +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +**Mfumo Mpya** (na ishara ya uthibitisho ya hiari): +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api", + "auth-token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} +``` + +**Maelezo ya Kila Kila Nyanja:** +`remote-name` (hiari): Jina linalotumika na seva ya MCP (linalotumika kiotomatiki kama funguo ya usanidi) +`url` (lazima): URL ya mwisho wa seva ya MCP +`auth-token` (hiari): Alama ya "Bearer" kwa uthibitishaji + +### Mtiririko wa Data + +1. **Hifadhi ya Usanidi:** Mtumiaji huanzisha `tg-set-mcp-tool --id my-tool --tool-url http://server/api --auth-token xyz123` +2. **Upakiaji wa Usanidi:** Huduma ya zana ya MCP hupokea sasisho la usanidi kupitia mjumuko wa `on_mcp_config()` +3. **Uanzishaji wa Zana:** Wakati zana inaanzishwa: + Huduma husoma `auth-token` kutoka usanidi (ikiwa ipo) + Huunda kamusi ya vichwa: `{"Authorization": "Bearer {token}"}` + Hutuma vichwa kwa `streamablehttp_client(url, headers=headers)` + Seva ya MCP huangalia alama na kutoa ombi + +### Mabadiliko ya API +Hakuna mabadiliko ya API ya nje - mabadiliko ya muundo wa usanidi tu. + +### Maelezo ya Vipengele + +#### Kipengele 1: service.py (Huduma ya Zana ya MCP) +**Faili:** `trustgraph-flow/trustgraph/agent/mcp_tool/service.py` + +**Lengo:** Kuendesha zana za MCP kwenye seva za mbali + +**Mabadiliko Yanayohitajika** (katika njia ya `invoke_tool()`): +1. Angalia `auth-token` katika usanidi wa `self.mcp_services[name]` +2. Jenga kamusi ya vichwa na kichwa cha "Authorization" ikiwa alama ipo +3. Tuma vichwa kwa `streamablehttp_client(url, headers=headers)` + +**Msimbo Sasa** (mistari 42-89): +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server + async with streamablehttp_client(url) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method +``` + +**Msimbo Uliorekebishwa**: +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + # Build headers with optional bearer token + headers = {} + if "auth-token" in self.mcp_services[name]: + token = self.mcp_services[name]["auth-token"] + headers["Authorization"] = f"Bearer {token}" + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server with headers + async with streamablehttp_client(url, headers=headers) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method (unchanged) +``` + +#### Sehemu ya 2: set_mcp_tool.py (Zana ya Usanidi wa CLI) +**Faili**: `trustgraph-cli/trustgraph/cli/set_mcp_tool.py` + +**Madhumuni**: Kuunda/kusasisha usanidi wa zana ya MCP + +**Mabadiliko Yanayohitajika**: +1. Ongeza sajili ya `--auth-token` ya hiari kwa argparse +2. Jumuisha `auth-token` katika JSON ya usanidi wakati inatolewa + +**Sajili za Sasa**: +`--id` (lazima): Kitambulisho cha zana ya MCP +`--remote-name` (ya hiari): Jina la zana ya MCP ya mbali +`--tool-url` (lazima): Ncha ya URL ya zana ya MCP +`-u, --api-url` (ya hiari): URL ya API ya TrustGraph + +**Sajili Mpya**: +`--auth-token` (ya hiari): Alama ya "Bearer" kwa uthibitishaji + +**Ujenzi wa Usanidi Uliobadilishwa**: +```python +# Build configuration object +config = { + "url": args.tool_url, +} + +if args.remote_name: + config["remote-name"] = args.remote_name + +if args.auth_token: + config["auth-token"] = args.auth_token + +# Store configuration +api.config().put([ + ConfigValue(type="mcp", key=args.id, value=json.dumps(config)) +]) +``` + +#### Sehemu ya 3: show_mcp_tools.py (Chombo cha Kuonyesha Kwenye Kamba) +**Faili**: `trustgraph-cli/trustgraph/cli/show_mcp_tools.py` + +**Madhumuni**: Kuonyesha usanidi wa chombo cha MCP + +**Mabadiliko Yanayohitajika**: +1. Ongeza safu ya "Auth" kwenye meza ya pato +2. Onyesha "Ndiyo" au "Hapana" kulingana na uwepo wa ishara ya uthibitishaji (auth-token) +3. Usionyeshe thamani halisi ya ishara (usalama) + +**Pato Lililopo Sasa**: +``` +ID Remote Name URL +---------- ------------- ------------------------ +my-tool my-tool http://server:3000/api +``` + +**Pato Jipya**: +``` +ID Remote Name URL Auth +---------- ------------- ------------------------ ------ +my-tool my-tool http://server:3000/api Yes +other-tool other-tool http://other:3000/api No +``` + +#### Sehemu ya 4: Nyaraka +**Faili**: `docs/cli/tg-set-mcp-tool.md` + +**Mabadiliko Yanayohitajika**: +1. Andika nyaraka kwa parameter mpya ya `--auth-token` +2. Toa mfano wa matumizi na uthibitishaji +3. Andika masuala ya usalama + +## Mpango wa Utendaji + +### Awamu ya 1: Unda Vipimo vya Kisaikolojia +[x] Andika vipimo vya kisaikolojia vya kina ambavyo vinadokeza mabadiliko yote + +### Awamu ya 2: Sasisha Huduma ya Zana ya MCP +[ ] Badilisha `invoke_tool()` katika `service.py` ili kusoma `auth-token` kutoka kwa usanidi +[ ] Jenga kamusi ya vichwa na uipitisha kwa `streamablehttp_client` +[ ] Jaribu na seva ya MCP iliyo na uthibitishaji + +### Awamu ya 3: Sasisha Zana za CLI +[ ] Ongeza hoja ya `--auth-token` kwa `set_mcp_tool.py` +[ ] Jumuisha `auth-token` katika usanidi wa JSON +[ ] Ongeza safu ya "Auth" kwenye pato la `show_mcp_tools.py` +[ ] Jaribu mabadiliko ya zana ya CLI + +### Awamu ya 4: Sasisha Nyaraka +[ ] Andika `--auth-token` katika `tg-set-mcp-tool.md` +[ ] Ongeza sehemu ya masuala ya usalama +[ ] Toa mfano wa matumizi + +### Awamu ya 5: Majaribio +[ ] Jaribu zana ya MCP na `auth-token` inaunganisha kwa ufanisi +[ ] Jaribu utangamano wa nyuma (zana bila `auth-token` zinaendelea kufanya kazi) +[ ] Jaribu zana za CLI hupokea na kuhifadhi `auth-token` kwa usahihi +[ ] Jaribu amri ya "Onyesha" inaonyesha hali ya uthibitishaji kwa usahihi + +### Muhtasari wa Mabadiliko ya Msimbo +| Faili | Aina ya Mabadiliko | Mistari | Maelezo | +|------|------------|-------|-------------| +| `service.py` | Imebadilishwa | ~52-66 | Ongeza usomaji wa `auth-token` na ujenzi wa vichwa | +| `set_mcp_tool.py` | Imebadilishwa | ~30-60 | Ongeza hoja ya `--auth-token` na uhifadhi wa usanidi | +| `show_mcp_tools.py` | Imebadilishwa | ~40-70 | Ongeza safu ya Uthibitishaji kwenye onyesho | +| `tg-set-mcp-tool.md` | Imebadilishwa | Mbalimbali | Andika parameter mpya | + +## Mkakati wa Majaribio + +### Majaribio ya Kitengo +**Usomaji wa Tokeni ya Uthibitishaji**: Jaribu `invoke_tool()` husoma `auth-token` kwa usahihi kutoka kwa usanidi +**Ujenzi wa Vichwa**: Jaribu vichwa vya Ruhusa vinajengwa kwa usahihi na mbele ya `Bearer` +**Utangamano wa Nyuma**: Jaribu zana bila `auth-token` zinafanya kazi bila mabadiliko +**Uchanganuzi wa Hoja ya CLI**: Jaribu hoja ya `--auth-token` inachanganzwa kwa usahihi + +### Majaribio ya Uunganisho +**Uunganisho Ulio na Uthibitishaji**: Jaribu huduma ya zana ya MCP inaunganisha na seva iliyo na uthibitishaji +**Kila kitu**: Jaribu CLI → uhifadhi wa usanidi → utekelezaji wa huduma na `auth token` +**Tokeni Haihitajiki**: Jaribu uunganisho na seva isiyo na uthibitishaji unaendelea kufanya kazi + +### Majaribio ya Kawaida +**Seva Halisi ya MCP**: Jaribu na seva halisi ya MCP inayohitaji uthibitishaji wa `bearer token` +**Mwendo wa CLI**: Jaribu mwendo kamili: weka zana na uthibitishaji → fanya kazi ya zana → thibitisha mafanikio +**Kuficha Kuonyesha**: Thibitisha hali ya uthibitishaji inaonyeshwa lakini thamani ya tokeni haijaonyeshwa + +## Uhamishaji na Utoaji + +### Mkakati wa Uhamishaji +Hakuna uhamishaji unaohitajika - hii ni utendakazi wa ziada: +Usanidi wa zana ya MCP iliyopo bila `auth-token` inaendelea kufanya kazi bila mabadiliko +Usanidi mpya unaweza kujumuisha sehemu ya `auth-token` +Zana za CLI hupokea lakini hazihitaji parameter ya `--auth-token` + +### Mpango wa Utoaji +1. **Awamu ya 1**: Toa mabadiliko ya msingi ya huduma kwa maendeleo/maandalizi +2. **Awamu ya 2**: Toa sasisho za zana za CLI +3. **Awamu ya 3**: Sasisha nyaraka +4. **Awamu ya 4**: Utoaji wa uzalishaji na ufuatiliaji + +### Mpango wa Kurudisha Nyuma +Mabadiliko ya msingi yana utangamano wa nyuma - zana zilizopo hazipatiwa madhara +Ikiwa matatizo yanajitokeza, utunzaji wa `auth-token` unaweza kuzimwa kwa kuondoa mantiki ya ujenzi wa vichwa +Mabadiliko ya zana za CLI ni huru na yanaweza kurejeshwa kando + +## Masuala ya Usalama + +### ⚠️ Kikomo Muhimu: Uthibitishaji wa Mfumo Mmoja Tu + +**Mfumo huu wa uthibitishaji haufai kwa mazingira ya watumiaji wengi au ya wateja wengi.** + +**Anwani zilizoshirikiwa**: Watumiaji wote na matumizi yote huongea tokeni moja kwa kila zana ya MCP +**Hakuna muktadha wa mtumiaji**: Seva ya MCP haiwezi kutofautisha kati ya watumiaji tofauti wa TrustGraph +**Hakuna kutengwa kwa mteja**: Wateja wote huongea anwani sawa kwa kila zana ya MCP +**Kizuia cha ukaguzi**: Seva ya MCP inaonyesha maombi yote kutoka kwa anwani sawa +**Nguvu za idhini**: Haiwezi kutekeleza viwango tofauti vya idhini kwa watumiaji tofauti + +**Usitumie kipengele hiki ikiwa:** +Umechanganya mashirika mengi +Unahitaji uthibitishaji wa mtu binafsi +Unahitaji uthibitishaji wa muda +Unahitaji uthibitishaji wa mteja mmoja + + +**Suluhisho mbadala kwa matukio ya watumiaji wengi/watu wengi:** +Tengeneza usambazaji wa muktadha wa mtumiaji kupitia vichwa maalum +Weka mifumo tofauti ya TrustGraph kwa kila mtoa huduma +Tumia utengano wa kiwango cha mtandao (VPCs, huduma za mtandao) +Tengeneza safu ya wakala inayoshughulikia uthibitishaji wa kila mtumiaji + +### Uhifadhi wa Tokeni +**Hatari**: Tokeni za uthibitishaji zimehifadhiwa kwa maandishi wazi katika mfumo wa usanidi + +**Hatua za kuzuia**: +Andika kwamba tokeni zimehifadhiwa bila usimbaji +Pendekeza kutumia tokeni za muda mfupi inapowezekana +Pendekeza udhibiti sahihi wa ufikiaji kwenye hifadhi ya usanidi +Fikiria uboreshaji wa baadaye kwa uhifadhi uliosimbwa wa tokeni + +### Uonyeshaji wa Tokeni +**Hatari**: Tokeni zinaweza kuonyeshwa katika arifa au pato la CLI + +**Hatua za kuzuia**: +Usiandike maadili ya tokeni (andika tu "uthibitishaji umeanzishwa: ndiyo/hapana") +Amri ya CLI ya kuonyesha inaonyesha hali iliyofichwa tu, sio tokeni halisi +Usijumuishe tokeni katika ujumbe wa hitilafu + +### Usalama wa Mtandao +**Hatari**: Tokeni zinafutwa kupitia miunganisho isiyo salama + +**Hatua za kuzuia**: +Andika pendekezo la kutumia URL za HTTPS kwa seva za MCP +Onya watumiaji kuhusu hatari ya usambazaji wa maandishi wazi na HTTP + +### Ufikiaji wa Usanidi +**Hatari**: Ufikiaji usioidhinishwa kwa mfumo wa usanidi unaoonyesha tokeni + +**Hatua za kuzuia**: +Andika umuhimu wa kuhakikisha ufikiaji wa mfumo wa usanidi +Pendekeza kanuni ya madaraka madogo kwa ufikiaji wa usanidi +Fikiria uandikaji wa matukio kwa mabadiliko ya usanidi (uboresho wa baadaye) + +### Mazingira ya Watumiaji Wengi +**Hatari**: Katika matukio ya watumiaji wengi, watumiaji wote wanashiriki anwani sawa za MCP + +**Kuelewa Hatari**: +Mtumiaji A na Mtumiaji B hutumia tokeni sawa wakati wa kufikia zana ya MCP +Seva ya MCP haiwezi kutofautisha kati ya watumiaji tofauti wa TrustGraph +Hakuna njia ya kutekeleza ruhusa au mipaka ya kiwango cha mtumiaji +Arifa kwenye seva ya MCP zinaonyesha maombi yote kutoka kwa anwani sawa +Ikiwa kikao cha mtumiaji mmoja kimebanwa, mshambuliaji ana ufikiaji sawa wa MCP kama watumiaji wote + +**HII SI hitilafu - ni kikomo cha msingi cha muundo huu.** + +## Athari ya Utendaji +**Mzigo mdogo**: Ujenzi wa kichwa unaongeza muda mdogo wa usindikaji +**Athari ya mtandao**: Kichwa cha ziada cha HTTP huongeza ~50-200 baiti kwa ombi +**Matumizi ya kumbukumbu**: Kuongezeka kwa kiasi kidogo kwa kuhifadhi mnyororo wa tokeni katika usanidi + +## Nyaraka + +### Nyaraka za Mtumiaji +[ ] Sasisha `tg-set-mcp-tool.md` na parameter ya `--auth-token` +[ ] Ongeza sehemu ya mambo ya usalama +[ ] Toa mfano wa matumizi na tokeni ya mfuata +[ ] Andika madhumuni ya uhifadhi wa tokeni + +### Nyaraka za Msanidi Programu +[ ] Ongeza maelezo ya ndani kwa usimamizi wa tokeni ya uthibitishaji katika `service.py` +[ ] Andika mantiki ya ujenzi wa kichwa +[ ] Sasisha nyaraka za schema ya usanidi ya zana ya MCP + +## Maswali ya Funguo +1. **Usimbaji wa tokeni**: Je, tunapaswa kutekeleza uhifadhi uliosimbwa wa tokeni katika mfumo wa usanidi? +2. **Urekebishaji wa tokeni**: Usaidizi wa siku zijazo kwa mtiririko wa OAuth wa urekebishaji au mzunguko wa tokeni? +3. **Njia mbadala za uthibitishaji**: Je, tunapaswa kusaidia uthibitishaji wa Msingi, ufunguo wa API, au mbinu zingine? + +## Mbadala Zilizozingatiwa + +1. **Vigezo vya mazingira kwa tokeni**: Hifadhi tokeni katika vigezo vya mazingira badala ya usanidi + **Ilikataliwa**: Inachanganya usakinishaji na usimamizi wa usanidi + +2. **Hifadhi ya siri tofauti**: Tumia mfumo maalum wa usimamizi wa siri + **Imeahirishwa**: Nje ya upeo wa utekelezaji wa awali, fikiria uboreshaji wa siku zijazo + +3. **Njia nyingi za uthibitishaji**: Kusaidia Msingi, ufunguo wa API, OAuth, n.k. + **Ilikataliwa**: Tokeni za mfuata hufunika matumizi mengi, endeleza utekelezaji wa awali rahisi + +4. **Uhifadhi uliosimbwa wa tokeni**: Simba tokeni katika mfumo wa usanidi + **Imeahirishwa**: Usalama wa mfumo wa usanidi ni suala pana, chelewesha hadi kazi ya baadaye + +5. **Tokeni za kila utendaji**: Ruhusu tokeni kupitishwa wakati wa utendaji + **Ilikataliwa**: Inakiuka utengano wa masuala, wakala haupaswi kushughulikia anwani + +## Marejeleo +[Maelezo ya Protokali ya MCP](https://github.com/modelcontextprotocol/spec) +[Uthibitishaji wa Mfuata wa HTTP (RFC 6750)](https://tools.ietf.org/html/rfc6750) +[Huduma ya Zana ya MCP ya Sasa](../trustgraph-flow/trustgraph/agent/mcp_tool/service.py) +[Maelezo ya Majadilisho ya Zana ya MCP](./mcp-tool-arguments.md) + +## Toa Maelezo + +### Matumizi ya Kifaa + +**Kuanzisha zana ya MCP pamoja na uthibitishaji:** +```bash +tg-set-mcp-tool \ + --id secure-tool \ + --tool-url https://secure-server.example.com/mcp \ + --auth-token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +``` + +**Kuonyesha zana za MCP**: +```bash +tg-show-mcp-tools + +ID Remote Name URL Auth +----------- ----------- ------------------------------------ ------ +secure-tool secure-tool https://secure-server.example.com/mcp Yes +public-tool public-tool http://localhost:3000/mcp No +``` + +### Mfano wa Usanidi + +**Imehifadhiwa katika mfumo wa usanidi:** +```json +{ + "type": "mcp", + "key": "secure-tool", + "value": "{\"url\": \"https://secure-server.example.com/mcp\", \"auth-token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\"}" +} +``` + +### Mbinu Bora za Usalama + +1. **Tumia HTTPS**: Daima tumia anwani za mtandao (URLs) za HTTPS kwa seva za MCP zenye uthibitishaji. +2. **Alama za muda mfupi**: Tumia alama (tokens) zenye muda wa kumalizika unapowezekana. +3. **Haki ndogo zaidi**: Toa alama ruhusa ndogo zaidi zinazohitajika. +4. **Kidhibiti cha ufikiaji**: Punguza ufikiaji kwenye mfumo wa usanidi. +5. **Kubadilisha alama**: Badilisha alama mara kwa mara. +6. **Uandikaji wa matukio**: Fuatilia mabadiliko ya usanidi ili kutambua matukio ya usalama. diff --git a/docs/tech-specs/mcp-tool-bearer-token.tr.md b/docs/tech-specs/mcp-tool-bearer-token.tr.md new file mode 100644 index 00000000..fb28a1ca --- /dev/null +++ b/docs/tech-specs/mcp-tool-bearer-token.tr.md @@ -0,0 +1,554 @@ +# MCP Aracı Taşıyıcı (Bearer) Token Doğrulama Özelliği Belirtimi + +> **⚠️ ÖNEMLİ: YALNIZCA TEK-KİRACI (SINGLE-TENANT) ORTAMLAR İÇİN** +> +> Bu belirtim, MCP araçları için temel, hizmet seviyesinde bir doğrulama mekanizmasını açıklamaktadır. Bu, **TAMAMLANMIŞ** bir doğrulama çözümü değildir ve aşağıdaki durumlar için **UYGUN DEĞİL**: +> - Çok kullanıcılı ortamlar +> - Çok kiracılı (multi-tenant) dağıtımlar +> - Federasyonlu doğrulama +> - Kullanıcı bağlamı yayılımı +> - Kullanıcı bazlı yetkilendirme +> +> Bu özellik, her MCP aracı için **tek bir statik token** sağlar ve bu token tüm kullanıcılar ve oturumlar arasında paylaşılır. Kullanıcı bazlı veya kiracı bazlı doğrulama gerekiyorsa, bu çözüm uygun değildir. + +## Genel Bakış +**Özellik Adı**: MCP Aracı Taşıyıcı (Bearer) Token Doğrulama Desteği +**Yazar**: Claude Code Assistant +**Tarih**: 2025-11-11 +**Durum**: Geliştirme Aşamasında + +### Yönetici Özeti + +MCP araçlarının, korumalı MCP sunucularıyla kimlik doğrulaması yapmak için isteğe bağlı taşıyıcı (bearer) token'lar belirtmesine olanak tanıyın. Bu, TrustGraph'ın, kimlik doğrulaması gerektiren sunucularda barındırılan MCP araçlarını, aracının veya araç çağrı arayüzlerinin değiştirilmesi olmadan güvenli bir şekilde çağırmasını sağlar. + +**ÖNEMLİ**: Bu, tek kiracılı, hizmetten hizmete doğrulama senaryoları için tasarlanmış temel bir doğrulama mekanizmasıdır. Aşağıdaki durumlar için **UYGUN DEĞİL**: +Farklı kullanıcıların farklı kimlik bilgilerine ihtiyaç duyduğu çok kullanıcılı ortamlar +Kiracı başına izolasyon gerektiren çok kiracılı dağıtımlar +Federasyonlu doğrulama senaryoları +Kullanıcı seviyesinde doğrulama veya yetkilendirme +Dinamik kimlik bilgisi yönetimi veya token yenileme + +Bu özellik, her MCP aracı yapılandırması için statik, sistem genelinde bir taşıyıcı (bearer) token sağlar ve bu token, o aracın tüm kullanıcıları ve çağrıları tarafından paylaşılır. + +### Sorun Tanımı + +Şu anda, MCP araçları yalnızca herkese açık olarak erişilebilir MCP sunucularına bağlanabilir. Birçok üretim MCP dağıtımı, güvenlik için taşıyıcı (bearer) token'lar aracılığıyla kimlik doğrulaması gerektirir. Kimlik doğrulama desteği olmadan: +MCP araçları, güvenli MCP sunucularına bağlanamaz +Kullanıcılar ya MCP sunucularını herkese açık hale getirmeli ya da ters vekil (reverse proxy) uygulamalıdır +MCP bağlantılarına kimlik bilgilerini iletmenin standart bir yolu yoktur +MCP uç noktalarında güvenlik en iyi uygulamaları uygulanamaz + +### Hedefler + +[ ] MCP araç yapılandırmalarının isteğe bağlı `auth-token` parametresini belirtmesine izin verin +[ ] MCP araç hizmetini, MCP sunucularına bağlanırken taşıyıcı (bearer) token'ları kullanacak şekilde güncelleyin +[ ] CLI araçlarını, kimlik doğrulama token'larını ayarlama/görüntüleme özelliğini destekleyecek şekilde güncelleyin +[ ] Kimlik doğrulaması olmayan MCP yapılandırmalarıyla geriye dönük uyumluluğu koruyun +[ ] Token depolama için güvenlik hususlarını belgeleyin + +### Hedef Dışı Kalanlar +Dinamik token yenileme veya OAuth akışları (yalnızca statik token'lar) +Depolanmış token'ların şifrelenmesi (yapılandırma sistemi güvenliği kapsam dışındadır) +Alternatif doğrulama yöntemleri (Temel kimlik doğrulama, API anahtarları, vb.) +Token doğrulama veya son kullanma kontrolü +**Kullanıcı başına doğrulama**: Bu özellik, kullanıcıya özel kimlik bilgilerini desteklemez +**Kiracı izolasyonu**: Bu özellik, kiracı başına token yönetimi sağlamaz +**Federasyonlu doğrulama**: Bu özellik, kimlik sağlayıcılarıyla (SSO, OAuth, SAML, vb.) entegre olmaz +**Bağlama duyarlı doğrulama**: Token'lar, kullanıcı bağlamına veya oturuma göre iletilmez + +## Arka Plan ve Bağlam + +### Mevcut Durum +MCP araç yapılandırmaları, `mcp` yapılandırma grubunda aşağıdaki yapıya sahip olarak saklanır: +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +MCP aracı hizmeti, `streamablehttp_client(url)` kullanarak sunuculara bağlanır ve herhangi bir kimlik doğrulama başlığı kullanmaz. + +### Sınırlamalar + +**Mevcut Sistem Sınırlamaları:** +1. **Kimlik doğrulama desteği yok:** Güvenli MCP sunucularına bağlanılamaz. +2. **Güvenlik açığı:** MCP sunucuları, yalnızca ağ seviyesinde güvenlik kullanılarak genel olarak erişilebilir olmalıdır. +3. **Üretim dağıtım sorunları:** API uç noktaları için güvenlik en iyi uygulamalarını takip edilemez. + +**Bu Çözümün Sınırlamaları:** +1. **Yalnızca tek kiracı:** Her MCP aracı için tek bir statik belirteç, tüm kullanıcılar arasında paylaşılır. +2. **Kullanıcı başına kimlik bilgileri yok:** Farklı kullanıcılar olarak kimlik doğrulaması yapılamaz veya kullanıcı bağlamı geçirilemez. +3. **Çok kiracılı destek yok:** Kimlik bilgilerini kiracı veya kuruluş başına izole etmek mümkün değildir. +4. **Yalnızca statik belirteçler:** Belirteç yenileme, döndürme veya son kullanma süresi yönetimi desteği yoktur. +5. **Hizmet seviyesi kimlik doğrulaması:** Bireysel kullanıcılar yerine TrustGraph hizmetini doğrular. +6. **Paylaşılan güvenlik bağlamı:** Bir MCP aracının tüm çağrıları aynı kimlik bilgisini kullanır. + +### Kullanım Alanı Uygunluğu + +**✅ Uygun Kullanım Alanları:** +Tek kiracılı TrustGraph dağıtımları +Hizmetten hizmete kimlik doğrulama (TrustGraph → MCP Sunucusu) +Geliştirme ve test ortamları +TrustGraph sistemi tarafından erişilen dahili MCP araçları +Tüm kullanıcıların aynı MCP aracı erişim düzeyini paylaştığı senaryolar +Statik, uzun ömürlü hizmet kimlik bilgileri + +**❌ Uygun Olmayan Kullanım Alanları:** +Kullanıcı başına kimlik doğrulama gerektiren çok kullanıcılı sistemler +Kiracı izolasyonu gereksinimleri olan çok kiracılı SaaS dağıtımları +Federasyon kimlik doğrulama senaryoları (SSO, OAuth, SAML) +MCP sunucularına kullanıcı bağlamının iletilmesi gereken sistemler +Dinamik belirteç yenileme veya kısa ömürlü belirteçler gerektiren ortamlar +Farklı kullanıcıların farklı izin düzeylerine ihtiyaç duyduğu uygulamalar +Kullanıcı seviyesinde denetim izleri için uyumluluk gereksinimleri + +**Örnek Uygun Senaryo:** +Tüm çalışanların aynı dahili MCP aracını (örneğin, şirket veritabanı sorgusu) kullandığı tek organizasyonlu bir TrustGraph dağıtımı. MCP sunucusunun harici erişimi önlemek için kimlik doğrulama gerektirmesi, ancak tüm dahili kullanıcıların aynı erişim düzeyine sahip olması. + +**Örnek Uygun Olmayan Senaryo:** +Kiracı A ve Kiracı B'nin her birinin ayrı kimlik bilgileriyle kendi izole MCP sunucularına erişmesi gereken çok kiracılı bir TrustGraph SaaS platformu. Bu özellik, kiracı başına belirteç yönetimi DEĞİLDİR. + +### İlgili Bileşenler +**trustgraph-flow/trustgraph/agent/mcp_tool/service.py**: MCP aracı çağrı hizmeti +**trustgraph-cli/trustgraph/cli/set_mcp_tool.py**: MCP yapılandırmalarını oluşturmak/güncellemek için CLI aracı +**trustgraph-cli/trustgraph/cli/show_mcp_tools.py**: MCP yapılandırmalarını görüntülemek için CLI aracı +**MCP Python SDK**: `streamablehttp_client` from `mcp.client.streamable_http` + +## Gereksinimler + +### Fonksiyonel Gereksinimler + +1. **MCP Yapılandırma Kimlik Doğrulama Belirteci**: MCP aracı yapılandırmaları, isteğe bağlı bir `auth-token` alanı DESTEKLEMELİDİR. +2. **Bearer Belirteç Kullanımı**: MCP aracı hizmeti, kimlik doğrulama belirteci yapılandırıldığında `Authorization: Bearer {token}` başlığını GÖNDERMELİDİR. +3. **CLI Desteği**: `tg-set-mcp-tool`, isteğe bağlı bir `--auth-token` parametresi KABUL ETMELİDİR. +4. **Belirteç Görüntüleme**: `tg-show-mcp-tools`, kimlik doğrulama belirtecinin yapılandırıldığını GÖSTERMELİDİR (güvenlik için gizlenmiş). +5. **Geriye Dönük Uyumluluk**: Kimlik doğrulama belirteci olmayan mevcut MCP aracı yapılandırmaları çalışmaya DEVAM ETMELİDİR. + +### Fonksiyonel Olmayan Gereksinimler +1. **Geriye Dönük Uyumluluk**: Mevcut MCP aracı yapılandırmaları için hiçbir bozucu değişiklik olmamalıdır. +2. **Performans**: MCP aracı çağrısı üzerinde önemli bir performans etkisi olmamalıdır. +3. **Güvenlik**: Belirteçler yapılandırmada saklanır (güvenlik etkilerini belgeleyin). + +### Kullanıcı Hikayeleri + +1. Bir **DevOps mühendisi** olarak, MCP sunucusu uç noktalarını güvence altına almak için MCP araçları için taşıyıcı belirteçleri yapılandırmak istiyorum. +2. Bir **CLI kullanıcısı** olarak, korumalı sunuculara bağlanabilmem için MCP araçları oluştururken kimlik doğrulama belirteçleri ayarlamak istiyorum. +3. Bir **sistem yöneticisi** olarak, hangi MCP araçlarının kimlik doğrulamasının yapılandırıldığını görmek istiyorum, böylece güvenlik ayarlarını denetleyebilirim. + +## Tasarım + +### Yüksek Seviyeli Mimari +Taşıyıcı belirteç kimlik doğrulaması desteği için MCP aracı yapılandırmasını ve hizmetini genişletin: +1. MCP aracı yapılandırma şemasına isteğe bağlı bir `auth-token` alanı ekleyin. +2. Kimlik doğrulama belirteci yapılandırıldığında, MCP aracı hizmetinin kimlik doğrulama belirteci okuyup HTTP istemcisine iletmesini sağlayın. +3. Kimlik doğrulama belirteçleri ayarlamak ve görüntülemek için CLI araçlarını güncelleyin. +4. Güvenlik hususlarını ve en iyi uygulamaları belgeleyin. + +### Yapılandırma Şeması + +**Mevcut Şema**: +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +**Yeni Şema** (isteğe bağlı kimlik doğrulama jetonu ile): +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api", + "auth-token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} +``` + +**Alan Açıklamaları**: +`remote-name` (isteğe bağlı): MCP sunucusu tarafından kullanılan isim (varsayılan olarak yapılandırma anahtarı) +`url` (gerekli): MCP sunucusu uç noktası URL'si +`auth-token` (isteğe bağlı): Kimlik doğrulama için kullanılan taşıyıcı belirteci + +### Veri Akışı + +1. **Yapılandırma Depolama**: Kullanıcı `tg-set-mcp-tool --id my-tool --tool-url http://server/api --auth-token xyz123`'ı çalıştırır +2. **Yapılandırma Yükleme**: MCP aracı hizmeti, `on_mcp_config()` geri çağırması aracılığıyla yapılandırma güncellemelerini alır +3. **Araç Çağrısı**: Araç çağrıldığında: + Hizmet, yapılandırmadan `auth-token`'ı okur (varsa) + Başlıklar sözlüğünü oluşturur: `{"Authorization": "Bearer {token}"}` + Başlıkları `streamablehttp_client(url, headers=headers)`'a iletir + MCP sunucusu belirteci doğrular ve isteği işler + +### API Değişiklikleri +Harici API değişiklikleri yok - yalnızca yapılandırma şeması uzantısı. + +### Bileşen Detayları + +#### Bileşen 1: service.py (MCP Aracı Hizmeti) +**Dosya**: `trustgraph-flow/trustgraph/agent/mcp_tool/service.py` + +**Amaç**: Uzak sunuculardaki MCP araçlarını çağırmak + +**Gerekli Değişiklikler** (`invoke_tool()` yönteminde): +1. `auth-token`'ın `self.mcp_services[name]` yapılandırmasında olup olmadığını kontrol edin +2. Belirteç varsa, Authorization başlığıyla başlıklar sözlüğünü oluşturun +3. Başlıkları `streamablehttp_client(url, headers=headers)`'a iletin + +**Mevcut Kod** (42-89 satırları): +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server + async with streamablehttp_client(url) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method +``` + +**Değiştirilmiş Kod:** +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + # Build headers with optional bearer token + headers = {} + if "auth-token" in self.mcp_services[name]: + token = self.mcp_services[name]["auth-token"] + headers["Authorization"] = f"Bearer {token}" + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server with headers + async with streamablehttp_client(url, headers=headers) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method (unchanged) +``` + +#### Bileşen 2: set_mcp_tool.py (CLI Yapılandırma Aracı) +**Dosya**: `trustgraph-cli/trustgraph/cli/set_mcp_tool.py` + +**Amaç**: MCP aracı yapılandırmalarını oluşturma/güncelleme + +**Gerekli Değişiklikler**: +1. `--auth-token` isteğe bağlı argümanı argparse'a ekleyin +2. Sağlandığında, `auth-token`'yi yapılandırma JSON'una dahil edin + +**Mevcut Argümanlar**: +`--id` (gerekli): MCP aracı tanımlayıcısı +`--remote-name` (isteğe bağlı): Uzak MCP aracı adı +`--tool-url` (gerekli): MCP aracı URL uç noktası +`-u, --api-url` (isteğe bağlı): TrustGraph API URL'si + +**Yeni Argüman**: +`--auth-token` (isteğe bağlı): Kimlik doğrulama için taşıyıcı belirteci + +**Değiştirilmiş Yapılandırma Oluşturma**: +```python +# Build configuration object +config = { + "url": args.tool_url, +} + +if args.remote_name: + config["remote-name"] = args.remote_name + +if args.auth_token: + config["auth-token"] = args.auth_token + +# Store configuration +api.config().put([ + ConfigValue(type="mcp", key=args.id, value=json.dumps(config)) +]) +``` + +#### Bileşen 3: show_mcp_tools.py (CLI Görüntüleme Aracı) +**Dosya**: `trustgraph-cli/trustgraph/cli/show_mcp_tools.py` + +**Amaç**: MCP araç yapılandırmalarını görüntülemek + +**Gerekli Değişiklikler**: +1. Çıktı tablosuna "Auth" sütununu ekleyin +2. "auth-token" varlığına bağlı olarak "Evet" veya "Hayır" görüntüleyin +3. Gerçek token değerini görüntülemeyin (güvenlik) + +**Mevcut Çıktı**: +``` +ID Remote Name URL +---------- ------------- ------------------------ +my-tool my-tool http://server:3000/api +``` + +**Yeni Çıktı**: +``` +ID Remote Name URL Auth +---------- ------------- ------------------------ ------ +my-tool my-tool http://server:3000/api Yes +other-tool other-tool http://other:3000/api No +``` + +#### Bileşen 4: Belgeler +**Dosya**: `docs/cli/tg-set-mcp-tool.md` + +**Gerekli Değişiklikler**: +1. Yeni `--auth-token` parametresini belgeleyin +2. Kimlik doğrulama ile örnek kullanım sağlayın +3. Güvenlik hususlarını belgeleyin + +## Uygulama Planı + +### Aşama 1: Teknik Özellikleri Oluşturma +[x] Tüm değişiklikleri belgeleyen kapsamlı bir teknik özellik yazın + +### Aşama 2: MCP Araç Hizmetini Güncelleme +[ ] `service.py` içindeki `invoke_tool()`'ı, auth-token'ı yapılandırmadan okumak için değiştirin +[ ] Başlıklar sözlüğünü oluşturun ve `streamablehttp_client`'a iletin +[ ] Kimliği doğrulanmış bir MCP sunucusuyla test edin + +### Aşama 3: CLI Araçlarını Güncelleme +[ ] `set_mcp_tool.py`'e `--auth-token` argümanını ekleyin +[ ] auth-token'ı yapılandırma JSON'unda dahil edin +[ ] `show_mcp_tools.py` çıktısına "Auth" sütununu ekleyin +[ ] CLI araç değişikliklerini test edin + +### Aşama 4: Belgeleri Güncelleme +[ ] `tg-set-mcp-tool.md` içindeki `--auth-token` parametresini belgeleyin +[ ] Güvenlik hususları bölümünü ekleyin +[ ] Örnek kullanım sağlayın + +### Aşama 5: Test +[ ] MCP aracının auth-token ile başarıyla bağlandığını test edin +[ ] Geriye dönük uyumluluğu test edin (auth-token olmadan çalışan araçlar) +[ ] CLI araçlarının auth-token'ı doğru şekilde kabul ettiğini ve depoladığını test edin +[ ] "show" komutunun auth durumunu doğru şekilde gösterdiğini test edin + +### Kod Değişiklikleri Özeti +| Dosya | Değişiklik Türü | Satırlar | Açıklama | +|------|------------|-------|-------------| +| `service.py` | Değiştirildi | ~52-66 | auth-token okuma ve başlık oluşturma ekleyin | +| `set_mcp_tool.py` | Değiştirildi | ~30-60 | --auth-token argümanı ve yapılandırma depolama ekleyin | +| `show_mcp_tools.py` | Değiştirildi | ~40-70 | Görüntüleme için "Auth" sütununu ekleyin | +| `tg-set-mcp-tool.md` | Değiştirildi | Çeşitli | Yeni parametreyi belgeleyin | + +## Test Stratejisi + +### Birim Testleri +**Auth Token Okuma**: `invoke_tool()`'ın auth-token'ı yapılandırmadan doğru şekilde okuduğunu test edin +**Başlık Oluşturma**: Authorization başlığının Bearer öneki ile doğru şekilde oluşturulduğunu test edin +**Geriye Dönük Uyumluluk**: auth-token olmadan çalışan araçların değişmeden çalıştığını test edin +**CLI Argümanı Ayrıştırma**: `--auth-token` argümanının doğru şekilde ayrıştırıldığını test edin + +### Entegrasyon Testleri +**Kimliği Doğrulanmış Bağlantı**: MCP araç hizmetinin kimliği doğrulanmış bir sunucuya bağlandığını test edin +**Uçtan Uca**: CLI → yapılandırma depolama → auth token ile hizmet çağrısını test edin +**Token Gerekli Değil**: Kimliği doğrulanmamış bir sunucuya bağlantının hala çalıştığını test edin + +### Manuel Testler +**Gerçek MCP Sunucusu**: bearer token kimlik doğrulaması gerektiren gerçek bir MCP sunucusuyla test edin +**CLI İş Akışı**: Tam iş akışını test edin: aracı auth ile yapılandır → aracı çağır → başarıyı doğrulayın +**Görüntü Maskeleme**: auth durumunun gösterildiğini ancak token değerinin görünmediğini doğrulayın + +## Göç ve Dağıtım + +### Göç Stratejisi +Göç gerektirmez - bu tamamen ek bir işlevsellik: +`auth-token` içermeyen mevcut MCP araç yapılandırmaları çalışmaya devam eder +Yeni yapılandırmalar isteğe bağlı olarak `auth-token` alanını içerebilir +CLI araçları `--auth-token` parametresini kabul eder, ancak gerektirmez + +### Dağıtım Planı +1. **Aşama 1**: Temel hizmet değişikliklerini geliştirme/hazırlık ortamına dağıtın +2. **Aşama 2**: CLI araç güncellemelerini dağıtın +3. **Aşama 3**: Belgeleri güncelleyin +4. **Aşama 4**: İzleme ile üretim dağıtımı + +### Geri Alma Planı +Temel değişiklikler geriye dönük uyumludur - mevcut araçlar etkilenmez +Sorunlar ortaya çıkarsa, auth-token işleme, başlık oluşturma mantığını kaldırarak devre dışı bırakılabilir +CLI değişiklikleri bağımsızdır ve ayrı olarak geri alınabilir + +## Güvenlik Hususları + +### ⚠️ Kritik Sınırlama: Yalnızca Tek Kiracılı Kimlik Doğrulama + +**Bu kimlik doğrulama mekanizması, çok kullanıcılı veya çok kiracılı ortamlar için UYGUN DEĞİLDİR.** + +**Paylaşılan kimlik bilgiler**: Tüm kullanıcılar ve çağrılar, her MCP aracı için aynı token'ı paylaşır +**Kullanıcı bağlamı yok**: MCP sunucusu, farklı TrustGraph kullanıcıları arasında ayrım yapamaz +**Kiracı yalıtımı yok**: Tüm kiracılar, her MCP aracı için aynı kimlik bilgilerini paylaşır +**Denetim izi sınırlaması**: MCP sunucusu, aynı kimlik bilgilerinden gelen tüm istekleri günlüğe kaydeder +**İzin kapsamı**: Farklı kullanıcılara farklı izin seviyeleri uygulanamaz + +**Bu özelliği KULLANMAYIN eğer:** +TrustGraph dağıtımınız birden fazla kuruluşu (çok kiracılı) hizmet veriyorsa +Hangi kullanıcının hangi MCP aracına eriştiğini izlemeniz gerekiyorsa +Farklı kullanıcıların farklı izin seviyelerine ihtiyacı varsa +Kullanıcı düzeyinde denetim gereksinimlerine uymanız gerekiyorsa +MCP sunucunuz kullanıcı başına hız sınırlamaları veya kotaları uyguluyorsa + +**Çok kullanıcılı/çok kiracılı senaryolar için alternatif çözümler:** +Özel başlıklar aracılığıyla kullanıcı bağlamı yayılımını uygulayın +Her kiracı için ayrı TrustGraph örnekleri dağıtın +Ağ seviyesinde izolasyon kullanın (VPC'ler, hizmet ağları) +Her kullanıcı için kimlik doğrulamayı yöneten bir ara katman uygulayın + +### Token Depolama +**Risk**: Kimlik doğrulama jetonları yapılandırma sisteminde düz metin olarak saklanır + +**Giderilmesi Gereken Durum:** +Jetonların şifrelenmeden saklandığını belgeleyin +Mümkün olduğunda kısa ömürlü jetonlar kullanılması önerin +Yapılandırma depolaması için uygun erişim kontrolü kullanılması önerin +Şifrelenmiş jeton depolama için gelecekteki bir iyileştirmeyi düşünün + +### Jetonun Açığa Çıkarılması +**Risk**: Jetonlar günlüklerde veya CLI çıktısında açığa çıkabilir + +**Giderilmesi Gereken Durum:** +Jeton değerlerini kaydetmeyin (sadece "kimlik doğrulama yapılandırıldı: evet/hayır" kaydını tutun) +CLI göster komutu yalnızca maskelenmiş durumu gösterir, gerçek jetonu göstermez +Jetonları hata mesajlarında dahil etmeyin + +### Ağ Güvenliği +**Risk**: Jetonlar şifrelenmemiş bağlantılar üzerinden iletilir + +**Giderilmesi Gereken Durum:** +MCP sunucuları için HTTPS URL'lerinin kullanılması önerisi belgelendirilmelidir +HTTP ile düz metin iletim riskine ilişkin kullanıcılara uyarı verilmelidir + +### Yapılandırma Erişimi +**Risk**: Yapılandırma sistemine yetkisiz erişim, jetonları açığa çıkarır + +**Giderilmesi Gereken Durum:** +Yapılandırma sistemi erişiminin güvenliğinin önemini belgeleyin +Yapılandırma erişimi için en az ayrıcalık ilkesi önerin +Yapılandırma değişiklikleri için denetim günlüğü almayı düşünün (gelecekteki iyileştirme) + +### Çok Kullanıcılı Ortamlar +**Risk**: Çok kullanıcılı dağıtımlarda, tüm kullanıcılar aynı MCP kimlik bilgilerini paylaşır + +**Riskin Anlaşılması:** +Kullanıcı A ve Kullanıcı B, bir MCP aracını kullanırken aynı jetonu kullanır +MCP sunucusu, farklı TrustGraph kullanıcıları arasında ayrım yapamaz +Kullanıcı başına izinleri veya hız sınırlamalarını uygulama imkanı yoktur +MCP sunucusundaki denetim günlükleri, aynı kimlik bilgilerinden gelen tüm istekleri gösterir +Bir kullanıcının oturumu tehlikeye girerse, saldırganın tüm kullanıcılar kadar aynı MCP erişimi vardır + +**Bu bir hata DEĞİLDİR - bu tasarımın temel bir sınırlamasıdır.** + +## Performans Etkisi +**Minimum ek yük**: Başlık oluşturma, ihmal edilebilir bir işlem süresi ekler +**Ağ etkisi**: Ek HTTP başlığı, istek başına yaklaşık 50-200 bayt ekler +**Bellek kullanımı**: Yapılandırmada jeton dizesini depolamak için ihmal edilebilir bir artış + +## Belgeler + +### Kullanıcı Belgeleri +[ ] `tg-set-mcp-tool.md`'ı `--auth-token` parametresiyle güncelleyin +[ ] Güvenlik hususları bölümü ekleyin +[ ] Bir örnek kullanım senaryosuyla birlikte taşıyıcı jetonu sağlayın +[ ] Jeton depolama etkilerini belgeleyin + +### Geliştirici Belgeleri +[ ] `service.py` içindeki kimlik doğrulama jetonu işleme için satır içi yorumlar ekleyin +[ ] Başlık oluşturma mantığını belgeleyin +[ ] MCP aracı yapılandırma şeması belgelerini güncelleyin + +## Açık Sorular +1. **Jeton şifreleme**: Yapılandırma sisteminde şifrelenmiş jeton depolamayı uygulamalı mıyız? +2. **Jeton yenileme**: OAuth yenileme akışları veya jeton rotasyonu için gelecekteki destek? +3. **Alternatif kimlik doğrulama yöntemleri**: Temel kimlik doğrulama, API anahtarları veya diğer yöntemleri desteklemeli miyiz? + +## Değerlendirilen Alternatifler + +1. **Jetonlar için ortam değişkenleri**: Jetonları yapılandırma yerine ortam değişkenlerinde saklayın + **Reddedildi**: Dağıtımı ve yapılandırma yönetimini karmaşıklaştırır + +2. **Ayrı gizli anahtar deposu**: Özel bir gizli anahtar yönetim sistemi kullanın + **Erteleme**: Başlangıç uygulaması kapsamı dışındadır, gelecekteki bir iyileştirme olarak düşünün + +3. **Çoklu kimlik doğrulama yöntemleri**: Temel, API anahtarı, OAuth vb. destekleyin + **Reddedildi**: Taşıyıcı jetonlar çoğu kullanım durumunu kapsar, başlangıç uygulamasını basit tutun + +4. **Şifrelenmiş jeton depolama**: Jetonları yapılandırma sisteminde şifreleyin + **Erteleme**: Yapılandırma sistemi güvenliği daha geniş bir endişedir, gelecekteki çalışmalara bırakın + +5. **Her çağrı için jetonlar**: Jetonların çağrı zamanında geçirilmesine izin verin + **Reddedildi**: Endişe ayrımını ihlal eder, aracının kimlik bilgilerini işlemesi gerekmez + +## Referanslar +[MCP Protokolü Özellikleri](https://github.com/modelcontextprotocol/spec) +[HTTP Taşıyıcı Kimlik Doğrulaması (RFC 6750)](https://tools.ietf.org/html/rfc6750) +[Mevcut MCP Aracı Hizmeti](../trustgraph-flow/trustgraph/agent/mcp_tool/service.py) +[MCP Aracı Argümanları Özellikleri](./mcp-tool-arguments.md) + +## Ek + +### Örnek Kullanım + +**Kimlik doğrulama ile MCP aracının yapılandırılması:** +```bash +tg-set-mcp-tool \ + --id secure-tool \ + --tool-url https://secure-server.example.com/mcp \ + --auth-token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +``` + +**MCP araçlarını göster:** +```bash +tg-show-mcp-tools + +ID Remote Name URL Auth +----------- ----------- ------------------------------------ ------ +secure-tool secure-tool https://secure-server.example.com/mcp Yes +public-tool public-tool http://localhost:3000/mcp No +``` + +### Yapılandırma Örneği + +**Yapılandırma sisteminde saklanır**: +```json +{ + "type": "mcp", + "key": "secure-tool", + "value": "{\"url\": \"https://secure-server.example.com/mcp\", \"auth-token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\"}" +} +``` + +### Güvenlik En İyi Uygulamaları + +1. **HTTPS Kullanımı**: Kimlik doğrulama ile çalışan MCP sunucuları için her zaman HTTPS URL'lerini kullanın. +2. **Kısa Ömürlü Token'lar**: Mümkün olduğunda, son kullanma tarihine sahip token'lar kullanın. +3. **En Az Yetki**: Token'lara, yalnızca gerekli olan minimum izinleri verin. +4. **Erişim Kontrolü**: Yapılandırma sistemine erişimi kısıtlayın. +5. **Token Döndürme**: Token'ları düzenli olarak değiştirin. +6. **Denetim Kayıtları**: Güvenlik olayları için yapılandırma değişikliklerini izleyin. diff --git a/docs/tech-specs/mcp-tool-bearer-token.zh-cn.md b/docs/tech-specs/mcp-tool-bearer-token.zh-cn.md new file mode 100644 index 00000000..52ef9010 --- /dev/null +++ b/docs/tech-specs/mcp-tool-bearer-token.zh-cn.md @@ -0,0 +1,554 @@ +# MCP 工具承载令牌身份验证规范 + +> **⚠️ 重要提示:仅限单租户环境** +> +> 本规范描述了一种用于 MCP 工具的**基本服务级别身份验证机制**。它**不是**一个完整的身份验证解决方案,**不适用于**以下情况: +> - 多用户环境 +> - 多租户部署 +> - 联合身份验证 +> - 用户上下文传播 +> - 基于用户的授权 +> +> 此功能为**每个 MCP 工具提供一个静态令牌**,该令牌在所有用户和会话中共享。 如果您需要基于用户的身份验证或基于租户的身份验证,则此功能不适合您。 + +## 概述 +**功能名称**: MCP 工具承载令牌身份验证支持 +**作者**: Claude 代码助手 +**日期**: 2025-11-11 +**状态**: 正在开发中 + +### 执行摘要 + +允许 MCP 工具配置指定可选的承载令牌,用于对受保护的 MCP 服务器进行身份验证。 这允许 TrustGraph 安全地调用托管在需要身份验证的服务器上的 MCP 工具,而无需修改代理或工具调用接口。 + +**重要提示**: 这是一个基本身份验证机制,旨在用于单租户、服务到服务的身份验证场景。 它**不适用于**以下情况: +需要不同用户凭据的多用户环境 +需要每个租户隔离的多租户部署 +联合身份验证场景 +基于用户的身份验证或授权 +动态凭据管理或令牌刷新 + +此功能为每个 MCP 工具配置提供一个静态、系统范围的承载令牌,该令牌在所有用户和该工具的调用中共享。 + +### 问题陈述 + +目前,MCP 工具只能连接到公共可访问的 MCP 服务器。 许多生产 MCP 部署需要通过承载令牌进行身份验证以提高安全性。 如果没有身份验证支持: +MCP 工具无法连接到受保护的 MCP 服务器 +用户必须要么公开 MCP 服务器,要么实现反向代理 +没有一种标准化的方法将凭据传递给 MCP 连接 +无法在 MCP 终端节点上强制执行安全最佳实践 + +### 目标 + +[ ] 允许 MCP 工具配置指定可选的 `auth-token` 参数 +[ ] 更新 MCP 工具服务,使其在连接到 MCP 服务器时使用承载令牌 +[ ] 更新 CLI 工具以支持设置/显示身份验证令牌 +[ ] 保持与未进行身份验证的 MCP 配置的向后兼容性 +[ ] 记录令牌存储的安全注意事项 + +### 非目标 +动态令牌刷新或 OAuth 流程(仅限静态令牌) +存储令牌的加密(配置系统安全性不在范围之内) +替代身份验证方法(基本身份验证、API 密钥等) +令牌验证或到期检查 +**基于用户的身份验证**: 此功能**不支持**用户特定的凭据 +**多租户隔离**: 此功能**不提供**基于租户的令牌管理 +**联合身份验证**: 此功能**不与**身份提供商(SSO、OAuth、SAML 等)集成 +**基于上下文的身份验证**: 令牌不是基于用户上下文或会话传递的 + +## 背景和上下文 + +### 当前状态 +MCP 工具配置存储在 `mcp` 配置组中,具有以下结构: +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +MCP 工具服务使用 `streamablehttp_client(url)` 连接到服务器,而无需任何身份验证头信息。 + +### 限制 + +**当前系统限制:** +1. **不支持身份验证:** 无法连接到需要身份验证的 MCP 服务器。 +2. **安全风险:** MCP 服务器必须是公开可访问的,或者仅使用网络级别的安全措施。 +3. **生产部署问题:** 无法遵循 API 端点的安全最佳实践。 + +**此解决方案的限制:** +1. **仅支持单租户:** 每个 MCP 工具只有一个静态令牌,所有用户共享该令牌。 +2. **不支持按用户身份验证:** 无法以不同的用户身份进行身份验证,也无法传递用户上下文。 +3. **不支持多租户:** 无法按租户或组织隔离凭据。 +4. **仅支持静态令牌:** 不支持令牌刷新、轮换或过期处理。 +5. **服务级别身份验证:** 仅对 TrustGraph 服务进行身份验证,而不是对单个用户进行身份验证。 +6. **共享安全上下文:** 对 MCP 工具的所有调用都使用相同的凭据。 + +### 使用场景适用性 + +**✅ 适用场景:** +单租户 TrustGraph 部署。 +服务到服务身份验证(TrustGraph → MCP 服务器)。 +开发和测试环境。 +TrustGraph 系统访问的内部 MCP 工具。 +所有用户共享相同 MCP 工具访问级别的场景。 +静态、长期有效的服务凭据。 + +**❌ 不适用场景:** +需要按用户身份验证的多用户系统。 +需要租户隔离的多租户 SaaS 部署。 +联合身份验证场景(SSO、OAuth、SAML)。 +需要将用户上下文传播到 MCP 服务器的系统。 +需要动态令牌刷新或短生命周期的令牌的环境。 +不同的用户需要不同权限级别的应用程序。 +用户级别审计跟踪的合规性要求。 + +**示例适用场景:** +单个组织的 TrustGraph 部署,其中所有员工都使用相同的内部 MCP 工具(例如,公司数据库查询)。MCP 服务器需要身份验证以防止外部访问,但所有内部用户都具有相同的访问级别。 + +**示例不适用场景:** +一个多租户 TrustGraph SaaS 平台,其中租户 A 和租户 B 需要访问各自隔离的 MCP 服务器,并使用不同的凭据。此功能不支持按租户管理令牌。 + +### 相关组件 +**trustgraph-flow/trustgraph/agent/mcp_tool/service.py**: MCP 工具调用服务。 +**trustgraph-cli/trustgraph/cli/set_mcp_tool.py**: 用于创建/更新 MCP 配置的 CLI 工具。 +**trustgraph-cli/trustgraph/cli/show_mcp_tools.py**: 用于显示 MCP 配置的 CLI 工具。 +**MCP Python SDK**: `streamablehttp_client` from `mcp.client.streamable_http` + +## 要求 + +### 功能性要求 + +1. **MCP 配置身份验证令牌:** MCP 工具配置必须支持一个可选的 `auth-token` 字段。 +2. **Bearer 令牌使用:** 当配置了 auth-token 时,MCP 工具服务必须发送 `Authorization: Bearer {token}` 头信息。 +3. **CLI 支持:** `tg-set-mcp-tool` 必须接受一个可选的 `--auth-token` 参数。 +4. **令牌显示:** `tg-show-mcp-tools` 必须指示是否配置了 auth-token(出于安全考虑,已屏蔽)。 +5. **向后兼容性:** 现有不带 auth-token 的 MCP 工具配置必须继续正常工作。 + +### 非功能性要求 +1. **向后兼容性:** 对于现有的 MCP 工具配置,不得有任何破坏性更改。 +2. **性能:** 对 MCP 工具的调用不会产生任何显著的性能影响。 +3. **安全性:** 令牌存储在配置中(请注意安全隐患)。 + +### 用户故事 + +1. 作为 **DevOps 工程师**,我希望配置 MCP 工具的 bearer 令牌,以便我可以保护 MCP 服务器端点。 +2. 作为 **CLI 用户**,我希望在创建 MCP 工具时设置身份验证令牌,以便我可以连接到受保护的服务器。 +3. 作为 **系统管理员**,我希望查看哪些 MCP 工具配置了身份验证,以便我可以审计安全设置。 + +## 设计 + +### 高级架构 +扩展 MCP 工具配置和服务以支持 bearer 令牌身份验证: +1. 向 MCP 工具配置模式添加一个可选的 `auth-token` 字段。 +2. 修改 MCP 工具服务以读取 auth-token 并将其传递给 HTTP 客户端。 +3. 更新 CLI 工具以支持设置和显示身份验证令牌。 +4. 记录安全注意事项和最佳实践。 + +### 配置模式 + +**当前模式:** +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api" +} +``` + +**新的模式**(带可选的认证令牌): +```json +{ + "remote-name": "tool_name", + "url": "http://mcp-server:3000/api", + "auth-token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} +``` + +**字段描述**: +`remote-name` (可选): MCP 服务器使用的名称(默认为配置键) +`url` (必需): MCP 服务器端点 URL +`auth-token` (可选): 用于身份验证的 Bearer token + +### 数据流 + +1. **配置存储**: 用户运行 `tg-set-mcp-tool --id my-tool --tool-url http://server/api --auth-token xyz123` +2. **配置加载**: MCP 工具服务通过 `on_mcp_config()` 回调接收配置更新 +3. **工具调用**: 当工具被调用时: + 服务从配置中读取 `auth-token`(如果存在) + 创建 headers 字典:`{"Authorization": "Bearer {token}"}` + 将 headers 传递给 `streamablehttp_client(url, headers=headers)` + MCP 服务器验证 token 并处理请求 + +### API 变更 +没有外部 API 变更,仅为配置模式扩展。 + +### 组件详情 + +#### 组件 1: service.py (MCP 工具服务) +**文件**: `trustgraph-flow/trustgraph/agent/mcp_tool/service.py` + +**目的**: 在远程服务器上调用 MCP 工具 + +**所需变更**(在 `invoke_tool()` 方法中): +1. 检查 `auth-token` 是否在 `self.mcp_services[name]` 配置中 +2. 如果 token 存在,则构建包含 Authorization header 的 headers 字典 +3. 将 headers 传递给 `streamablehttp_client(url, headers=headers)` + +**当前代码**(42-89 行): +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server + async with streamablehttp_client(url) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method +``` + +**修改后的代码**: +```python +async def invoke_tool(self, name, parameters): + try: + if name not in self.mcp_services: + raise RuntimeError(f"MCP service {name} not known") + if "url" not in self.mcp_services[name]: + raise RuntimeError(f"MCP service {name} URL not defined") + + url = self.mcp_services[name]["url"] + + if "remote-name" in self.mcp_services[name]: + remote_name = self.mcp_services[name]["remote-name"] + else: + remote_name = name + + # Build headers with optional bearer token + headers = {} + if "auth-token" in self.mcp_services[name]: + token = self.mcp_services[name]["auth-token"] + headers["Authorization"] = f"Bearer {token}" + + logger.info(f"Invoking {remote_name} at {url}") + + # Connect to a streamable HTTP server with headers + async with streamablehttp_client(url, headers=headers) as ( + read_stream, + write_stream, + _, + ): + # ... rest of method (unchanged) +``` + +#### 组件 2: set_mcp_tool.py (命令行配置工具) +**文件**: `trustgraph-cli/trustgraph/cli/set_mcp_tool.py` + +**目的**: 创建/更新 MCP 工具配置 + +**所需更改**: +1. 向 argparse 添加 `--auth-token` 可选参数 +2. 在提供时,将 `auth-token` 包含在配置 JSON 中 + +**当前参数**: +`--id` (必需): MCP 工具标识符 +`--remote-name` (可选): 远程 MCP 工具名称 +`--tool-url` (必需): MCP 工具 URL 端点 +`-u, --api-url` (可选): TrustGraph API URL + +**新参数**: +`--auth-token` (可选): 用于身份验证的 Bearer token + +**修改后的配置构建**: +```python +# Build configuration object +config = { + "url": args.tool_url, +} + +if args.remote_name: + config["remote-name"] = args.remote_name + +if args.auth_token: + config["auth-token"] = args.auth_token + +# Store configuration +api.config().put([ + ConfigValue(type="mcp", key=args.id, value=json.dumps(config)) +]) +``` + +#### 组件 3:show_mcp_tools.py (命令行显示工具) +**文件**: `trustgraph-cli/trustgraph/cli/show_mcp_tools.py` + +**目的**: 显示 MCP 工具的配置 + +**需要修改的内容**: +1. 在输出表中添加 "Auth" 列 +2. 根据是否存在 auth-token 显示 "是" 或 "否" +3. 不要显示实际的 token 值(出于安全考虑) + +**当前输出**: +``` +ID Remote Name URL +---------- ------------- ------------------------ +my-tool my-tool http://server:3000/api +``` + +**新的输出:** +``` +ID Remote Name URL Auth +---------- ------------- ------------------------ ------ +my-tool my-tool http://server:3000/api Yes +other-tool other-tool http://other:3000/api No +``` + +#### 组件 4:文档 +**文件**: `docs/cli/tg-set-mcp-tool.md` + +**需要修改的内容**: +1. 文档新的 `--auth-token` 参数 +2. 提供带有身份验证的示例用法 +3. 文档安全注意事项 + +## 实施计划 + +### 第一阶段:创建技术规范 +[x] 编写全面的技术规范,记录所有更改 + +### 第二阶段:更新 MCP 工具服务 +[ ] 修改 `invoke_tool()` 中的 `service.py` 以从配置文件读取 auth-token +[ ] 构建 headers 字典并传递给 `streamablehttp_client` +[ ] 使用经过身份验证的 MCP 服务器进行测试 + +### 第三阶段:更新 CLI 工具 +[ ] 向 `set_mcp_tool.py` 添加 `--auth-token` 参数 +[ ] 在配置 JSON 中包含 auth-token +[ ] 向 `show_mcp_tools.py` 的输出添加 "Auth" 列 +[ ] 测试 CLI 工具的更改 + +### 第四阶段:更新文档 +[ ] 在 `tg-set-mcp-tool.md` 中记录 `--auth-token` 参数 +[ ] 添加安全注意事项部分 +[ ] 提供示例用法 + +### 第五阶段:测试 +[ ] 测试 MCP 工具是否能够使用 auth-token 成功连接 +[ ] 测试向后兼容性(没有 auth-token 的工具仍然可以工作) +[ ] 测试 CLI 工具是否能够正确接受和存储 auth-token +[ ] 测试 "show" 命令是否能够正确显示身份验证状态 + +### 代码更改摘要 +| 文件 | 更改类型 | 行数 | 描述 | +|------|------------|-------|-------------| +| `service.py` | 修改 | ~52-66 | 添加 auth-token 读取和 header 构建 | +| `set_mcp_tool.py` | 修改 | ~30-60 | 添加 --auth-token 参数和配置存储 | +| `show_mcp_tools.py` | 修改 | ~40-70 | 向显示添加 Auth 列 | +| `tg-set-mcp-tool.md` | 修改 | 各种 | 文档新的参数 | + +## 测试策略 + +### 单元测试 +**Auth Token 读取**: 测试 `invoke_tool()` 是否能够正确从配置文件读取 auth-token +**Header 构建**: 测试 Authorization header 是否能够使用 Bearer 前缀正确构建 +**向后兼容性**: 测试没有 auth-token 的工具是否能够正常工作 +**CLI 参数解析**: 测试 `--auth-token` 参数是否能够正确解析 + +### 集成测试 +**经过身份验证的连接**: 测试 MCP 工具服务是否能够连接到经过身份验证的服务器 +**端到端**: 测试 CLI → 配置文件存储 → 服务调用,并使用 auth token +**不需要 Token**: 测试连接到未经过身份验证的服务器是否仍然可以工作 + +### 手动测试 +**真实的 MCP 服务器**: 使用需要 bearer token 身份验证的实际 MCP 服务器进行测试 +**CLI 工作流程**: 测试完整的流程:使用 auth 设置工具 → 调用工具 → 验证成功 +**显示屏蔽**: 验证身份验证状态显示,但 token 值不暴露 + +## 迁移和发布 + +### 迁移策略 +不需要迁移 - 这是一个纯粹的附加功能: +现有的 MCP 工具配置,如果没有 `auth-token`,可以继续正常工作 +新的配置可以选择包含 `auth-token` 字段 +CLI 工具接受,但不要求 `--auth-token` 参数 + +### 发布计划 +1. **第一阶段**: 将核心服务更改部署到开发/测试环境 +2. **第二阶段**: 部署 CLI 工具更新 +3. **第三阶段**: 更新文档 +4. **第四阶段**: 生产发布,并进行监控 + +### 回滚计划 +核心更改是向后兼容的 - 现有的工具不受影响 +如果出现问题,可以通过删除 header 构建逻辑来禁用身份验证 token 处理 +CLI 更改是独立的,并且可以单独回滚 + +## 安全注意事项 + +### ⚠️ 关键限制:仅支持单租户身份验证 + +**此身份验证机制不适用于多用户或多租户环境。** + +**共享凭据**: 所有用户和调用都共享每个 MCP 工具的相同 token +**没有用户上下文**: MCP 服务器无法区分不同的 TrustGraph 用户 +**没有租户隔离**: 所有租户共享每个 MCP 工具的相同凭据 +**审计跟踪限制**: MCP 服务器日志显示来自相同凭据的所有请求 +**权限范围**: 无法为不同的用户强制执行不同的权限级别 + +**不要使用此功能,如果:** +您的 TrustGraph 部署服务于多个组织(多租户) +您需要跟踪哪些用户访问了哪些 MCP 工具 +不同的用户需要不同的权限级别 +您需要遵守用户级别的审计要求 +您的 MCP 服务器强制执行每个用户的速率限制或配额 + +**多用户/多租户场景的替代方案:** +通过自定义头部实现用户上下文传播 +为每个租户部署独立的 TrustGraph 实例 +使用网络级别隔离(VPCs、服务网格) +实现一个代理层,该层处理每个用户的身份验证 + +### 令牌存储 +**风险:** 身份验证令牌以明文形式存储在配置系统中 + +**缓解措施:** +记录令牌以明文形式存储 +尽可能推荐使用短寿命令牌 +推荐对配置存储进行适当的访问控制 +考虑未来增强功能,用于加密令牌存储 + +### 令牌泄露 +**风险:** 令牌可能出现在日志或 CLI 输出中 + +**缓解措施:** +不要记录令牌值(仅记录“身份验证已配置:是/否”) +CLI 显示命令仅显示屏蔽状态,不显示实际令牌 +不要将令牌包含在错误消息中 + +### 网络安全 +**风险:** 令牌通过未加密的连接传输 + +**缓解措施:** +记录推荐使用 HTTPS URL 进行 MCP 服务器访问 +警告用户使用 HTTP 传输的明文风险 + +### 配置访问 +**风险:** 未授权访问配置系统会暴露令牌 + +**缓解措施:** +记录保护配置系统访问的重要性 +推荐对配置访问采用最小权限原则 +考虑对配置更改进行审计日志记录(未来增强功能) + +### 多用户环境 +**风险:** 在多用户部署中,所有用户共享相同的 MCP 凭据 + +**风险理解:** +用户 A 和用户 B 在访问 MCP 工具时都使用相同的令牌 +MCP 服务器无法区分不同的 TrustGraph 用户 +没有办法强制执行每个用户的权限或速率限制 +MCP 服务器上的审计日志显示来自相同凭据的所有请求 +如果一个用户的会话被盗,攻击者将拥有与所有用户相同的 MCP 访问权限 + +**这不是一个错误 - 这是一个该设计的基本限制。** + +## 性能影响 +**最小开销:** 头部构建添加了可忽略的处理时间 +**网络影响:** 额外的 HTTP 头部增加了每个请求约 50-200 字节 +**内存使用:** 存储在配置中的令牌字符串会增加可忽略的内存 + +## 文档 + +### 用户文档 +[ ] 使用 `--auth-token` 参数更新 `tg-set-mcp-tool.md` +[ ] 添加安全注意事项部分 +[ ] 提供使用 bearer 令牌的示例 +[ ] 记录令牌存储的影响 + +### 开发人员文档 +[ ] 在 `service.py` 中添加身份验证令牌处理的内联注释 +[ ] 记录头部构建逻辑 +[ ] 更新 MCP 工具配置模式文档 + +## 开放问题 +1. **令牌加密:** 我们是否应该在配置系统中实现加密令牌存储? +2. **令牌刷新:** 未来是否支持 OAuth 刷新流程或令牌轮换? +3. **替代身份验证方法:** 我们是否应该支持 Basic 身份验证、API 密钥或其他方法? + +## 考虑过的替代方案 + +1. **环境变量用于令牌:** 将令牌存储在环境变量中而不是配置中 + **已拒绝:** complicates deployment and configuration management (使部署和配置管理复杂化) + +2. **单独的密钥存储:** 使用专用的密钥管理系统 + **推迟:** Out of scope for initial implementation, consider future enhancement (超出初始实现的范围,考虑未来增强) + +3. **多种身份验证方法:** 支持 Basic、API 密钥、OAuth 等。 + **已拒绝:** Bearer tokens cover most use cases, keep initial implementation simple (Bearer 令牌涵盖大多数用例,保持初始实现的简单性) + +4. **加密令牌存储:** 在配置系统中加密令牌 + **推迟:** Configuration system security is broader concern, defer to future work (配置系统安全是一个更广泛的问题,推迟到未来工作) + +5. **按调用令牌:** 允许在调用时传递令牌 + **已拒绝:** Violates separation of concerns, agent shouldn't handle credentials (违反了关注点分离,代理不应处理凭据) + +## 引用 +[MCP 协议规范](https://github.com/modelcontextprotocol/spec) +[HTTP Bearer 身份验证 (RFC 6750)](https://tools.ietf.org/html/rfc6750) +[Current MCP Tool Service](../trustgraph-flow/trustgraph/agent/mcp_tool/service.py) +[MCP 工具参数规范](./mcp-tool-arguments.md) + +## 附录 + +### 用法示例 + +**设置带有身份验证的 MCP 工具:** +```bash +tg-set-mcp-tool \ + --id secure-tool \ + --tool-url https://secure-server.example.com/mcp \ + --auth-token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... +``` + +**展示 MCP 工具:** +```bash +tg-show-mcp-tools + +ID Remote Name URL Auth +----------- ----------- ------------------------------------ ------ +secure-tool secure-tool https://secure-server.example.com/mcp Yes +public-tool public-tool http://localhost:3000/mcp No +``` + +### 配置示例 + +**存储在配置系统中**: +```json +{ + "type": "mcp", + "key": "secure-tool", + "value": "{\"url\": \"https://secure-server.example.com/mcp\", \"auth-token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\"}" +} +``` + +### 安全最佳实践 + +1. **使用 HTTPS**: 始终为具有身份验证的 MCP 服务器使用 HTTPS URL。 +2. **短生命周期令牌**: 尽可能使用具有过期时间的令牌。 +3. **最小权限**: 授予令牌最低要求的权限。 +4. **访问控制**: 限制对配置系统的访问。 +5. **令牌轮换**: 定期轮换令牌。 +6. **审计日志记录**: 监控配置更改以检测安全事件。 diff --git a/docs/tech-specs/minio-to-s3-migration.ar.md b/docs/tech-specs/minio-to-s3-migration.ar.md new file mode 100644 index 00000000..65c86c6a --- /dev/null +++ b/docs/tech-specs/minio-to-s3-migration.ar.md @@ -0,0 +1,258 @@ +# المواصفات الفنية: دعم تخزين متوافق مع S3 + +## نظرة عامة + +تستخدم خدمة Librarian تخزين كائنات متوافق مع S3 لتخزين ملفات المستندات. توثق هذه المواصفة التنفيذ الذي يمكّن الدعم لأي نظام تخزين متوافق مع S3 بما في ذلك MinIO و Ceph RADOS Gateway (RGW) و AWS S3 و Cloudflare R2 و DigitalOcean Spaces وغيرها. + +## البنية + +### مكونات التخزين +**تخزين الكائنات (Blob Storage)**: تخزين كائنات متوافق مع S3 عبر مكتبة عميل Python `minio` +**تخزين البيانات الوصفية (Metadata Storage)**: Cassandra (تخزن مطابقة object_id وبيانات وصفية للمستندات) +**المكون المتأثر**: خدمة Librarian فقط +**نمط التخزين**: تخزين هجين مع البيانات الوصفية في Cassandra والمحتوى في تخزين متوافق مع S3 + +### التنفيذ +**المكتبة**: عميل Python `minio` (يدعم أي واجهة برمجة تطبيقات متوافقة مع S3) +**الموقع**: `trustgraph-flow/trustgraph/librarian/blob_store.py` +**العمليات**: + `add()` - تخزين كائن بمعرف كائن UUID + `get()` - استرجاع كائن بمعرف الكائن + `remove()` - حذف كائن بمعرف الكائن + `ensure_bucket()` - إنشاء حاوية إذا لم تكن موجودة +**الحاوية (Bucket)**: `library` +**مسار الكائن (Object Path)**: `doc/{object_id}` +**أنواع MIME المدعومة**: `text/plain`، `application/pdf` + +### الملفات الرئيسية +1. `trustgraph-flow/trustgraph/librarian/blob_store.py` - تطبيق BlobStore +2. `trustgraph-flow/trustgraph/librarian/librarian.py` - تهيئة BlobStore +3. `trustgraph-flow/trustgraph/librarian/service.py` - تكوين الخدمة +4. `trustgraph-flow/pyproject.toml` - التبعيات (حزمة `minio`) +5. `docs/apis/api-librarian.md` - وثائق API + +## أنظمة التخزين المدعومة + +يعمل هذا التنفيذ مع أي نظام تخزين كائنات متوافق مع S3: + +### تم الاختبار/مدعوم +**Ceph RADOS Gateway (RGW)** - نظام تخزين موزع مع واجهة برمجة تطبيقات S3 (التكوين الافتراضي) +**MinIO** - تخزين كائنات خفيف الوزن ومستضاف ذاتيًا +**Garage** - تخزين S3 متوافق وخفيف الوزن وموزع جغرافيًا + +### يجب أن يعمل (متوافق مع S3) +**AWS S3** - تخزين الكائنات السحابي من Amazon +**Cloudflare R2** - تخزين S3 متوافق من Cloudflare +**DigitalOcean Spaces** - تخزين الكائنات من DigitalOcean +**Wasabi** - تخزين سحابي متوافق مع S3 +**Backblaze B2** - تخزين نسخ احتياطي متوافق مع S3 +أي خدمة أخرى تنفذ واجهة برمجة تطبيقات S3 REST + +## التكوين + +### وسائط سطر الأوامر + +```bash +librarian \ + --object-store-endpoint \ + --object-store-access-key \ + --object-store-secret-key \ + [--object-store-use-ssl] \ + [--object-store-region ] +``` + +**ملاحظة:** لا تقم بتضمين `http://` أو `https://` في النهاية. استخدم `--object-store-use-ssl` لتمكين HTTPS. + +### متغيرات البيئة (بديل) + +```bash +OBJECT_STORE_ENDPOINT= +OBJECT_STORE_ACCESS_KEY= +OBJECT_STORE_SECRET_KEY= +OBJECT_STORE_USE_SSL=true|false # Optional, default: false +OBJECT_STORE_REGION= # Optional +``` + +### أمثلة + +**بوابة Ceph RADOS (افتراضيًا):** +```bash +--object-store-endpoint ceph-rgw:7480 \ +--object-store-access-key object-user \ +--object-store-secret-key object-password +``` + +**مينيو:** +```bash +--object-store-endpoint minio:9000 \ +--object-store-access-key minioadmin \ +--object-store-secret-key minioadmin +``` + +**مخزن (متوافق مع S3):** +```bash +--object-store-endpoint garage:3900 \ +--object-store-access-key GK000000000000000000000001 \ +--object-store-secret-key b171f00be9be4c32c734f4c05fe64c527a8ab5eb823b376cfa8c2531f70fc427 +``` + +**AWS S3 مع SSL:** +```bash +--object-store-endpoint s3.amazonaws.com \ +--object-store-access-key AKIAIOSFODNN7EXAMPLE \ +--object-store-secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \ +--object-store-use-ssl \ +--object-store-region us-east-1 +``` + +## المصادقة + +تتطلب جميع الواجهات الخلفية المتوافقة مع S3 مصادقة AWS Signature Version 4 (أو الإصدار 2): + +**مفتاح الوصول (Access Key)** - مُعرّف عام (مثل اسم المستخدم) +**المفتاح السري (Secret Key)** - مفتاح توقيع خاص (مثل كلمة المرور) + +يتعامل عميل MinIO بلغة Python مع جميع عمليات حساب التوقيع تلقائيًا. + +### إنشاء بيانات الاعتماد + +**لـ MinIO:** +```bash +# Use default credentials or create user via MinIO Console +minioadmin / minioadmin +``` + +**لـ Ceph RGW:** +```bash +radosgw-admin user create --uid="trustgraph" --display-name="TrustGraph Service" +# Returns access_key and secret_key +``` + +**لـ AWS S3:** +إنشاء مستخدم IAM مع أذونات S3. +إنشاء مفتاح وصول في وحدة تحكم AWS. + +## اختيار المكتبة: عميل MinIO Python + +**السبب:** +خفيف الوزن (~500 كيلوبايت مقابل ~50 ميجابايت لـ boto3). +متوافق مع S3 - يعمل مع أي نقطة نهاية S3. +واجهة برمجة تطبيقات أبسط من boto3 للعمليات الأساسية. +قيد الاستخدام بالفعل، لا حاجة إلى ترحيل. +تم اختباره بشكل مكثف مع MinIO وأنظمة S3 الأخرى. + +## تنفيذ BlobStore + +**الموقع:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +```python +from minio import Minio +import io +import logging + +logger = logging.getLogger(__name__) + +class BlobStore: + """ + S3-compatible blob storage for document content. + Supports MinIO, Ceph RGW, AWS S3, and other S3-compatible backends. + """ + + def __init__(self, endpoint, access_key, secret_key, bucket_name, + use_ssl=False, region=None): + """ + Initialize S3-compatible blob storage. + + Args: + endpoint: S3 endpoint (e.g., "minio:9000", "ceph-rgw:7480") + access_key: S3 access key + secret_key: S3 secret key + bucket_name: Bucket name for storage + use_ssl: Use HTTPS instead of HTTP (default: False) + region: S3 region (optional, e.g., "us-east-1") + """ + self.client = Minio( + endpoint=endpoint, + access_key=access_key, + secret_key=secret_key, + secure=use_ssl, + region=region, + ) + + self.bucket_name = bucket_name + + protocol = "https" if use_ssl else "http" + logger.info(f"Connected to S3-compatible storage at {protocol}://{endpoint}") + + self.ensure_bucket() + + def ensure_bucket(self): + """Create bucket if it doesn't exist""" + found = self.client.bucket_exists(bucket_name=self.bucket_name) + if not found: + self.client.make_bucket(bucket_name=self.bucket_name) + logger.info(f"Created bucket {self.bucket_name}") + else: + logger.debug(f"Bucket {self.bucket_name} already exists") + + async def add(self, object_id, blob, kind): + """Store blob in S3-compatible storage""" + self.client.put_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + length=len(blob), + data=io.BytesIO(blob), + content_type=kind, + ) + logger.debug("Add blob complete") + + async def remove(self, object_id): + """Delete blob from S3-compatible storage""" + self.client.remove_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + logger.debug("Remove blob complete") + + async def get(self, object_id): + """Retrieve blob from S3-compatible storage""" + resp = self.client.get_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + return resp.read() +``` + +## الفوائد الرئيسية + +1. **لا يوجد اعتماد على مورد واحد** - يعمل مع أي تخزين متوافق مع S3. +2. **خفيف الوزن** - حجم عميل MinIO يبلغ حوالي 500 كيلوبايت فقط. +3. **تكوين بسيط** - يتطلب فقط نقطة النهاية وبيانات الاعتماد. +4. **لا حاجة لنقل البيانات** - بديل مباشر بين الأنظمة الخلفية. +5. **تم اختباره ميدانيًا** - يعمل عميل MinIO مع جميع تطبيقات S3 الرئيسية. + +## حالة التنفيذ + +تم تحديث جميع التعليمات البرمجية لاستخدام أسماء معلمات S3 العامة: + +✅ `blob_store.py` - تم التحديث لقبول `endpoint`، `access_key`، `secret_key`. +✅ `librarian.py` - تم تحديث أسماء المعلمات. +✅ `service.py` - تم تحديث وسيطات سطر الأوامر والتكوين. +✅ تم تحديث الوثائق. + +## التحسينات المستقبلية + +1. **دعم SSL/TLS** - إضافة علامة `--s3-use-ssl` لـ HTTPS. +2. **منطق إعادة المحاولة** - تطبيق تأخير أُسي للأخطاء العابرة. +3. **عناوين URL مؤقتة** - إنشاء عناوين URL مؤقتة للتحميل/التنزيل. +4. **دعم متعدد المناطق** - تكرار الكائنات عبر المناطق. +5. **تكامل CDN** - تقديم الكائنات عبر CDN. +6. **فئات التخزين** - استخدام فئات تخزين S3 لتحسين التكلفة. +7. **سياسات دورة الحياة** - الأرشفة/الحذف التلقائي. +8. **التحكم في الإصدار** - تخزين إصدارات متعددة من الكائنات. + +## المراجع + +عميل MinIO Python: https://min.io/docs/minio/linux/developers/python/API.html +واجهة برمجة تطبيقات Ceph RGW S3: https://docs.ceph.com/en/latest/radosgw/s3/ +مرجع واجهة برمجة تطبيقات S3: https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html diff --git a/docs/tech-specs/minio-to-s3-migration.es.md b/docs/tech-specs/minio-to-s3-migration.es.md new file mode 100644 index 00000000..5aebde9e --- /dev/null +++ b/docs/tech-specs/minio-to-s3-migration.es.md @@ -0,0 +1,258 @@ +# Especificación Técnica: Soporte para Backend de Almacenamiento Compatible con S3 + +## Resumen + +El servicio Librarian utiliza almacenamiento de objetos compatible con S3 para el almacenamiento de blobs de documentos. Esta especificación documenta la implementación que permite el soporte para cualquier backend compatible con S3, incluyendo MinIO, Ceph RADOS Gateway (RGW), AWS S3, Cloudflare R2, DigitalOcean Spaces, y otros. + +## Arquitectura + +### Componentes de Almacenamiento +**Almacenamiento de Blobs**: Almacenamiento de objetos compatible con S3 a través de la biblioteca de cliente `minio` de Python. +**Almacenamiento de Metadatos**: Cassandra (almacena el mapeo de object_id y los metadatos del documento). +**Componente Afectado**: Solo el servicio Librarian. +**Patrón de Almacenamiento**: Almacenamiento híbrido con metadatos en Cassandra y contenido en almacenamiento compatible con S3. + +### Implementación +**Biblioteca**: Cliente `minio` de Python (soporta cualquier API compatible con S3). +**Ubicación**: `trustgraph-flow/trustgraph/librarian/blob_store.py` +**Operaciones**: + `add()` - Almacenar blob con object_id UUID. + `get()` - Recuperar blob por object_id. + `remove()` - Eliminar blob por object_id. + `ensure_bucket()` - Crear bucket si no existe. +**Bucket**: `library` +**Ruta del Objeto**: `doc/{object_id}` +**Tipos MIME Soportados**: `text/plain`, `application/pdf` + +### Archivos Clave +1. `trustgraph-flow/trustgraph/librarian/blob_store.py` - Implementación de BlobStore. +2. `trustgraph-flow/trustgraph/librarian/librarian.py` - Inicialización de BlobStore. +3. `trustgraph-flow/trustgraph/librarian/service.py` - Configuración del servicio. +4. `trustgraph-flow/pyproject.toml` - Dependencias (paquete `minio`). +5. `docs/apis/api-librarian.md` - Documentación de la API. + +## Backends de Almacenamiento Soportados + +La implementación funciona con cualquier sistema de almacenamiento de objetos compatible con S3: + +### Probado/Soportado +**Ceph RADOS Gateway (RGW)** - Sistema de almacenamiento distribuido con API S3 (configuración predeterminada). +**MinIO** - Almacenamiento de objetos auto-alojado ligero. +**Garage** - Almacenamiento S3-compatible geo-distribuido ligero. + +### Debería Funcionar (Compatible con S3) +**AWS S3** - Almacenamiento de objetos en la nube de Amazon. +**Cloudflare R2** - Almacenamiento S3-compatible de Cloudflare. +**DigitalOcean Spaces** - Almacenamiento de objetos de DigitalOcean. +**Wasabi** - Almacenamiento en la nube S3-compatible. +**Backblaze B2** - Almacenamiento de respaldo S3-compatible. +Cualquier otro servicio que implemente la API REST S3. + +## Configuración + +### Argumentos de la Línea de Comandos + +```bash +librarian \ + --object-store-endpoint \ + --object-store-access-key \ + --object-store-secret-key \ + [--object-store-use-ssl] \ + [--object-store-region ] +``` + +**Nota:** No incluya `http://` ni `https://` en el punto final. Use `--object-store-use-ssl` para habilitar HTTPS. + +### Variables de entorno (Alternativa) + +```bash +OBJECT_STORE_ENDPOINT= +OBJECT_STORE_ACCESS_KEY= +OBJECT_STORE_SECRET_KEY= +OBJECT_STORE_USE_SSL=true|false # Optional, default: false +OBJECT_STORE_REGION= # Optional +``` + +### Ejemplos + +**Ceph RADOS Gateway (predeterminado):** +```bash +--object-store-endpoint ceph-rgw:7480 \ +--object-store-access-key object-user \ +--object-store-secret-key object-password +``` + +**MinIO:** +```bash +--object-store-endpoint minio:9000 \ +--object-store-access-key minioadmin \ +--object-store-secret-key minioadmin +``` + +**Almacenamiento (compatible con S3):** +```bash +--object-store-endpoint garage:3900 \ +--object-store-access-key GK000000000000000000000001 \ +--object-store-secret-key b171f00be9be4c32c734f4c05fe64c527a8ab5eb823b376cfa8c2531f70fc427 +``` + +**AWS S3 con SSL:** +```bash +--object-store-endpoint s3.amazonaws.com \ +--object-store-access-key AKIAIOSFODNN7EXAMPLE \ +--object-store-secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \ +--object-store-use-ssl \ +--object-store-region us-east-1 +``` + +## Autenticación + +Todos los backends compatibles con S3 requieren la autenticación AWS Signature Version 4 (o v2): + +**Clave de acceso** - Identificador público (como nombre de usuario) +**Clave secreta** - Clave de firma privada (como contraseña) + +El cliente de Python de MinIO gestiona automáticamente todos los cálculos de firma. + +### Creación de credenciales + +**Para MinIO:** +```bash +# Use default credentials or create user via MinIO Console +minioadmin / minioadmin +``` + +**Para Ceph RGW:** +```bash +radosgw-admin user create --uid="trustgraph" --display-name="TrustGraph Service" +# Returns access_key and secret_key +``` + +**Para AWS S3:** +Crear usuario IAM con permisos de S3 +Generar clave de acceso en la consola de AWS + +## Selección de la biblioteca: Cliente de Python para MinIO + +**Justificación:** +Ligera (~500 KB frente a los ~50 MB de boto3) +Compatible con S3: funciona con cualquier punto final de la API de S3 +API más simple que boto3 para operaciones básicas +Ya en uso, no se necesita migración +Probada en batalla con MinIO y otros sistemas S3 + +## Implementación de BlobStore + +**Ubicación:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +```python +from minio import Minio +import io +import logging + +logger = logging.getLogger(__name__) + +class BlobStore: + """ + S3-compatible blob storage for document content. + Supports MinIO, Ceph RGW, AWS S3, and other S3-compatible backends. + """ + + def __init__(self, endpoint, access_key, secret_key, bucket_name, + use_ssl=False, region=None): + """ + Initialize S3-compatible blob storage. + + Args: + endpoint: S3 endpoint (e.g., "minio:9000", "ceph-rgw:7480") + access_key: S3 access key + secret_key: S3 secret key + bucket_name: Bucket name for storage + use_ssl: Use HTTPS instead of HTTP (default: False) + region: S3 region (optional, e.g., "us-east-1") + """ + self.client = Minio( + endpoint=endpoint, + access_key=access_key, + secret_key=secret_key, + secure=use_ssl, + region=region, + ) + + self.bucket_name = bucket_name + + protocol = "https" if use_ssl else "http" + logger.info(f"Connected to S3-compatible storage at {protocol}://{endpoint}") + + self.ensure_bucket() + + def ensure_bucket(self): + """Create bucket if it doesn't exist""" + found = self.client.bucket_exists(bucket_name=self.bucket_name) + if not found: + self.client.make_bucket(bucket_name=self.bucket_name) + logger.info(f"Created bucket {self.bucket_name}") + else: + logger.debug(f"Bucket {self.bucket_name} already exists") + + async def add(self, object_id, blob, kind): + """Store blob in S3-compatible storage""" + self.client.put_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + length=len(blob), + data=io.BytesIO(blob), + content_type=kind, + ) + logger.debug("Add blob complete") + + async def remove(self, object_id): + """Delete blob from S3-compatible storage""" + self.client.remove_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + logger.debug("Remove blob complete") + + async def get(self, object_id): + """Retrieve blob from S3-compatible storage""" + resp = self.client.get_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + return resp.read() +``` + +## Beneficios Clave + +1. **Sin dependencia de un proveedor** - Funciona con cualquier almacenamiento compatible con S3. +2. **Ligero** - El cliente MinIO tiene un tamaño de aproximadamente 500 KB. +3. **Configuración sencilla** - Solo necesita el punto de acceso y las credenciales. +4. **Sin migración de datos** - Reemplazo directo entre diferentes backends. +5. **Probado en batalla** - El cliente MinIO funciona con todas las principales implementaciones de S3. + +## Estado de la implementación + +Todo el código se ha actualizado para utilizar nombres de parámetros S3 genéricos: + +✅ `blob_store.py` - Actualizado para aceptar `endpoint`, `access_key`, `secret_key` +✅ `librarian.py` - Nombres de parámetros actualizados +✅ `service.py` - Argumentos de la línea de comandos y configuración actualizados +✅ Documentación actualizada + +## Mejoras futuras + +1. **Soporte para SSL/TLS** - Agregar la bandera `--s3-use-ssl` para HTTPS. +2. **Lógica de reintento** - Implementar un reintento exponencial para fallos transitorios. +3. **URLs prefirmadas** - Generar URLs temporales de carga/descarga. +4. **Soporte para múltiples regiones** - Replicar blobs a través de regiones. +5. **Integración con CDN** - Servir blobs a través de una CDN. +6. **Clases de almacenamiento** - Utilizar clases de almacenamiento de S3 para la optimización de costos. +7. **Políticas de ciclo de vida** - Archivado/eliminación automática. +8. **Versionado** - Almacenar múltiples versiones de blobs. + +## Referencias + +Cliente de MinIO para Python: https://min.io/docs/minio/linux/developers/python/API.html +API S3 de Ceph RGW: https://docs.ceph.com/en/latest/radosgw/s3/ +Referencia de la API S3: https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html diff --git a/docs/tech-specs/minio-to-s3-migration.he.md b/docs/tech-specs/minio-to-s3-migration.he.md new file mode 100644 index 00000000..c2440282 --- /dev/null +++ b/docs/tech-specs/minio-to-s3-migration.he.md @@ -0,0 +1,258 @@ +# Tech Spec: S3-Compatible Storage Backend Support + +## Overview + +השירות Librarian משתמש באחסון אובייקטים תואם ל-S3 לאחסון קבצים. מסמך זה מתאר את היישום המאפשר תמיכה בכל אחסון תואם ל-S3, כולל MinIO, Ceph RADOS Gateway (RGW), AWS S3, Cloudflare R2, DigitalOcean Spaces, ואחרים. + +## Architecture + +### Storage Components +**Blob Storage**: אחסון אובייקטים תואם ל-S3 באמצעות `minio` ספריית לקוח Python +**Metadata Storage**: Cassandra (מאחסן מיפוי object_id ונתוני מטא-דאטה של מסמכים) +**Affected Component**: רק השירות Librarian +**Storage Pattern**: אחסון היברידי עם מטא-דאטה ב-Cassandra ותוכן באחסון תואם ל-S3 + +### Implementation +**Library**: `minio` לקוח Python (תומך בכל API תואם ל-S3) +**Location**: `trustgraph-flow/trustgraph/librarian/blob_store.py` +**Operations**: + `add()` - שמירת קובץ עם מזהה אובייקט UUID + `get()` - שליפת קובץ לפי מזהה אובייקט + `remove()` - מחיקת קובץ לפי מזהה אובייקט + `ensure_bucket()` - יצירת תיקייה אם היא לא קיימת +**Bucket**: `library` +**Object Path**: `doc/{object_id}` +**Supported MIME Types**: `text/plain`, `application/pdf` + +### Key Files +1. `trustgraph-flow/trustgraph/librarian/blob_store.py` - יישום BlobStore +2. `trustgraph-flow/trustgraph/librarian/librarian.py` - אתחול BlobStore +3. `trustgraph-flow/trustgraph/librarian/service.py` - תצורת שירות +4. `trustgraph-flow/pyproject.toml` - תלויות (חבילת `minio`) +5. `docs/apis/api-librarian.md` - תיעוד API + +## Supported Storage Backends + +היישום עובד עם כל מערכת אחסון אובייקטים תואמת ל-S3: + +### Tested/Supported +**Ceph RADOS Gateway (RGW)** - מערכת אחסון מבוזרת עם API של S3 (תצורת ברירת מחדל) +**MinIO** - אחסון אובייקטים קל משקל, הניתן לאירוח עצמי +**Garage** - אחסון S3-תואם, מבוזר גיאוגרפית, קל משקל + +### Should Work (S3-Compatible) +**AWS S3** - אחסון אובייקטים בענן של Amazon +**Cloudflare R2** - אחסון S3-תואם של Cloudflare +**DigitalOcean Spaces** - אחסון אובייקטים של DigitalOcean +**Wasabi** - אחסון בענן S3-תואם +**Backblaze B2** - אחסון גיבוי S3-תואם +כל שירות אחר המיישם את ממשק ה-API של S3 + +## Configuration + +### CLI Arguments + +```bash +librarian \ + --object-store-endpoint \ + --object-store-access-key \ + --object-store-secret-key \ + [--object-store-use-ssl] \ + [--object-store-region ] +``` + +**הערה:** אל תכללו את `http://` או `https://` בסוף. השתמשו ב-`--object-store-use-ssl` כדי להפעיל HTTPS. + +### משתני סביבה (חלופי) + +```bash +OBJECT_STORE_ENDPOINT= +OBJECT_STORE_ACCESS_KEY= +OBJECT_STORE_SECRET_KEY= +OBJECT_STORE_USE_SSL=true|false # Optional, default: false +OBJECT_STORE_REGION= # Optional +``` + +### דוגמאות + +**שער Ceph RADOS (ברירת מחדל):** +```bash +--object-store-endpoint ceph-rgw:7480 \ +--object-store-access-key object-user \ +--object-store-secret-key object-password +``` + +**MinIO:** +```bash +--object-store-endpoint minio:9000 \ +--object-store-access-key minioadmin \ +--object-store-secret-key minioadmin +``` + +**מחסן (תואם S3):** +```bash +--object-store-endpoint garage:3900 \ +--object-store-access-key GK000000000000000000000001 \ +--object-store-secret-key b171f00be9be4c32c734f4c05fe64c527a8ab5eb823b376cfa8c2531f70fc427 +``` + +**AWS S3 עם SSL:** +```bash +--object-store-endpoint s3.amazonaws.com \ +--object-store-access-key AKIAIOSFODNN7EXAMPLE \ +--object-store-secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \ +--object-store-use-ssl \ +--object-store-region us-east-1 +``` + +## אימות + +כל השרתים התומכים ב-S3 דורשים אימות AWS Signature Version 4 (או v2): + +**מפתח גישה (Access Key)** - מזהה ציבורי (כמו שם משתמש) +**מפתח סודי (Secret Key)** - מפתח חתימה פרטי (כמו סיסמה) + +לקוח ה-Python של MinIO מטפל בכל חישוב החתימה באופן אוטומטי. + +### יצירת פרטי גישה + +**עבור MinIO:** +```bash +# Use default credentials or create user via MinIO Console +minioadmin / minioadmin +``` + +**עבור Ceph RGW:** +```bash +radosgw-admin user create --uid="trustgraph" --display-name="TrustGraph Service" +# Returns access_key and secret_key +``` + +**עבור AWS S3:** +צור משתמש IAM עם הרשאות S3 +צור מפתח גישה בלוח הבקרה של AWS + +## בחירת ספרייה: לקוח Python של MinIO + +**ההצדקה:** +קל משקל (~500KB לעומת ~50MB של boto3) +תואם ל-S3 - עובד עם כל נקודת קצה של ממשק API של S3 +ממשק API פשוט יותר מ-boto3 עבור פעולות בסיסיות +כבר בשימוש, אין צורך בהעברה +נבדק היטב עם MinIO ומערכות S3 אחרות + +## יישום BlobStore + +**מיקום:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +```python +from minio import Minio +import io +import logging + +logger = logging.getLogger(__name__) + +class BlobStore: + """ + S3-compatible blob storage for document content. + Supports MinIO, Ceph RGW, AWS S3, and other S3-compatible backends. + """ + + def __init__(self, endpoint, access_key, secret_key, bucket_name, + use_ssl=False, region=None): + """ + Initialize S3-compatible blob storage. + + Args: + endpoint: S3 endpoint (e.g., "minio:9000", "ceph-rgw:7480") + access_key: S3 access key + secret_key: S3 secret key + bucket_name: Bucket name for storage + use_ssl: Use HTTPS instead of HTTP (default: False) + region: S3 region (optional, e.g., "us-east-1") + """ + self.client = Minio( + endpoint=endpoint, + access_key=access_key, + secret_key=secret_key, + secure=use_ssl, + region=region, + ) + + self.bucket_name = bucket_name + + protocol = "https" if use_ssl else "http" + logger.info(f"Connected to S3-compatible storage at {protocol}://{endpoint}") + + self.ensure_bucket() + + def ensure_bucket(self): + """Create bucket if it doesn't exist""" + found = self.client.bucket_exists(bucket_name=self.bucket_name) + if not found: + self.client.make_bucket(bucket_name=self.bucket_name) + logger.info(f"Created bucket {self.bucket_name}") + else: + logger.debug(f"Bucket {self.bucket_name} already exists") + + async def add(self, object_id, blob, kind): + """Store blob in S3-compatible storage""" + self.client.put_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + length=len(blob), + data=io.BytesIO(blob), + content_type=kind, + ) + logger.debug("Add blob complete") + + async def remove(self, object_id): + """Delete blob from S3-compatible storage""" + self.client.remove_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + logger.debug("Remove blob complete") + + async def get(self, object_id): + """Retrieve blob from S3-compatible storage""" + resp = self.client.get_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + return resp.read() +``` + +## יתרונות מרכזיים + +1. **ללא תלות בספק** - עובד עם כל אחסון התומך ב-S3 +2. **קל משקל** - הלקוח של MinIO הוא בגודל של כ-500KB בלבד +3. **הגדרות פשוטות** - רק נקודת קצה (endpoint) ואישורים +4. **ללא העברת נתונים** - החלפה ישירה בין מערכות אחסון שונות +5. **נבדק ביסודיות** - לקוח MinIO עובד עם כל המימושים העיקריים של S3 + +## סטטוס יישום + +כל הקוד עודכן לשימוש בשמות פרמטרים גנריים של S3: + +✅ `blob_store.py` - עודכן כדי לקבל `endpoint`, `access_key`, `secret_key` +✅ `librarian.py` - עודכנו שמות הפרמטרים +✅ `service.py` - עודכנו ארגומנטים של שורת הפקודה והגדרות +✅ תיעוד עודכן + +## שיפורים עתידיים + +1. **תמיכה ב-SSL/TLS** - הוספת דגל `--s3-use-ssl` עבור HTTPS +2. **לוגיקת ניסיונות חוזרים** - יישום של דחייה אקספוננציאלית עבור כשלים זמניים +3. **כתובות URL חתומות** - יצירת כתובות URL זמניות להעלאה/הורדה +4. **תמיכה בריבוי אזורים** - שכפול קבצים בין אזורים +5. **אינטגרציה עם CDN** - שירות קבצים באמצעות CDN +6. **מדרגי אחסון** - שימוש במדרגי אחסון של S3 למיטוב עלויות +7. **מדיניות מחזור חיים** - ארכיון/מחיקה אוטומטיים +8. **גרסאות** - שמירת גרסאות מרובות של קבצים + +## הפניות + +לקוח MinIO לפייתון: https://min.io/docs/minio/linux/developers/python/API.html +Ceph RGW S3 API: https://docs.ceph.com/en/latest/radosgw/s3/ +מדריך API של S3: https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html diff --git a/docs/tech-specs/minio-to-s3-migration.hi.md b/docs/tech-specs/minio-to-s3-migration.hi.md new file mode 100644 index 00000000..65b69dca --- /dev/null +++ b/docs/tech-specs/minio-to-s3-migration.hi.md @@ -0,0 +1,258 @@ +# तकनीकी विनिर्देश: S3-संगत स्टोरेज बैकएंड समर्थन + +## अवलोकन + +लाइब्रेरियन सेवा दस्तावेज़ ब्लॉब स्टोरेज के लिए S3-संगत ऑब्जेक्ट स्टोरेज का उपयोग करती है। यह विनिर्देश उस कार्यान्वयन का दस्तावेज़ करता है जो किसी भी S3-संगत बैकएंड के लिए समर्थन को सक्षम करता है, जिसमें MinIO, Ceph RADOS गेटवे (RGW), AWS S3, Cloudflare R2, DigitalOcean Spaces और अन्य शामिल हैं। + +## वास्तुकला + +### स्टोरेज घटक +**ब्लॉब स्टोरेज**: `minio` पायथन क्लाइंट लाइब्रेरी के माध्यम से S3-संगत ऑब्जेक्ट स्टोरेज +**मेटाडेटा स्टोरेज**: कैसेंड्रा (ऑब्जेक्ट_आईडी मैपिंग और दस्तावेज़ मेटाडेटा संग्रहीत करता है) +**प्रभावित घटक**: केवल लाइब्रेरियन सेवा +**स्टोरेज पैटर्न**: कैसेंड्रा में मेटाडेटा और S3-संगत स्टोरेज में सामग्री के साथ हाइब्रिड स्टोरेज + +### कार्यान्वयन +**लाइब्रेरी**: `minio` पायथन क्लाइंट (किसी भी S3-संगत API का समर्थन करता है) +**स्थान**: `trustgraph-flow/trustgraph/librarian/blob_store.py` +**ऑपरेशन**: + `add()` - UUID ऑब्जेक्ट_आईडी के साथ ब्लॉब संग्रहीत करें + `get()` - ऑब्जेक्ट_आईडी द्वारा ब्लॉब पुनर्प्राप्त करें + `remove()` - ऑब्जेक्ट_आईडी द्वारा ब्लॉब हटाएं + `ensure_bucket()` - यदि मौजूद नहीं है तो बकेट बनाएं +**बकेट**: `library` +**ऑब्जेक्ट पथ**: `doc/{object_id}` +**समर्थित MIME प्रकार**: `text/plain`, `application/pdf` + +### महत्वपूर्ण फाइलें +1. `trustgraph-flow/trustgraph/librarian/blob_store.py` - BlobStore कार्यान्वयन +2. `trustgraph-flow/trustgraph/librarian/librarian.py` - BlobStore इनिशियलाइज़ेशन +3. `trustgraph-flow/trustgraph/librarian/service.py` - सेवा कॉन्फ़िगरेशन +4. `trustgraph-flow/pyproject.toml` - निर्भरताएँ (`minio` पैकेज) +5. `docs/apis/api-librarian.md` - एपीआई दस्तावेज़ + +## समर्थित स्टोरेज बैकएंड + +कार्यान्वयन किसी भी S3-संगत ऑब्जेक्ट स्टोरेज सिस्टम के साथ काम करता है: + +### परीक्षण किया गया/समर्थित +**Ceph RADOS गेटवे (RGW)** - S3 API के साथ वितरित स्टोरेज सिस्टम (डिफ़ॉल्ट कॉन्फ़िगरेशन) +**MinIO** - हल्का स्व-होस्टेड ऑब्जेक्ट स्टोरेज +**गैराज** - हल्का जियो-वितरित S3-संगत स्टोरेज + +### काम करना चाहिए (S3-संगत) +**AWS S3** - अमेज़ॅन का क्लाउड ऑब्जेक्ट स्टोरेज +**Cloudflare R2** - Cloudflare का S3-संगत स्टोरेज +**DigitalOcean Spaces** - DigitalOcean का ऑब्जेक्ट स्टोरेज +**Wasabi** - S3-संगत क्लाउड स्टोरेज +**Backblaze B2** - S3-संगत बैकअप स्टोरेज +S3 REST API को लागू करने वाली कोई भी अन्य सेवा + +## कॉन्फ़िगरेशन + +### CLI तर्क + +```bash +librarian \ + --object-store-endpoint \ + --object-store-access-key \ + --object-store-secret-key \ + [--object-store-use-ssl] \ + [--object-store-region ] +``` + +**ध्यान दें:** अंतिम बिंदु में `http://` या `https://` को शामिल न करें। HTTPS को सक्षम करने के लिए `--object-store-use-ssl` का उपयोग करें। + +### पर्यावरण चर (वैकल्पिक) + +```bash +OBJECT_STORE_ENDPOINT= +OBJECT_STORE_ACCESS_KEY= +OBJECT_STORE_SECRET_KEY= +OBJECT_STORE_USE_SSL=true|false # Optional, default: false +OBJECT_STORE_REGION= # Optional +``` + +### उदाहरण + +**सेफ रेडोस गेटवे (डिफ़ॉल्ट):** +```bash +--object-store-endpoint ceph-rgw:7480 \ +--object-store-access-key object-user \ +--object-store-secret-key object-password +``` + +**मिनियो:** +```bash +--object-store-endpoint minio:9000 \ +--object-store-access-key minioadmin \ +--object-store-secret-key minioadmin +``` + +**गैराज (एस3-संगत):** +```bash +--object-store-endpoint garage:3900 \ +--object-store-access-key GK000000000000000000000001 \ +--object-store-secret-key b171f00be9be4c32c734f4c05fe64c527a8ab5eb823b376cfa8c2531f70fc427 +``` + +**AWS S3 एसएसएल के साथ:** +```bash +--object-store-endpoint s3.amazonaws.com \ +--object-store-access-key AKIAIOSFODNN7EXAMPLE \ +--object-store-secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \ +--object-store-use-ssl \ +--object-store-region us-east-1 +``` + +## प्रमाणीकरण + +सभी S3-संगत बैकएंड को AWS सिग्नेचर संस्करण 4 (या v2) प्रमाणीकरण की आवश्यकता होती है: + +**एक्सेस कुंजी** - सार्वजनिक पहचानकर्ता (जैसे उपयोगकर्ता नाम) +**सीक्रेट कुंजी** - निजी हस्ताक्षर कुंजी (जैसे पासवर्ड) + +MinIO पायथन क्लाइंट सभी हस्ताक्षर गणना को स्वचालित रूप से संभालता है। + +### क्रेडेंशियल बनाना + +**MinIO के लिए:** +```bash +# Use default credentials or create user via MinIO Console +minioadmin / minioadmin +``` + +**सेफ आरजीडब्ल्यू के लिए:** +```bash +radosgw-admin user create --uid="trustgraph" --display-name="TrustGraph Service" +# Returns access_key and secret_key +``` + +**AWS S3 के लिए:** +S3 अनुमतियों के साथ एक IAM उपयोगकर्ता बनाएँ। +AWS कंसोल में एक्सेस कुंजी उत्पन्न करें। + +## लाइब्रेरी चयन: MinIO Python क्लाइंट + +**तर्क:** +हल्का (~500KB बनाम boto3 का ~50MB) +S3-संगत - किसी भी S3 API एंडपॉइंट के साथ काम करता है। +बुनियादी कार्यों के लिए boto3 की तुलना में सरल API। +पहले से उपयोग में है, माइग्रेशन की आवश्यकता नहीं है। +MinIO और अन्य S3 सिस्टम के साथ परीक्षण किया गया। + +## BlobStore कार्यान्वयन + +**स्थान:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +```python +from minio import Minio +import io +import logging + +logger = logging.getLogger(__name__) + +class BlobStore: + """ + S3-compatible blob storage for document content. + Supports MinIO, Ceph RGW, AWS S3, and other S3-compatible backends. + """ + + def __init__(self, endpoint, access_key, secret_key, bucket_name, + use_ssl=False, region=None): + """ + Initialize S3-compatible blob storage. + + Args: + endpoint: S3 endpoint (e.g., "minio:9000", "ceph-rgw:7480") + access_key: S3 access key + secret_key: S3 secret key + bucket_name: Bucket name for storage + use_ssl: Use HTTPS instead of HTTP (default: False) + region: S3 region (optional, e.g., "us-east-1") + """ + self.client = Minio( + endpoint=endpoint, + access_key=access_key, + secret_key=secret_key, + secure=use_ssl, + region=region, + ) + + self.bucket_name = bucket_name + + protocol = "https" if use_ssl else "http" + logger.info(f"Connected to S3-compatible storage at {protocol}://{endpoint}") + + self.ensure_bucket() + + def ensure_bucket(self): + """Create bucket if it doesn't exist""" + found = self.client.bucket_exists(bucket_name=self.bucket_name) + if not found: + self.client.make_bucket(bucket_name=self.bucket_name) + logger.info(f"Created bucket {self.bucket_name}") + else: + logger.debug(f"Bucket {self.bucket_name} already exists") + + async def add(self, object_id, blob, kind): + """Store blob in S3-compatible storage""" + self.client.put_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + length=len(blob), + data=io.BytesIO(blob), + content_type=kind, + ) + logger.debug("Add blob complete") + + async def remove(self, object_id): + """Delete blob from S3-compatible storage""" + self.client.remove_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + logger.debug("Remove blob complete") + + async def get(self, object_id): + """Retrieve blob from S3-compatible storage""" + resp = self.client.get_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + return resp.read() +``` + +## मुख्य लाभ + +1. **कोई विक्रेता लॉक-इन नहीं** - किसी भी S3-संगत स्टोरेज के साथ काम करता है। +2. **हल्का** - MinIO क्लाइंट केवल ~500KB है। +3. **सरल कॉन्फ़िगरेशन** - केवल एंडपॉइंट + क्रेडेंशियल। +4. **कोई डेटा माइग्रेशन नहीं** - बैकएंड के बीच ड्रॉप-इन रिप्लेसमेंट। +5. **युद्ध-परीक्षित** - MinIO क्लाइंट सभी प्रमुख S3 कार्यान्वयन के साथ काम करता है। + +## कार्यान्वयन स्थिति + +सभी कोड को जेनेरिक S3 पैरामीटर नामों का उपयोग करने के लिए अपडेट किया गया है: + +✅ `blob_store.py` - `endpoint`, `access_key`, `secret_key` को स्वीकार करने के लिए अपडेट किया गया। +✅ `librarian.py` - पैरामीटर नामों को अपडेट किया गया। +✅ `service.py` - CLI तर्क और कॉन्फ़िगरेशन को अपडेट किया गया। +✅ दस्तावेज़ अपडेट किया गया। + +## भविष्य के सुधार + +1. **SSL/TLS समर्थन** - HTTPS के लिए `--s3-use-ssl` ध्वज जोड़ें। +2. **पुन: प्रयास तर्क** - क्षणिक विफलताओं के लिए घातीय बैकऑफ़ लागू करें। +3. **प्रीसाइंड URL** - अस्थायी अपलोड/डाउनलोड URL उत्पन्न करें। +4. **मल्टी-रीजन समर्थन** - क्षेत्रों में ब्लॉब्स को दोहराएं। +5. **CDN एकीकरण** - CDN के माध्यम से ब्लॉब्स परोसें। +6. **स्टोरेज क्लासेस** - लागत अनुकूलन के लिए S3 स्टोरेज क्लासेस का उपयोग करें। +7. **लाइफसाइकिल नीतियां** - स्वचालित अभिलेखागार/हटाना। +8. **वर्जनिंग** - ब्लॉब्स के कई संस्करणों को संग्रहीत करें। + +## संदर्भ + +MinIO Python क्लाइंट: https://min.io/docs/minio/linux/developers/python/API.html +Ceph RGW S3 API: https://docs.ceph.com/en/latest/radosgw/s3/ +S3 API संदर्भ: https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html diff --git a/docs/tech-specs/minio-to-s3-migration.pt.md b/docs/tech-specs/minio-to-s3-migration.pt.md new file mode 100644 index 00000000..11bcedb1 --- /dev/null +++ b/docs/tech-specs/minio-to-s3-migration.pt.md @@ -0,0 +1,258 @@ +# Especificação Técnica: Suporte a Backend de Armazenamento Compatível com S3 + +## Visão Geral + +O serviço Librarian utiliza armazenamento de objetos compatível com S3 para o armazenamento de blobs de documentos. Esta especificação documenta a implementação que permite o suporte a qualquer backend compatível com S3, incluindo MinIO, Ceph RADOS Gateway (RGW), AWS S3, Cloudflare R2, DigitalOcean Spaces e outros. + +## Arquitetura + +### Componentes de Armazenamento +**Armazenamento de Blobs**: Armazenamento de objetos compatível com S3 através da biblioteca cliente `minio` Python. +**Armazenamento de Metadados**: Cassandra (armazena o mapeamento object_id e os metadados do documento). +**Componente Afetado**: Apenas o serviço Librarian. +**Padrão de Armazenamento**: Armazenamento híbrido com metadados no Cassandra e conteúdo no armazenamento compatível com S3. + +### Implementação +**Biblioteca**: Cliente `minio` Python (suporta qualquer API compatível com S3). +**Localização**: `trustgraph-flow/trustgraph/librarian/blob_store.py` +**Operações**: + `add()` - Armazenar blob com object_id UUID. + `get()` - Recuperar blob por object_id. + `remove()` - Excluir blob por object_id. + `ensure_bucket()` - Criar bucket se não existir. +**Bucket**: `library` +**Caminho do Objeto**: `doc/{object_id}` +**Tipos MIME Suportados**: `text/plain`, `application/pdf` + +### Arquivos Chave +1. `trustgraph-flow/trustgraph/librarian/blob_store.py` - Implementação do BlobStore. +2. `trustgraph-flow/trustgraph/librarian/librarian.py` - Inicialização do BlobStore. +3. `trustgraph-flow/trustgraph/librarian/service.py` - Configuração do serviço. +4. `trustgraph-flow/pyproject.toml` - Dependências (pacote `minio`). +5. `docs/apis/api-librarian.md` - Documentação da API. + +## Backends de Armazenamento Suportados + +A implementação funciona com qualquer sistema de armazenamento de objetos compatível com S3: + +### Testados/Suportados +**Ceph RADOS Gateway (RGW)** - Sistema de armazenamento distribuído com API S3 (configuração padrão). +**MinIO** - Armazenamento de objetos auto-hospedado leve. +**Garage** - Armazenamento S3-compatível geo-distribuído leve. + +### Deve Funcionar (Compatível com S3) +**AWS S3** - Armazenamento de objetos em nuvem da Amazon. +**Cloudflare R2** - Armazenamento S3-compatível da Cloudflare. +**DigitalOcean Spaces** - Armazenamento de objetos da DigitalOcean. +**Wasabi** - Armazenamento em nuvem S3-compatível. +**Backblaze B2** - Armazenamento de backup S3-compatível. +Qualquer outro serviço que implemente a API REST S3. + +## Configuração + +### Argumentos da Linha de Comando + +```bash +librarian \ + --object-store-endpoint \ + --object-store-access-key \ + --object-store-secret-key \ + [--object-store-use-ssl] \ + [--object-store-region ] +``` + +**Observação:** Não inclua `http://` ou `https://` no endpoint. Use `--object-store-use-ssl` para habilitar HTTPS. + +### Variáveis de Ambiente (Alternativa) + +```bash +OBJECT_STORE_ENDPOINT= +OBJECT_STORE_ACCESS_KEY= +OBJECT_STORE_SECRET_KEY= +OBJECT_STORE_USE_SSL=true|false # Optional, default: false +OBJECT_STORE_REGION= # Optional +``` + +### Exemplos + +**Ceph RADOS Gateway (padrão):** +```bash +--object-store-endpoint ceph-rgw:7480 \ +--object-store-access-key object-user \ +--object-store-secret-key object-password +``` + +**MinIO:** +```bash +--object-store-endpoint minio:9000 \ +--object-store-access-key minioadmin \ +--object-store-secret-key minioadmin +``` + +**Armazenamento (compatível com S3):** +```bash +--object-store-endpoint garage:3900 \ +--object-store-access-key GK000000000000000000000001 \ +--object-store-secret-key b171f00be9be4c32c734f4c05fe64c527a8ab5eb823b376cfa8c2531f70fc427 +``` + +**AWS S3 com SSL:** +```bash +--object-store-endpoint s3.amazonaws.com \ +--object-store-access-key AKIAIOSFODNN7EXAMPLE \ +--object-store-secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \ +--object-store-use-ssl \ +--object-store-region us-east-1 +``` + +## Autenticação + +Todos os backends compatíveis com S3 requerem a autenticação AWS Signature Version 4 (ou v2): + +**Chave de Acesso** - Identificador público (como nome de usuário) +**Chave Secreta** - Chave de assinatura privada (como senha) + +O cliente Python da MinIO gerencia automaticamente todos os cálculos de assinatura. + +### Criando Credenciais + +**Para MinIO:** +```bash +# Use default credentials or create user via MinIO Console +minioadmin / minioadmin +``` + +**Para o Ceph RGW:** +```bash +radosgw-admin user create --uid="trustgraph" --display-name="TrustGraph Service" +# Returns access_key and secret_key +``` + +**Para AWS S3:** +Crie um usuário IAM com permissões S3 +Gere uma chave de acesso no Console da AWS + +## Seleção da Biblioteca: Cliente Python MinIO + +**Justificativa:** +Leve (~500KB vs ~50MB do boto3) +Compatível com S3 - funciona com qualquer endpoint de API S3 +API mais simples que o boto3 para operações básicas +Já em uso, não é necessária migração +Testado em batalha com MinIO e outros sistemas S3 + +## Implementação do BlobStore + +**Localização:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +```python +from minio import Minio +import io +import logging + +logger = logging.getLogger(__name__) + +class BlobStore: + """ + S3-compatible blob storage for document content. + Supports MinIO, Ceph RGW, AWS S3, and other S3-compatible backends. + """ + + def __init__(self, endpoint, access_key, secret_key, bucket_name, + use_ssl=False, region=None): + """ + Initialize S3-compatible blob storage. + + Args: + endpoint: S3 endpoint (e.g., "minio:9000", "ceph-rgw:7480") + access_key: S3 access key + secret_key: S3 secret key + bucket_name: Bucket name for storage + use_ssl: Use HTTPS instead of HTTP (default: False) + region: S3 region (optional, e.g., "us-east-1") + """ + self.client = Minio( + endpoint=endpoint, + access_key=access_key, + secret_key=secret_key, + secure=use_ssl, + region=region, + ) + + self.bucket_name = bucket_name + + protocol = "https" if use_ssl else "http" + logger.info(f"Connected to S3-compatible storage at {protocol}://{endpoint}") + + self.ensure_bucket() + + def ensure_bucket(self): + """Create bucket if it doesn't exist""" + found = self.client.bucket_exists(bucket_name=self.bucket_name) + if not found: + self.client.make_bucket(bucket_name=self.bucket_name) + logger.info(f"Created bucket {self.bucket_name}") + else: + logger.debug(f"Bucket {self.bucket_name} already exists") + + async def add(self, object_id, blob, kind): + """Store blob in S3-compatible storage""" + self.client.put_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + length=len(blob), + data=io.BytesIO(blob), + content_type=kind, + ) + logger.debug("Add blob complete") + + async def remove(self, object_id): + """Delete blob from S3-compatible storage""" + self.client.remove_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + logger.debug("Remove blob complete") + + async def get(self, object_id): + """Retrieve blob from S3-compatible storage""" + resp = self.client.get_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + return resp.read() +``` + +## Benefícios Principais + +1. **Sem Dependência de Fornecedor** - Funciona com qualquer armazenamento compatível com S3. +2. **Leve** - O cliente MinIO tem apenas ~500KB. +3. **Configuração Simples** - Apenas endpoint e credenciais. +4. **Sem Migração de Dados** - Substituição direta entre backends. +5. **Testado em Combate** - O cliente MinIO funciona com todas as principais implementações S3. + +## Status da Implementação + +Todo o código foi atualizado para usar nomes de parâmetros S3 genéricos: + +✅ `blob_store.py` - Atualizado para aceitar `endpoint`, `access_key`, `secret_key`. +✅ `librarian.py` - Nomes de parâmetros atualizados. +✅ `service.py` - Argumentos da CLI e configuração atualizados. +✅ Documentação atualizada. + +## Melhorias Futuras + +1. **Suporte SSL/TLS** - Adicionar a flag `--s3-use-ssl` para HTTPS. +2. **Lógica de Repetição** - Implementar retrocesso exponencial para falhas transitórias. +3. **URLs Pré-assinadas** - Gerar URLs temporárias de upload/download. +4. **Suporte Multi-região** - Replicar blobs entre regiões. +5. **Integração CDN** - Servir blobs via CDN. +6. **Classes de Armazenamento** - Usar classes de armazenamento S3 para otimização de custos. +7. **Políticas de Ciclo de Vida** - Arquivamento/exclusão automática. +8. **Versionamento** - Armazenar múltiplas versões de blobs. + +## Referências + +Cliente Python MinIO: https://min.io/docs/minio/linux/developers/python/API.html +API S3 Ceph RGW: https://docs.ceph.com/en/latest/radosgw/s3/ +Referência da API S3: https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html diff --git a/docs/tech-specs/minio-to-s3-migration.ru.md b/docs/tech-specs/minio-to-s3-migration.ru.md new file mode 100644 index 00000000..0926b12f --- /dev/null +++ b/docs/tech-specs/minio-to-s3-migration.ru.md @@ -0,0 +1,258 @@ +# Технические характеристики: Поддержка хранилища, совместимого с S3 + +## Обзор + +Сервис Librarian использует объектное хранилище, совместимое с S3, для хранения двоичных данных документов. Этот документ описывает реализацию, которая обеспечивает поддержку любого хранилища, совместимого с S3, включая MinIO, Ceph RADOS Gateway (RGW), AWS S3, Cloudflare R2, DigitalOcean Spaces и другие. + +## Архитектура + +### Компоненты хранения +**Хранилище двоичных данных**: Объектное хранилище, совместимое с S3, через `minio` Python клиентскую библиотеку. +**Хранилище метаданных**: Cassandra (хранит сопоставление object_id и метаданные документов). +**Затронутый компонент**: Только сервис Librarian. +**Схема хранения**: Гибридное хранилище с метаданными в Cassandra и содержимым в хранилище, совместимом с S3. + +### Реализация +**Библиотека**: `minio` Python клиент (поддерживает любой API, совместимый с S3). +**Расположение**: `trustgraph-flow/trustgraph/librarian/blob_store.py` +**Операции**: + `add()` - Сохранение двоичных данных с object_id в формате UUID. + `get()` - Получение двоичных данных по object_id. + `remove()` - Удаление двоичных данных по object_id. + `ensure_bucket()` - Создание бакета, если он не существует. +**Бакет**: `library` +**Путь к объекту**: `doc/{object_id}` +**Поддерживаемые типы MIME**: `text/plain`, `application/pdf` + +### Основные файлы +1. `trustgraph-flow/trustgraph/librarian/blob_store.py` - Реализация BlobStore. +2. `trustgraph-flow/trustgraph/librarian/librarian.py` - Инициализация BlobStore. +3. `trustgraph-flow/trustgraph/librarian/service.py` - Конфигурация сервиса. +4. `trustgraph-flow/pyproject.toml` - Зависимости (пакет `minio`). +5. `docs/apis/api-librarian.md` - Документация API. + +## Поддерживаемые системы хранения + +Реализация работает с любой системой объектного хранения, совместимой с S3: + +### Протестировано/Поддерживается +**Ceph RADOS Gateway (RGW)** - Распределенная система хранения с API S3 (конфигурация по умолчанию). +**MinIO** - Легковесное объектное хранилище для самостоятельного размещения. +**Garage** - Легковесное географически распределенное хранилище, совместимое с S3. + +### Должно работать (совместимо с S3) +**AWS S3** - Облачное объектное хранилище от Amazon. +**Cloudflare R2** - Хранилище от Cloudflare, совместимое с S3. +**DigitalOcean Spaces** - Объектное хранилище от DigitalOcean. +**Wasabi** - Облачное хранилище, совместимое с S3. +**Backblaze B2** - Хранилище резервных копий, совместимое с S3. +Любая другая служба, реализующая REST API S3. + +## Конфигурация + +### Аргументы командной строки + +```bash +librarian \ + --object-store-endpoint \ + --object-store-access-key \ + --object-store-secret-key \ + [--object-store-use-ssl] \ + [--object-store-region ] +``` + +**Примечание:** Не включайте `http://` или `https://` в конечную точку. Используйте `--object-store-use-ssl` для включения HTTPS. + +### Переменные окружения (Альтернативный способ) + +```bash +OBJECT_STORE_ENDPOINT= +OBJECT_STORE_ACCESS_KEY= +OBJECT_STORE_SECRET_KEY= +OBJECT_STORE_USE_SSL=true|false # Optional, default: false +OBJECT_STORE_REGION= # Optional +``` + +### Примеры + +**Ceph RADOS Gateway (по умолчанию):** +```bash +--object-store-endpoint ceph-rgw:7480 \ +--object-store-access-key object-user \ +--object-store-secret-key object-password +``` + +**MinIO:** +```bash +--object-store-endpoint minio:9000 \ +--object-store-access-key minioadmin \ +--object-store-secret-key minioadmin +``` + +**Гараж (совместимый с S3):** +```bash +--object-store-endpoint garage:3900 \ +--object-store-access-key GK000000000000000000000001 \ +--object-store-secret-key b171f00be9be4c32c734f4c05fe64c527a8ab5eb823b376cfa8c2531f70fc427 +``` + +**AWS S3 с использованием SSL:** +```bash +--object-store-endpoint s3.amazonaws.com \ +--object-store-access-key AKIAIOSFODNN7EXAMPLE \ +--object-store-secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \ +--object-store-use-ssl \ +--object-store-region us-east-1 +``` + +## Аутентификация + +Все бэкенды, совместимые с S3, требуют аутентификации AWS Signature Version 4 (или v2): + +**Access Key** - Публичный идентификатор (например, имя пользователя) +**Secret Key** - Приватный ключ для подписи (например, пароль) + +Python-клиент MinIO автоматически обрабатывает все вычисления подписи. + +### Создание учетных данных + +**Для MinIO:** +```bash +# Use default credentials or create user via MinIO Console +minioadmin / minioadmin +``` + +**Для Ceph RGW:** +```bash +radosgw-admin user create --uid="trustgraph" --display-name="TrustGraph Service" +# Returns access_key and secret_key +``` + +**Для AWS S3:** +Создайте пользователя IAM с разрешениями S3 +Сгенерируйте ключ доступа в консоли AWS + +## Выбор библиотеки: MinIO Python Client + +**Обоснование:** +Легковесная (~500 КБ против ~50 МБ у boto3) +Совместима с S3 - работает с любым конечным пунктом API S3 +Более простой API, чем boto3, для основных операций +Уже используется, не требуется миграция +Проверена в боевых условиях с MinIO и другими системами S3 + +## Реализация BlobStore + +**Расположение:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +```python +from minio import Minio +import io +import logging + +logger = logging.getLogger(__name__) + +class BlobStore: + """ + S3-compatible blob storage for document content. + Supports MinIO, Ceph RGW, AWS S3, and other S3-compatible backends. + """ + + def __init__(self, endpoint, access_key, secret_key, bucket_name, + use_ssl=False, region=None): + """ + Initialize S3-compatible blob storage. + + Args: + endpoint: S3 endpoint (e.g., "minio:9000", "ceph-rgw:7480") + access_key: S3 access key + secret_key: S3 secret key + bucket_name: Bucket name for storage + use_ssl: Use HTTPS instead of HTTP (default: False) + region: S3 region (optional, e.g., "us-east-1") + """ + self.client = Minio( + endpoint=endpoint, + access_key=access_key, + secret_key=secret_key, + secure=use_ssl, + region=region, + ) + + self.bucket_name = bucket_name + + protocol = "https" if use_ssl else "http" + logger.info(f"Connected to S3-compatible storage at {protocol}://{endpoint}") + + self.ensure_bucket() + + def ensure_bucket(self): + """Create bucket if it doesn't exist""" + found = self.client.bucket_exists(bucket_name=self.bucket_name) + if not found: + self.client.make_bucket(bucket_name=self.bucket_name) + logger.info(f"Created bucket {self.bucket_name}") + else: + logger.debug(f"Bucket {self.bucket_name} already exists") + + async def add(self, object_id, blob, kind): + """Store blob in S3-compatible storage""" + self.client.put_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + length=len(blob), + data=io.BytesIO(blob), + content_type=kind, + ) + logger.debug("Add blob complete") + + async def remove(self, object_id): + """Delete blob from S3-compatible storage""" + self.client.remove_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + logger.debug("Remove blob complete") + + async def get(self, object_id): + """Retrieve blob from S3-compatible storage""" + resp = self.client.get_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + return resp.read() +``` + +## Ключевые преимущества + +1. **Отсутствие привязки к конкретному поставщику** - Работает с любым хранилищем, совместимым с S3. +2. **Легковесность** - Клиент MinIO занимает всего около 500 КБ. +3. **Простая настройка** - Только конечная точка и учетные данные. +4. **Отсутствие миграции данных** - Замена между бэкендами без перебоев. +5. **Проверено в боевых условиях** - Клиент MinIO работает со всеми основными реализациями S3. + +## Статус реализации + +Весь код был обновлен для использования общих имен параметров S3: + +✅ `blob_store.py` - Обновлено для приема `endpoint`, `access_key`, `secret_key` +✅ `librarian.py` - Обновлены имена параметров +✅ `service.py` - Обновлены аргументы командной строки и конфигурация +✅ Обновлена документация + +## Планируемые улучшения + +1. **Поддержка SSL/TLS** - Добавить флаг `--s3-use-ssl` для HTTPS. +2. **Логика повторных попыток** - Реализовать экспоненциальную задержку для временных сбоев. +3. **Временные URL-адреса** - Генерировать временные URL-адреса для загрузки/скачивания. +4. **Поддержка нескольких регионов** - Репликация объектов между регионами. +5. **Интеграция с CDN** - Предоставление объектов через CDN. +6. **Классы хранения** - Использование классов хранения S3 для оптимизации затрат. +7. **Политики жизненного цикла** - Автоматическое архивирование/удаление. +8. **Версионирование** - Хранение нескольких версий объектов. + +## Ссылки + +MinIO Python Client: https://min.io/docs/minio/linux/developers/python/API.html +Ceph RGW S3 API: https://docs.ceph.com/en/latest/radosgw/s3/ +S3 API Reference: https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html diff --git a/docs/tech-specs/minio-to-s3-migration.sw.md b/docs/tech-specs/minio-to-s3-migration.sw.md new file mode 100644 index 00000000..538049f3 --- /dev/null +++ b/docs/tech-specs/minio-to-s3-migration.sw.md @@ -0,0 +1,258 @@ +# Vipimo vya Kisaikolojia: Usaidizi wa Hifadhi Data inayolingana na S3 + +## Muhtasari + +Huduma ya Librarian hutumia hifadhi data ya vitu inayolingana na S3 kwa kuhifadhi faili za hati. Haya yanatoa maelezo ya utekelezaji unaoleta uwezo wa kusaidia mfumo wowote wa hifadhi inayolingana na S3, ikiwa ni pamoja na MinIO, Ceph RADOS Gateway (RGW), AWS S3, Cloudflare R2, DigitalOcean Spaces, na wengine. + +## Muundo + +### Vipengele vya Uhifadhi +**Hifadhi ya Vitu:** Hifadhi data ya vitu inayolingana na S3 kupitia `minio` maktaba ya mteja ya Python +**Hifadhi ya MetaData:** Cassandra (hufanya kazi ya kuhifadhi uhusiano wa object_id na metadata ya hati) +**Kipengele Kilichohusika:** Huduma ya Librarian pekee +**Mfumo wa Uhifadhi:** Uhifadhi mchanganyiko na metadata katika Cassandra, na yaliyomo katika hifadhi inayolingana na S3 + +### Utendaji +**Maktaba:** `minio` mteja wa Python (inaunga mkono API yoyote inayolingana na S3) +**Mahali:** `trustgraph-flow/trustgraph/librarian/blob_store.py` +**Tendo:** + `add()` - Hifadhi faili kwa kitambulisho cha kipekee (object_id) + `get()` - Rudisha faili kwa kitambulisho cha kipekee (object_id) + `remove()` - Futa faili kwa kitambulisho cha kipekee (object_id) + `ensure_bucket()` - Unda kiasi (bucket) ikiwa haipo +**Kiasi (Bucket):** `library` +**Njia ya Faili:** `doc/{object_id}` +**Aina Zinazoidhinishwa (MIME Types):** `text/plain`, `application/pdf` + +### Faili Muhimu +1. `trustgraph-flow/trustgraph/librarian/blob_store.py` - Utendaji wa BlobStore +2. `trustgraph-flow/trustgraph/librarian/librarian.py` - Uanzishaji wa BlobStore +3. `trustgraph-flow/trustgraph/librarian/service.py` - Usanidi wa huduma +4. `trustgraph-flow/pyproject.toml` - Utendakazi (pakiti ya `minio`) +5. `docs/apis/api-librarian.md` - Nyaraka za API + +## Mifumo ya Uhifadhi Inayoungwa Mkono + +Utendaji huu unafanya kazi na mfumo wowote wa hifadhi data ya vitu inayolingana na S3: + +### Imethibitishwa/Inaungwa Mkono +**Ceph RADOS Gateway (RGW)** - Mfumo wa hifadhi usambazwa na API ya S3 (usanidi chaguu) +**MinIO** - Hifadhi data ya vitu nyepesi inayoweza kuendeshwa na wewe mwenyewe +**Garage** - Hifadhi data ya vitu nyepesi inayopaswa kusambazwa kijiografia inayolingana na S3 + +### Inapaswa Kufanya kazi (Inayolingana na S3) +**AWS S3** - Hifadhi data ya vitu ya Amazon kwenye wingu +**Cloudflare R2** - Hifadhi data inayolingana na S3 ya Cloudflare +**DigitalOcean Spaces** - Hifadhi data ya vitu ya DigitalOcean +**Wasabi** - Hifadhi data ya vitu kwenye wingu inayolingana na S3 +**Backblaze B2** - Hifadhi data ya vitu inayolingana na S3 kwa ajili ya chelezo +Huduma yoyote nyingine inayotekeleza API ya S3 REST + +## Usanidi + +### Majadiliano ya CLI + +```bash +librarian \ + --object-store-endpoint \ + --object-store-access-key \ + --object-store-secret-key \ + [--object-store-use-ssl] \ + [--object-store-region ] +``` + +**Kumbuka:** Usijumuishie `http://` au `https://` katika mwisho. Tumia `--object-store-use-ssl` ili kuwezesha HTTPS. + +### Vigezo vya Mazingira (Mbadala) + +```bash +OBJECT_STORE_ENDPOINT= +OBJECT_STORE_ACCESS_KEY= +OBJECT_STORE_SECRET_KEY= +OBJECT_STORE_USE_SSL=true|false # Optional, default: false +OBJECT_STORE_REGION= # Optional +``` + +### Mifano + +**Lango la RADOS la Ceph (linalolingana na chaguo-msingi):** +```bash +--object-store-endpoint ceph-rgw:7480 \ +--object-store-access-key object-user \ +--object-store-secret-key object-password +``` + +**MinIO:** +```bash +--object-store-endpoint minio:9000 \ +--object-store-access-key minioadmin \ +--object-store-secret-key minioadmin +``` + +**Gara (Inayoambatana na S3):** +```bash +--object-store-endpoint garage:3900 \ +--object-store-access-key GK000000000000000000000001 \ +--object-store-secret-key b171f00be9be4c32c734f4c05fe64c527a8ab5eb823b376cfa8c2531f70fc427 +``` + +**AWS S3 na SSL:** +```bash +--object-store-endpoint s3.amazonaws.com \ +--object-store-access-key AKIAIOSFODNN7EXAMPLE \ +--object-store-secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \ +--object-store-use-ssl \ +--object-store-region us-east-1 +``` + +## Uthibitisho + +Vifaa vyote vinavyolingana na S3 vinahitaji uthibitisho wa AWS Signature Version 4 (au v2): + +**Ufunguo wa Ufikiaji** - Kitambulisho cha umma (kama jina la mtumiaji) +**Ufunguo Siri** - Ufunguo wa siri wa usaini (kama nenosiri) + +Mteja wa Python wa MinIO hushughulikia hesabu yote ya usaini kiotomatiki. + +### Kuunda Anwani + +**Kwa MinIO:** +```bash +# Use default credentials or create user via MinIO Console +minioadmin / minioadmin +``` + +**Kwa Ceph RGW:** +```bash +radosgw-admin user create --uid="trustgraph" --display-name="TrustGraph Service" +# Returns access_key and secret_key +``` + +**Kwa AWS S3:** +Unda mtumiaji wa IAM na ruhusa za S3 +Toa ufunguo wa ufikiaji katika Konsoli ya AWS + +## Chaguo la Klibu: Mteja wa MinIO Python + +**Sababu:** +Nyepesi (~500KB dhidi ya ~50MB ya boto3) +Inafanana na S3 - inafanya kazi na mwisho wowote wa API ya S3 +API rahisi kuliko boto3 kwa operesheni za msingi +Tayari inatumika, hakuna uhamishaji unaohitajika +Imethibitishwa kwa MinIO na mifumo mingine ya S3 + +## Utendaji wa BlobStore + +**Mahali:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +```python +from minio import Minio +import io +import logging + +logger = logging.getLogger(__name__) + +class BlobStore: + """ + S3-compatible blob storage for document content. + Supports MinIO, Ceph RGW, AWS S3, and other S3-compatible backends. + """ + + def __init__(self, endpoint, access_key, secret_key, bucket_name, + use_ssl=False, region=None): + """ + Initialize S3-compatible blob storage. + + Args: + endpoint: S3 endpoint (e.g., "minio:9000", "ceph-rgw:7480") + access_key: S3 access key + secret_key: S3 secret key + bucket_name: Bucket name for storage + use_ssl: Use HTTPS instead of HTTP (default: False) + region: S3 region (optional, e.g., "us-east-1") + """ + self.client = Minio( + endpoint=endpoint, + access_key=access_key, + secret_key=secret_key, + secure=use_ssl, + region=region, + ) + + self.bucket_name = bucket_name + + protocol = "https" if use_ssl else "http" + logger.info(f"Connected to S3-compatible storage at {protocol}://{endpoint}") + + self.ensure_bucket() + + def ensure_bucket(self): + """Create bucket if it doesn't exist""" + found = self.client.bucket_exists(bucket_name=self.bucket_name) + if not found: + self.client.make_bucket(bucket_name=self.bucket_name) + logger.info(f"Created bucket {self.bucket_name}") + else: + logger.debug(f"Bucket {self.bucket_name} already exists") + + async def add(self, object_id, blob, kind): + """Store blob in S3-compatible storage""" + self.client.put_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + length=len(blob), + data=io.BytesIO(blob), + content_type=kind, + ) + logger.debug("Add blob complete") + + async def remove(self, object_id): + """Delete blob from S3-compatible storage""" + self.client.remove_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + logger.debug("Remove blob complete") + + async def get(self, object_id): + """Retrieve blob from S3-compatible storage""" + resp = self.client.get_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + return resp.read() +``` + +## Faida Muhimu + +1. **Hakuna Utegemezi wa Mtoa Huduma** - Inafanya kazi na hifadhi yoyote inayolingana na S3. +2. **Nyepesi** - Mteja wa MinIO ni takriban 500KB. +3. **Uwekaji Rahisi** - Tu mwisho na anwani za kuingia. +4. **Hakuna Uhamishaji wa Data** - Badala ya moja kwa moja kati ya mifumo ya nyuma. +5. **Imethibitishwa katika Vita** - Mteja wa MinIO unafanya kazi na matoleo yote makubwa ya S3. + +## Hali ya Utendaji + +Msimbo wote umeongezwa ili kutumia majina ya vigezo vya S3. + +✅ `blob_store.py` - Imeongezwa ili kukubali `endpoint`, `access_key`, `secret_key` +✅ `librarian.py` - Majina ya vigezo yameongezwa. +✅ `service.py` - Majadiliano ya CLI na usanidi yameongezwa. +✅ Nyaraka zimeongezwa. + +## Maboresho ya Baadaye + +1. **Usaidizi wa SSL/TLS** - Ongeza bendera `--s3-use-ssl` kwa HTTPS. +2. **Mantiki ya Kujaribu Upya** - Tekeleza kuchelewesha kwa eksponensia kwa kushindwa kwa muda mfupi. +3. **Anwani za Muda** - Zunda anwani za muda za kupakia/kupakua. +4. **Usaidizi wa Mikoa Mbalimbali** - Nakili data katika mikoa mbalimbali. +5. **Uunganisho wa CDN** - Toa data kupitia CDN. +6. **Daraja za Hifadhi** - Tumia daraja za hifadhi za S3 kwa uboreshaji wa gharama. +7. **Sera za Maisha** - Hifadhi/ufute data kiotomatiki. +8. **Toleo** - Hifadhi matoleo mengi ya data. + +## Marejeleo + +Mteja wa MinIO wa Python: https://min.io/docs/minio/linux/developers/python/API.html +API ya S3 ya Ceph RGW: https://docs.ceph.com/en/latest/radosgw/s3/ +Marejeleo ya API ya S3: https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html diff --git a/docs/tech-specs/minio-to-s3-migration.tr.md b/docs/tech-specs/minio-to-s3-migration.tr.md new file mode 100644 index 00000000..599acb04 --- /dev/null +++ b/docs/tech-specs/minio-to-s3-migration.tr.md @@ -0,0 +1,258 @@ +# Teknik Özellikler: S3 Uyumlu Depolama Arka Ucu Desteği + +## Genel Bakış + +Librarian hizmeti, belge bloğu depolaması için S3 uyumlu nesne depolamayı kullanır. Bu özellik, MinIO, Ceph RADOS Gateway (RGW), AWS S3, Cloudflare R2, DigitalOcean Spaces ve diğerleri dahil olmak üzere herhangi bir S3 uyumlu arka uç için desteği etkinleştiren uygulamayı belgelemektedir. + +## Mimari + +### Depolama Bileşenleri +**Bloğu Depolama**: `minio` Python istemci kitaplığı aracılığıyla S3 uyumlu nesne depolama +**Metaveri Depolama**: Cassandra (object_id eşlemesini ve belge meta verilerini depolar) +**Etkilenen Bileşen**: Yalnızca Librarian hizmeti +**Depolama Modeli**: Cassandra'da metaveri, S3 uyumlu depolamada içerikle hibrit depolama + +### Uygulama +**Kitaplık**: `minio` Python istemcisi (herhangi bir S3 uyumlu API'yi destekler) +**Konum**: `trustgraph-flow/trustgraph/librarian/blob_store.py` +**İşlemler**: + `add()` - UUID object_id ile bloğu kaydet + `get()` - object_id ile bloğu al + `remove()` - object_id ile bloğu sil + `ensure_bucket()` - Yoksa bucket oluştur +**Bucket**: `library` +**Nesne Yolu**: `doc/{object_id}` +**Desteklenen MIME Türleri**: `text/plain`, `application/pdf` + +### Önemli Dosyalar +1. `trustgraph-flow/trustgraph/librarian/blob_store.py` - BlobStore uygulaması +2. `trustgraph-flow/trustgraph/librarian/librarian.py` - BlobStore başlatma +3. `trustgraph-flow/trustgraph/librarian/service.py` - Hizmet yapılandırması +4. `trustgraph-flow/pyproject.toml` - Bağımlılıklar (`minio` paketi) +5. `docs/apis/api-librarian.md` - API dokümantasyonu + +## Desteklenen Depolama Arka Uçları + +Bu uygulama, herhangi bir S3 uyumlu nesne depolama sistemiyle çalışır: + +### Test Edildi/Destekleniyor +**Ceph RADOS Gateway (RGW)** - S3 API'sine sahip dağıtılmış depolama sistemi (varsayılan yapılandırma) +**MinIO** - Hafif, kendi kendine barındırılan nesne depolama +**Garage** - Hafif, coğrafi olarak dağıtılmış S3 uyumlu depolama + +### Çalışması Gerekiyor (S3 Uyumlu) +**AWS S3** - Amazon'un bulut nesne depolaması +**Cloudflare R2** - Cloudflare'in S3 uyumlu depolaması +**DigitalOcean Spaces** - DigitalOcean'ın nesne depolaması +**Wasabi** - S3 uyumlu bulut depolama +**Backblaze B2** - S3 uyumlu yedekleme depolama +S3 REST API'sini uygulayan herhangi bir hizmet + +## Yapılandırma + +### CLI Argümanları + +```bash +librarian \ + --object-store-endpoint \ + --object-store-access-key \ + --object-store-secret-key \ + [--object-store-use-ssl] \ + [--object-store-region ] +``` + +**Not:** `http://` veya `https://`'i uç noktada dahil etmeyin. HTTPS'yi etkinleştirmek için `--object-store-use-ssl`'yi kullanın. + +### Ortam Değişkenleri (Alternatif) + +```bash +OBJECT_STORE_ENDPOINT= +OBJECT_STORE_ACCESS_KEY= +OBJECT_STORE_SECRET_KEY= +OBJECT_STORE_USE_SSL=true|false # Optional, default: false +OBJECT_STORE_REGION= # Optional +``` + +### Örnekler + +**Ceph RADOS Ağ Geçidi (varsayılan):** +```bash +--object-store-endpoint ceph-rgw:7480 \ +--object-store-access-key object-user \ +--object-store-secret-key object-password +``` + +**MinIO:** +```bash +--object-store-endpoint minio:9000 \ +--object-store-access-key minioadmin \ +--object-store-secret-key minioadmin +``` + +**Garaj (S3 uyumlu):** +```bash +--object-store-endpoint garage:3900 \ +--object-store-access-key GK000000000000000000000001 \ +--object-store-secret-key b171f00be9be4c32c734f4c05fe64c527a8ab5eb823b376cfa8c2531f70fc427 +``` + +**AWS S3 SSL ile:** +```bash +--object-store-endpoint s3.amazonaws.com \ +--object-store-access-key AKIAIOSFODNN7EXAMPLE \ +--object-store-secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \ +--object-store-use-ssl \ +--object-store-region us-east-1 +``` + +## Kimlik Doğrulama + +Tüm S3 uyumlu arka uçlar, AWS Signature Version 4 (veya v2) kimlik doğrulamasını gerektirir: + +**Erişim Anahtarı** - Genel tanımlayıcı (kullanıcı adı gibi) +**Gizli Anahtar** - Özel imzalama anahtarı (parola gibi) + +MinIO Python istemcisi, tüm imza hesaplamalarını otomatik olarak yapar. + +### Kimlik Bilgilerini Oluşturma + +**MinIO için:** +```bash +# Use default credentials or create user via MinIO Console +minioadmin / minioadmin +``` + +**Ceph RGW için:** +```bash +radosgw-admin user create --uid="trustgraph" --display-name="TrustGraph Service" +# Returns access_key and secret_key +``` + +**AWS S3 için:** +S3 izinlerine sahip bir IAM kullanıcısı oluşturun. +AWS Konsolu'nda bir erişim anahtarı oluşturun. + +## Kütüphane Seçimi: MinIO Python İstemcisi + +**Gerekçe:** +Hafif (~500KB, boto3'ün ~50MB'sine kıyasla) +S3 uyumlu - herhangi bir S3 API uç noktasıyla çalışır. +Temel işlemler için boto3'e göre daha basit bir API. +Zaten kullanımda, herhangi bir geçişe gerek yok. +MinIO ve diğer S3 sistemleriyle test edilmiş. + +## BlobStore Uygulaması + +**Konum:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +```python +from minio import Minio +import io +import logging + +logger = logging.getLogger(__name__) + +class BlobStore: + """ + S3-compatible blob storage for document content. + Supports MinIO, Ceph RGW, AWS S3, and other S3-compatible backends. + """ + + def __init__(self, endpoint, access_key, secret_key, bucket_name, + use_ssl=False, region=None): + """ + Initialize S3-compatible blob storage. + + Args: + endpoint: S3 endpoint (e.g., "minio:9000", "ceph-rgw:7480") + access_key: S3 access key + secret_key: S3 secret key + bucket_name: Bucket name for storage + use_ssl: Use HTTPS instead of HTTP (default: False) + region: S3 region (optional, e.g., "us-east-1") + """ + self.client = Minio( + endpoint=endpoint, + access_key=access_key, + secret_key=secret_key, + secure=use_ssl, + region=region, + ) + + self.bucket_name = bucket_name + + protocol = "https" if use_ssl else "http" + logger.info(f"Connected to S3-compatible storage at {protocol}://{endpoint}") + + self.ensure_bucket() + + def ensure_bucket(self): + """Create bucket if it doesn't exist""" + found = self.client.bucket_exists(bucket_name=self.bucket_name) + if not found: + self.client.make_bucket(bucket_name=self.bucket_name) + logger.info(f"Created bucket {self.bucket_name}") + else: + logger.debug(f"Bucket {self.bucket_name} already exists") + + async def add(self, object_id, blob, kind): + """Store blob in S3-compatible storage""" + self.client.put_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + length=len(blob), + data=io.BytesIO(blob), + content_type=kind, + ) + logger.debug("Add blob complete") + + async def remove(self, object_id): + """Delete blob from S3-compatible storage""" + self.client.remove_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + logger.debug("Remove blob complete") + + async def get(self, object_id): + """Retrieve blob from S3-compatible storage""" + resp = self.client.get_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + return resp.read() +``` + +## Temel Avantajlar + +1. **Satıcıya Bağlılık Yok** - Herhangi bir S3 uyumlu depolama ile çalışır. +2. **Hafif** - MinIO istemcisi yaklaşık 500KB'dir. +3. **Basit Yapılandırma** - Sadece uç nokta + kimlik bilgileri gereklidir. +4. **Veri Göçü Yok** - Arka uçlar arasında doğrudan değiştirilebilir. +5. **Kanıtlanmış** - MinIO istemcisi, tüm büyük S3 uygulamalarıyla çalışır. + +## Uygulama Durumu + +Tüm kod, genel S3 parametre adlarını kullanacak şekilde güncellenmiştir: + +✅ `blob_store.py` - `endpoint`, `access_key` ve `secret_key`'ü kabul edecek şekilde güncellendi. +✅ `librarian.py` - Parametre adları güncellendi. +✅ `service.py` - CLI argümanları ve yapılandırma güncellendi. +✅ Belgeler güncellendi. + +## Gelecek Geliştirmeler + +1. **SSL/TLS Desteği** - HTTPS için `--s3-use-ssl` bayrağı eklenecek. +2. **Yeniden Deneme Mantığı** - Geçici hatalar için üstel geri alma uygulanacak. +3. **Önceden İmzalı URL'ler** - Geçici yükleme/indirme URL'leri oluşturulacak. +4. **Çok Bölgeli Destek** - Verileri bölgeler arasında çoğaltılacak. +5. **CDN Entegrasyonu** - Veriler CDN üzerinden sunulacak. +6. **Depolama Sınıfları** - Maliyet optimizasyonu için S3 depolama sınıfları kullanılacak. +7. **Yaşam Döngüsü Politikaları** - Otomatik arşivleme/silme. +8. **Sürümleme** - Verilerin birden fazla sürümü saklanacak. + +## Referanslar + +MinIO Python İstemcisi: https://min.io/docs/minio/linux/developers/python/API.html +Ceph RGW S3 API: https://docs.ceph.com/en/latest/radosgw/s3/ +S3 API Referansı: https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html diff --git a/docs/tech-specs/minio-to-s3-migration.zh-cn.md b/docs/tech-specs/minio-to-s3-migration.zh-cn.md new file mode 100644 index 00000000..cfadf61f --- /dev/null +++ b/docs/tech-specs/minio-to-s3-migration.zh-cn.md @@ -0,0 +1,258 @@ +# 技术规范:S3 兼容的存储后端支持 + +## 概述 + +Librarian 服务使用 S3 兼容的对象存储来存储文档 Blob。此规范记录了实现,该实现支持任何 S3 兼容的后端,包括 MinIO、Ceph RADOS Gateway (RGW)、AWS S3、Cloudflare R2、DigitalOcean Spaces 等。 + +## 架构 + +### 存储组件 +**Blob 存储**: 通过 `minio` Python 客户端库实现的 S3 兼容对象存储 +**元数据存储**: Cassandra (存储 object_id 映射和文档元数据) +**受影响的组件**: 仅限 Librarian 服务 +**存储模式**: 混合存储,元数据存储在 Cassandra 中,内容存储在 S3 兼容的存储中 + +### 实现 +**库**: `minio` Python 客户端 (支持任何 S3 兼容的 API) +**位置**: `trustgraph-flow/trustgraph/librarian/blob_store.py` +**操作**: + `add()` - 使用 UUID object_id 存储 Blob + `get()` - 根据 object_id 检索 Blob + `remove()` - 根据 object_id 删除 Blob + `ensure_bucket()` - 如果不存在,则创建 Bucket +**Bucket**: `library` +**对象路径**: `doc/{object_id}` +**支持的 MIME 类型**: `text/plain`, `application/pdf` + +### 关键文件 +1. `trustgraph-flow/trustgraph/librarian/blob_store.py` - BlobStore 实现 +2. `trustgraph-flow/trustgraph/librarian/librarian.py` - BlobStore 初始化 +3. `trustgraph-flow/trustgraph/librarian/service.py` - 服务配置 +4. `trustgraph-flow/pyproject.toml` - 依赖项 (`minio` 包) +5. `docs/apis/api-librarian.md` - API 文档 + +## 支持的存储后端 + +此实现适用于任何 S3 兼容的对象存储系统: + +### 已测试/支持 +**Ceph RADOS Gateway (RGW)** - 具有 S3 API 的分布式存储系统 (默认配置) +**MinIO** - 轻量级的自托管对象存储 +**Garage** - 轻量级的分布式 S3 兼容存储 + +### 应该可以工作 (S3 兼容) +**AWS S3** - Amazon 的云对象存储 +**Cloudflare R2** - Cloudflare 的 S3 兼容存储 +**DigitalOcean Spaces** - DigitalOcean 的对象存储 +**Wasabi** - S3 兼容的云存储 +**Backblaze B2** - S3 兼容的备份存储 +任何实现 S3 REST API 的服务 + +## 配置 + +### 命令行参数 + +```bash +librarian \ + --object-store-endpoint \ + --object-store-access-key \ + --object-store-secret-key \ + [--object-store-use-ssl] \ + [--object-store-region ] +``` + +**注意:** 请不要在端点中包含 `http://` 或 `https://`。 使用 `--object-store-use-ssl` 启用 HTTPS。 + +### 环境变量(备选方案) + +```bash +OBJECT_STORE_ENDPOINT= +OBJECT_STORE_ACCESS_KEY= +OBJECT_STORE_SECRET_KEY= +OBJECT_STORE_USE_SSL=true|false # Optional, default: false +OBJECT_STORE_REGION= # Optional +``` + +### 示例 + +**Ceph RADOS 网关(默认):** +```bash +--object-store-endpoint ceph-rgw:7480 \ +--object-store-access-key object-user \ +--object-store-secret-key object-password +``` + +**MinIO:** +```bash +--object-store-endpoint minio:9000 \ +--object-store-access-key minioadmin \ +--object-store-secret-key minioadmin +``` + +**云存储(兼容S3):** +```bash +--object-store-endpoint garage:3900 \ +--object-store-access-key GK000000000000000000000001 \ +--object-store-secret-key b171f00be9be4c32c734f4c05fe64c527a8ab5eb823b376cfa8c2531f70fc427 +``` + +**AWS S3 使用 SSL:** +```bash +--object-store-endpoint s3.amazonaws.com \ +--object-store-access-key AKIAIOSFODNN7EXAMPLE \ +--object-store-secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \ +--object-store-use-ssl \ +--object-store-region us-east-1 +``` + +## 身份验证 + +所有兼容 S3 的后端都需要 AWS 签名版本 4(或 v2)身份验证: + +**访问密钥** - 公开标识符(类似于用户名) +**密钥** - 私有签名密钥(类似于密码) + +MinIO Python 客户端会自动处理所有签名计算。 + +### 创建凭证 + +**对于 MinIO:** +```bash +# Use default credentials or create user via MinIO Console +minioadmin / minioadmin +``` + +**适用于 Ceph RGW:** +```bash +radosgw-admin user create --uid="trustgraph" --display-name="TrustGraph Service" +# Returns access_key and secret_key +``` + +**适用于 AWS S3:** +创建具有 S3 权限的 IAM 用户 +在 AWS 控制台中生成访问密钥 + +## 库选择:MinIO Python 客户端 + +**理由:** +轻量级(约 500KB,而 boto3 约为 50MB) +与 S3 兼容,适用于任何 S3 API 端点 +对于基本操作,API 比 boto3 更简单 +已在使用中,无需迁移 +经过 MinIO 和其他 S3 系统的严格测试 + +## BlobStore 实施 + +**位置:** `trustgraph-flow/trustgraph/librarian/blob_store.py` + +```python +from minio import Minio +import io +import logging + +logger = logging.getLogger(__name__) + +class BlobStore: + """ + S3-compatible blob storage for document content. + Supports MinIO, Ceph RGW, AWS S3, and other S3-compatible backends. + """ + + def __init__(self, endpoint, access_key, secret_key, bucket_name, + use_ssl=False, region=None): + """ + Initialize S3-compatible blob storage. + + Args: + endpoint: S3 endpoint (e.g., "minio:9000", "ceph-rgw:7480") + access_key: S3 access key + secret_key: S3 secret key + bucket_name: Bucket name for storage + use_ssl: Use HTTPS instead of HTTP (default: False) + region: S3 region (optional, e.g., "us-east-1") + """ + self.client = Minio( + endpoint=endpoint, + access_key=access_key, + secret_key=secret_key, + secure=use_ssl, + region=region, + ) + + self.bucket_name = bucket_name + + protocol = "https" if use_ssl else "http" + logger.info(f"Connected to S3-compatible storage at {protocol}://{endpoint}") + + self.ensure_bucket() + + def ensure_bucket(self): + """Create bucket if it doesn't exist""" + found = self.client.bucket_exists(bucket_name=self.bucket_name) + if not found: + self.client.make_bucket(bucket_name=self.bucket_name) + logger.info(f"Created bucket {self.bucket_name}") + else: + logger.debug(f"Bucket {self.bucket_name} already exists") + + async def add(self, object_id, blob, kind): + """Store blob in S3-compatible storage""" + self.client.put_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + length=len(blob), + data=io.BytesIO(blob), + content_type=kind, + ) + logger.debug("Add blob complete") + + async def remove(self, object_id): + """Delete blob from S3-compatible storage""" + self.client.remove_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + logger.debug("Remove blob complete") + + async def get(self, object_id): + """Retrieve blob from S3-compatible storage""" + resp = self.client.get_object( + bucket_name=self.bucket_name, + object_name=f"doc/{object_id}", + ) + return resp.read() +``` + +## 关键优势 + +1. **无厂商锁定** - 适用于任何兼容 S3 的存储 +2. **轻量级** - MinIO 客户端仅约 500KB +3. **简单配置** - 仅需端点 + 凭据 +4. **无需数据迁移** - 作为后端之间的直接替代方案 +5. **经过严格测试** - MinIO 客户端与所有主要的 S3 实现兼容 + +## 实现状态 + +所有的代码都已更新为使用通用的 S3 参数名称: + +✅ `blob_store.py` - 更新为接受 `endpoint`, `access_key`, `secret_key` +✅ `librarian.py` - 更新了参数名称 +✅ `service.py` - 更新了 CLI 参数和配置 +✅ 文档已更新 + +## 未来增强功能 + +1. **SSL/TLS 支持** - 添加 `--s3-use-ssl` 标志以支持 HTTPS +2. **重试逻辑** - 针对瞬时错误实现指数级退避 +3. **预签名 URL** - 生成临时上传/下载 URL +4. **多区域支持** - 在区域之间复制数据块 +5. **CDN 集成** - 通过 CDN 提供数据块 +6. **存储类别** - 使用 S3 存储类别进行成本优化 +7. **生命周期策略** - 自动归档/删除 +8. **版本控制** - 存储数据块的多个版本 + +## 参考文献 + +MinIO Python 客户端: https://min.io/docs/minio/linux/developers/python/API.html +Ceph RGW S3 API: https://docs.ceph.com/en/latest/radosgw/s3/ +S3 API 参考: https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html diff --git a/docs/tech-specs/more-config-cli.pt.md b/docs/tech-specs/more-config-cli.pt.md new file mode 100644 index 00000000..cf25862d --- /dev/null +++ b/docs/tech-specs/more-config-cli.pt.md @@ -0,0 +1,279 @@ +# Mais Configurações - Especificação Técnica da Interface de Linha de Comando (CLI) + +## Visão Geral + +Esta especificação descreve as capacidades aprimoradas de configuração por meio da interface de linha de comando para o TrustGraph, permitindo que os usuários gerenciem itens de configuração individuais por meio de comandos de linha de comando granulares. A integração suporta quatro casos de uso primários: + +1. **Listar Itens de Configuração**: Exibir chaves de configuração de um tipo específico +2. **Obter Item de Configuração**: Recuperar valores de configuração específicos +3. **Definir Item de Configuração**: Definir ou atualizar itens de configuração individuais +4. **Excluir Item de Configuração**: Remover itens de configuração específicos + +## Objetivos + +**Controle Granular**: Permitir o gerenciamento de itens de configuração individuais, em vez de operações em lote +**Listagem Baseada em Tipo**: Permitir que os usuários explorem itens de configuração por tipo +**Operações de Item Único**: Fornecer comandos para obter/definir/excluir itens de configuração individuais +**Integração com a API**: Utilizar a API de Configuração existente para todas as operações +**Padrão de CLI Consistente**: Seguir as convenções e padrões de CLI do TrustGraph estabelecidos +**Tratamento de Erros**: Fornecer mensagens de erro claras para operações inválidas +**Saída JSON**: Suportar saída estruturada para uso programático +**Documentação**: Incluir ajuda abrangente e exemplos de uso + +## Contexto + +Atualmente, o TrustGraph fornece gerenciamento de configuração por meio da API de Configuração e um único comando de linha de comando `tg-show-config` que exibe toda a configuração. Embora isso funcione para visualizar a configuração, ele carece de capacidades de gerenciamento granular. + +As limitações atuais incluem: +Não há como listar itens de configuração por tipo a partir da linha de comando +Não há comando de linha de comando para recuperar valores de configuração específicos +Não há comando de linha de comando para definir itens de configuração individuais +Não há comando de linha de comando para excluir itens de configuração específicos + +Esta especificação aborda essas lacunas, adicionando quatro novos comandos de linha de comando que fornecem gerenciamento de configuração granular. Ao expor operações individuais da API de Configuração por meio de comandos de linha de comando, o TrustGraph pode: +Permitir o gerenciamento de configuração por script +Permitir a exploração da estrutura de configuração por tipo +Suportar atualizações de configuração direcionadas +Fornecer controle de configuração granular + +## Design Técnico + +### Arquitetura + +A configuração aprimorada da linha de comando requer os seguintes componentes técnicos: + +1. **tg-list-config-items** + Lista chaves de configuração para um tipo especificado + Chama o método da API Config.list(type) + Exibe a lista de chaves de configuração + + Módulo: `trustgraph.cli.list_config_items` + +2. **tg-get-config-item** + Recupera um(s) item(ns) de configuração específico(s) + Chama o método da API Config.get(keys) + Exibe os valores de configuração em formato JSON + + Módulo: `trustgraph.cli.get_config_item` + +3. **tg-put-config-item** + Define ou atualiza um item de configuração + Chama o método da API Config.put(values) + Aceita parâmetros de tipo, chave e valor + + Módulo: `trustgraph.cli.put_config_item` + +4. **tg-delete-config-item** + Remove um item de configuração + Chama o método da API Config.delete(keys) + Aceita parâmetros de tipo e chave + + Módulo: `trustgraph.cli.delete_config_item` + +### Modelos de Dados + +#### ConfigKey e ConfigValue + +Os comandos utilizam as estruturas de dados existentes de `trustgraph.api.types`: + +```python +@dataclasses.dataclass +class ConfigKey: + type : str + key : str + +@dataclasses.dataclass +class ConfigValue: + type : str + key : str + value : str +``` + +Esta abordagem permite: +Tratamento de dados consistente entre a interface de linha de comando (CLI) e a API. +Operações de configuração com segurança de tipo. +Formatos de entrada/saída estruturados. +Integração com a API de Configuração existente. + +### Especificações de comandos da CLI + +#### tg-list-config-items +```bash +tg-list-config-items --type [--format text|json] [--api-url ] +``` +**Propósito**: Listar todas as chaves de configuração para um determinado tipo. +**Chamada da API**: `Config.list(type)` +**Saída**: + `text` (padrão): Chaves de configuração separadas por quebras de linha. + `json`: Array JSON de chaves de configuração. + +#### tg-get-config-item +```bash +tg-get-config-item --type --key [--format text|json] [--api-url ] +``` +**Propósito**: Recuperar um item de configuração específico. +**Chamada da API**: `Config.get([ConfigKey(type, key)])` +**Saída**: + `text` (padrão): Valor de string bruto. + `json`: Valor de string codificado em JSON. + +#### tg-put-config-item +```bash +tg-put-config-item --type --key --value [--api-url ] +tg-put-config-item --type --key --stdin [--api-url ] +``` +**Propósito**: Definir ou atualizar um item de configuração. +**Chamada da API**: `Config.put([ConfigValue(type, key, value)])` +**Opções de Entrada**: + `--value`: Valor de string fornecido diretamente na linha de comando. + `--stdin`: Ler o valor da entrada padrão. +**Saída**: Confirmação de sucesso. + +#### tg-delete-config-item +```bash +tg-delete-config-item --type --key [--api-url ] +``` +**Propósito**: Excluir item de configuração +**Chamada da API**: `Config.delete([ConfigKey(type, key)])` +**Saída**: Confirmação de sucesso + +### Detalhes da Implementação + +Todos os comandos seguem o padrão estabelecido da CLI TrustGraph: +Use `argparse` para análise de argumentos da linha de comando +Importe e use `trustgraph.api.Api` para comunicação com o backend +Siga os mesmos padrões de tratamento de erros dos comandos da CLI existentes +Suporte ao parâmetro padrão `--api-url` para configuração do endpoint da API +Forneça texto de ajuda descritivo e exemplos de uso + +#### Tratamento do Formato de Saída + +**Formato de Texto (Padrão)**: +`tg-list-config-items`: Uma chave por linha, texto simples +`tg-get-config-item`: Valor de string bruto, sem aspas ou codificação + +**Formato JSON**: +`tg-list-config-items`: Array de strings `["key1", "key2", "key3"]` +`tg-get-config-item`: Valor de string codificado em JSON `"actual string value"` + +#### Tratamento da Entrada + +**tg-put-config-item** suporta dois métodos de entrada mutuamente exclusivos: +`--value `: Valor de string direto na linha de comando +`--stdin`: Leia toda a entrada da entrada padrão como o valor de configuração +O conteúdo da entrada padrão é lido como texto bruto (preservando novas linhas, espaços em branco, etc.) +Suporta o envio por pipe de arquivos, comandos ou entrada interativa + +## Considerações de Segurança + +**Validação da Entrada**: Todos os parâmetros da linha de comando devem ser validados antes das chamadas da API +**Autenticação da API**: Os comandos herdam os mecanismos de autenticação da API existentes +**Acesso à Configuração**: Os comandos respeitam os controles de acesso à configuração existentes +**Informações de Erro**: As mensagens de erro não devem vazar detalhes confidenciais da configuração + +## Considerações de Desempenho + +**Operações de Item Único**: Os comandos são projetados para itens individuais, evitando a sobrecarga de operações em lote +**Eficiência da API**: As chamadas diretas da API minimizam as camadas de processamento +**Latência da Rede**: Cada comando faz uma chamada de API, minimizando as viagens de ida e volta na rede +**Uso de Memória**: Pegada de memória mínima para operações de item único + +## Estratégia de Teste + +**Testes Unitários**: Teste cada módulo de comando da CLI independentemente +**Testes de Integração**: Teste os comandos da CLI contra a API de Configuração em tempo real +**Testes de Tratamento de Erros**: Verifique o tratamento adequado de erros para entradas inválidas +**Compatibilidade da API**: Garanta que os comandos funcionem com as versões existentes da API de Configuração + +## Plano de Migração + +Nenhuma migração necessária - estes são novos comandos da CLI que complementam a funcionalidade existente: +O comando `tg-show-config` existente permanece inalterado +Novos comandos podem ser adicionados incrementalmente +Nenhuma alteração disruptiva nos fluxos de trabalho de configuração existentes + +## Empacotamento e Distribuição + +Estes comandos serão adicionados ao pacote `trustgraph-cli` existente: + +**Localização do Pacote**: `trustgraph-cli/` +**Arquivos do Módulo**: +`trustgraph-cli/trustgraph/cli/list_config_items.py` +`trustgraph-cli/trustgraph/cli/get_config_item.py` +`trustgraph-cli/trustgraph/cli/put_config_item.py` +`trustgraph-cli/trustgraph/cli/delete_config_item.py` + +**Pontos de Entrada**: Adicionados a `trustgraph-cli/pyproject.toml` na seção `[project.scripts]`: +```toml +tg-list-config-items = "trustgraph.cli.list_config_items:main" +tg-get-config-item = "trustgraph.cli.get_config_item:main" +tg-put-config-item = "trustgraph.cli.put_config_item:main" +tg-delete-config-item = "trustgraph.cli.delete_config_item:main" +``` + +## Tarefas de Implementação + +1. **Criar Módulos CLI**: Implementar os quatro módulos de comando CLI em `trustgraph-cli/trustgraph/cli/` +2. **Atualizar pyproject.toml**: Adicionar novos pontos de entrada de comando em `trustgraph-cli/pyproject.toml` +3. **Documentação**: Criar documentação CLI para cada comando em `docs/cli/` +4. **Testes**: Implementar cobertura de testes abrangente +5. **Integração**: Garantir que os comandos funcionem com a infraestrutura TrustGraph existente +6. **Construção do Pacote**: Verificar se os comandos são instalados corretamente com `pip install trustgraph-cli` + +## Exemplos de Uso + +#### Listar itens de configuração +```bash +# List prompt keys (text format) +tg-list-config-items --type prompt +template-1 +template-2 +system-prompt + +# List prompt keys (JSON format) +tg-list-config-items --type prompt --format json +["template-1", "template-2", "system-prompt"] +``` + +#### Obter item de configuração +```bash +# Get prompt value (text format) +tg-get-config-item --type prompt --key template-1 +You are a helpful assistant. Please respond to: {query} + +# Get prompt value (JSON format) +tg-get-config-item --type prompt --key template-1 --format json +"You are a helpful assistant. Please respond to: {query}" +``` + +#### Definir item de configuração +```bash +# Set from command line +tg-put-config-item --type prompt --key new-template --value "Custom prompt: {input}" + +# Set from file via pipe +cat ./prompt-template.txt | tg-put-config-item --type prompt --key complex-template --stdin + +# Set from file via redirect +tg-put-config-item --type prompt --key complex-template --stdin < ./prompt-template.txt + +# Set from command output +echo "Generated template: {query}" | tg-put-config-item --type prompt --key auto-template --stdin +``` + +#### Excluir item de configuração +```bash +tg-delete-config-item --type prompt --key old-template +``` + +## Perguntas Abertas + +Os comandos devem suportar operações em lote (múltiplas chaves) além de itens individuais? +Qual formato de saída deve ser usado para confirmações de sucesso? +Como os tipos de configuração devem ser documentados/descobertos pelos usuários? + +## Referências + +API de Configuração existente: `trustgraph/api/config.py` +Padrões de CLI: `trustgraph-cli/trustgraph/cli/show_config.py` +Tipos de dados: `trustgraph/api/types.py` \ No newline at end of file diff --git a/docs/tech-specs/more-config-cli.tr.md b/docs/tech-specs/more-config-cli.tr.md new file mode 100644 index 00000000..3b5ed6c6 --- /dev/null +++ b/docs/tech-specs/more-config-cli.tr.md @@ -0,0 +1,279 @@ +# Daha Fazla Yapılandırma CLI Teknik Özellikleri + +## Genel Bakış + +Bu özellik, TrustGraph için gelişmiş komut satırı yapılandırma yeteneklerini tanımlar ve kullanıcıların ayrı yapılandırma öğelerini ayrıntılı CLI komutları aracılığıyla yönetmelerini sağlar. Bu entegrasyon, dört birincil kullanım senaryosunu destekler: + +1. **Yapılandırma Öğelerini Listele**: Belirli bir türdeki yapılandırma anahtarlarını görüntüleyin +2. **Yapılandırma Öğesini Al**: Belirli yapılandırma değerlerini alın +3. **Yapılandırma Öğesini Ekle/Güncelle**: Bireysel yapılandırma öğelerini ayarlayın veya güncelleyin +4. **Yapılandırma Öğesini Sil**: Belirli yapılandırma öğelerini kaldırın + +## Hedefler + +**Ayrıntılı Kontrol**: Toplu işlemler yerine bireysel yapılandırma öğelerinin yönetimini sağlayın +**Türe Dayalı Listeleme**: Kullanıcıların yapılandırma öğelerini türe göre incelemesine izin verin +**Tek Öğeli İşlemler**: Bireysel yapılandırma öğelerinin alınması/eklenmesi/güncellenmesi/silinmesi için komutlar sağlayın +**API Entegrasyonu**: Tüm işlemler için mevcut Config API'sini kullanın +**Tutarlı CLI Modeli**: Kuruluş içi TrustGraph CLI kurallarına ve kalıplarına uyun +**Hata Yönetimi**: Geçersiz işlemler için açık hata mesajları sağlayın +**JSON Çıkışı**: Programlı kullanım için yapılandırılmış çıktı desteği sağlayın +**Belgeleme**: Kapsamlı yardım ve kullanım örnekleri ekleyin + +## Arka Plan + +TrustGraph şu anda Config API ve tüm yapılandırmayı görüntüleyen `tg-show-config` adlı tek bir CLI komutu aracılığıyla yapılandırma yönetimini sağlar. Bu, yapılandırmayı görüntülemek için işe yarasa da, ayrıntılı yönetim yetenekleri eksiktir. + +Mevcut sınırlamalar şunlardır: +CLI'den yapılandırma öğelerini türe göre listelemenin bir yolu yok +Belirli yapılandırma değerlerini almak için bir CLI komutu yok +Bireysel yapılandırma öğelerini ayarlamak için bir CLI komutu yok +Belirli yapılandırma öğelerini silmek için bir CLI komutu yok + +Bu özellik, ayrıntılı yapılandırma yönetimi sağlayan dört yeni CLI komutu ekleyerek bu boşlukları giderir. Bireysel Config API işlemlerini CLI komutları aracılığıyla açığa çıkararak TrustGraph şunları yapabilir: +Betik tabanlı yapılandırma yönetimini etkinleştirin +Yapılandırma yapısını türe göre incelemeye izin verin +Hedefli yapılandırma güncellemelerini destekleyin +İnce taneli yapılandırma kontrolü sağlayın + +## Teknik Tasarım + +### Mimari + +Gelişmiş CLI yapılandırması, aşağıdaki teknik bileşenleri gerektirir: + +1. **tg-list-config-items** + Belirtilen bir tür için yapılandırma anahtarlarını listeler + Config.list(type) API yöntemini çağırır + Yapılandırma anahtarlarının listesini çıktı olarak verir + + Modül: `trustgraph.cli.list_config_items` + +2. **tg-get-config-item** + Belirli yapılandırma öğesi(ni) alır + Config.get(keys) API yöntemini çağırır + Yapılandırma değerlerini JSON formatında çıktı olarak verir + + Modül: `trustgraph.cli.get_config_item` + +3. **tg-put-config-item** + Bir yapılandırma öğesini ayarlar veya günceller + Config.put(values) API yöntemini çağırır + Tür, anahtar ve değer parametrelerini kabul eder + + Modül: `trustgraph.cli.put_config_item` + +4. **tg-delete-config-item** + Bir yapılandırma öğesini siler + Config.delete(keys) API yöntemini çağırır + Tür ve anahtar parametrelerini kabul eder + + Modül: `trustgraph.cli.delete_config_item` + +### Veri Modelleri + +#### ConfigKey ve ConfigValue + +Bu komutlar, `trustgraph.api.types`'dan mevcut veri yapılarını kullanır: + +```python +@dataclasses.dataclass +class ConfigKey: + type : str + key : str + +@dataclasses.dataclass +class ConfigValue: + type : str + key : str + value : str +``` + +Bu yaklaşım şunları sağlar: +CLI ve API'ler arasında tutarlı veri işleme +Tür güvenli yapılandırma işlemleri +Yapılandırılmış girdi/çıktı formatları +Mevcut Config API ile entegrasyon + +### CLI Komut Özellikleri + +#### tg-list-config-items +```bash +tg-list-config-items --type [--format text|json] [--api-url ] +``` +**Amaç**: Belirli bir tür için tüm yapılandırma anahtarlarını listele. +**API Çağrısı**: `Config.list(type)` +**Çıktı**: + `text` (varsayılan): Yeni satırlarla ayrılmış yapılandırma anahtarları. + `json`: Yapılandırma anahtarlarının JSON dizisi. + +#### tg-get-config-item +```bash +tg-get-config-item --type --key [--format text|json] [--api-url ] +``` +**Amaç**: Belirli bir yapılandırma öğesini almak. +**API Çağrısı**: `Config.get([ConfigKey(type, key)])` +**Çıktı**: + `text` (varsayılan): Ham metin değeri. + `json`: JSON olarak kodlanmış metin değeri. + +#### tg-put-config-item +```bash +tg-put-config-item --type --key --value [--api-url ] +tg-put-config-item --type --key --stdin [--api-url ] +``` +**Amaç**: Yapılandırma öğesini ayarlayın veya güncelleyin. +**API Çağrısı**: `Config.put([ConfigValue(type, key, value)])` +**Giriş Seçenekleri**: + `--value`: Değer, doğrudan komut satırından sağlanır. + `--stdin`: Değer, standart girişten okunur. +**Çıktı**: Başarı onayı. + +#### tg-delete-config-item +```bash +tg-delete-config-item --type --key [--api-url ] +``` +**Amaç**: Yapılandırma öğesini silme +**API Çağrısı**: `Config.delete([ConfigKey(type, key)])` +**Çıktı**: Başarı onayı + +### Uygulama Detayları + +Tüm komutlar, mevcut TrustGraph CLI kalıbını izler: +Komut satırı argüman ayrıştırması için `argparse` kullanın +Arka uç iletişimi için `trustgraph.api.Api`'i içe aktarın ve kullanın +Mevcut CLI komutlarındaki aynı hata işleme kalıplarını izleyin +API uç noktası yapılandırması için standart `--api-url` parametresini destekleyin +Açıklayıcı yardım metni ve kullanım örnekleri sağlayın + +#### Çıktı Biçimi İşleme + +**Metin Biçimi (Varsayılan)**: +`tg-list-config-items`: Her satırda bir anahtar, düz metin +`tg-get-config-item`: Ham dize değeri, tırnak veya kodlama yok + +**JSON Biçimi**: +`tg-list-config-items`: `["key1", "key2", "key3"]` dize dizisi +`tg-get-config-item`: JSON ile kodlanmış dize değeri `"actual string value"` + +#### Giriş İşleme + +**tg-put-config-item**, iki karşılıklı olarak münhasır giriş yöntemini destekler: +`--value `: Doğrudan komut satırı dize değeri +`--stdin`: Tüm girdiyi yapılandırma değeri olarak standart girdiden okuyun +stdin içeriği ham metin olarak okunur (satır başları, boşluklar vb. korunur) +Dosyalardan, komutlardan veya etkileşimli girdiden boru hattı desteği + +## Güvenlik Hususları + +**Giriş Doğrulama**: Tüm komut satırı parametreleri, API çağrıları yapılmadan önce doğrulanmalıdır. +**API Kimlik Doğrulama**: Komutlar, mevcut API kimlik doğrulama mekanizmalarını kullanır. +**Yapılandırma Erişimi**: Komutlar, mevcut yapılandırma erişim kontrollerine saygı gösterir. +**Hata Bilgisi**: Hata mesajları, hassas yapılandırma ayrıntılarını ifşa etmemelidir. + +## Performans Hususları + +**Tek Öğeli İşlemler**: Komutlar, toplu işlem yükünü önlemek için tek tek öğeler için tasarlanmıştır. +**API Verimliliği**: Doğrudan API çağrıları, işleme katmanlarını en aza indirir. +**Ağ Gecikmesi**: Her komut, tek bir API çağrısı yapar ve bu da ağ iletişimini en aza indirir. +**Bellek Kullanımı**: Tek öğeli işlemler için minimum bellek kullanımı. + +## Test Stratejisi + +**Birim Testleri**: Her CLI komut modülünü bağımsız olarak test edin. +**Entegrasyon Testleri**: CLI komutlarını canlı Config API'ye karşı test edin. +**Hata Yönetimi Testleri**: Geçersiz girişler için uygun hata yönetimini doğrulayın. +**API Uyumluluğu**: Komutların mevcut Config API sürümleriyle çalıştığından emin olun. + +## Geçiş Planı + +Geçiş gerekli değil - bunlar, mevcut işlevselliği tamamlayan yeni CLI komutlarıdır: +Mevcut `tg-show-config` komutu değişmeden kalır. +Yeni komutlar kademeli olarak eklenebilir. +Mevcut yapılandırma iş akışlarında herhangi bir değişiklik yapılmaz. + +## Paketleme ve Dağıtım + +Bu komutlar, mevcut `trustgraph-cli` paketine eklenecektir: + +**Paket Konumu**: `trustgraph-cli/` +**Modül Dosyaları**: +`trustgraph-cli/trustgraph/cli/list_config_items.py` +`trustgraph-cli/trustgraph/cli/get_config_item.py` +`trustgraph-cli/trustgraph/cli/put_config_item.py` +`trustgraph-cli/trustgraph/cli/delete_config_item.py` + +**Giriş Noktaları**: `trustgraph-cli/pyproject.toml`'a `[project.scripts]` bölümüne eklendi: +```toml +tg-list-config-items = "trustgraph.cli.list_config_items:main" +tg-get-config-item = "trustgraph.cli.get_config_item:main" +tg-put-config-item = "trustgraph.cli.put_config_item:main" +tg-delete-config-item = "trustgraph.cli.delete_config_item:main" +``` + +## Uygulama Görevleri + +1. **CLI Modüllerini Oluşturma**: `trustgraph-cli/trustgraph/cli/` içinde dört CLI komut modülünü uygulayın. +2. **pyproject.toml'yi Güncelleme**: `trustgraph-cli/pyproject.toml`'a yeni komut giriş noktaları ekleyin. +3. **Belgeleme**: `docs/cli/` içindeki her komut için CLI belgelerini oluşturun. +4. **Test**: Kapsamlı test kapsamı uygulayın. +5. **Entegrasyon**: Komutların mevcut TrustGraph altyapısıyla çalıştığından emin olun. +6. **Paket Oluşturma**: Komutların `pip install trustgraph-cli` ile düzgün bir şekilde yüklendiğini doğrulayın. + +## Kullanım Örnekleri + +#### Yapılandırma öğelerini listeleme +```bash +# List prompt keys (text format) +tg-list-config-items --type prompt +template-1 +template-2 +system-prompt + +# List prompt keys (JSON format) +tg-list-config-items --type prompt --format json +["template-1", "template-2", "system-prompt"] +``` + +#### Yapılandırma öğesini al +```bash +# Get prompt value (text format) +tg-get-config-item --type prompt --key template-1 +You are a helpful assistant. Please respond to: {query} + +# Get prompt value (JSON format) +tg-get-config-item --type prompt --key template-1 --format json +"You are a helpful assistant. Please respond to: {query}" +``` + +#### Yapılandırma öğesini ayarlayın +```bash +# Set from command line +tg-put-config-item --type prompt --key new-template --value "Custom prompt: {input}" + +# Set from file via pipe +cat ./prompt-template.txt | tg-put-config-item --type prompt --key complex-template --stdin + +# Set from file via redirect +tg-put-config-item --type prompt --key complex-template --stdin < ./prompt-template.txt + +# Set from command output +echo "Generated template: {query}" | tg-put-config-item --type prompt --key auto-template --stdin +``` + +#### Yapılandırma öğesini sil +```bash +tg-delete-config-item --type prompt --key old-template +``` + +## Açık Sorular + +Komutlar, tek öğelerin yanı sıra toplu işlemleri (çoklu anahtarlar) desteklemeli mi? +Başarı onayları için hangi çıktı formatı kullanılmalıdır? +Konfigürasyon türleri kullanıcılar tarafından nasıl belgelenmeli/keşfedilmelidir? + +## Referanslar + +Mevcut Konfigürasyon API'si: `trustgraph/api/config.py` +CLI kalıpları: `trustgraph-cli/trustgraph/cli/show_config.py` +Veri türleri: `trustgraph/api/types.py` \ No newline at end of file diff --git a/docs/tech-specs/multi-tenant-support.ar.md b/docs/tech-specs/multi-tenant-support.ar.md new file mode 100644 index 00000000..cd5fad18 --- /dev/null +++ b/docs/tech-specs/multi-tenant-support.ar.md @@ -0,0 +1,772 @@ +# المواصفات الفنية: دعم البيئات متعددة المستأجرين + +## نظرة عامة + +تمكين عمليات النشر متعددة المستأجرين عن طريق إصلاح عدم تطابق أسماء المعلمات التي تمنع تخصيص قائمة الانتظار وإضافة معلمات مساحة مفاتيح Cassandra. + +## سياق البنية + +### حل قائمة الانتظار القائم على التدفق + +يستخدم نظام TrustGraph بنية **قائمة انتظار قائمة على التدفق** لحل ديناميكي لقوائم الانتظار، والتي تدعم بشكل طبيعي البيئات متعددة المستأجرين: + +يتم تخزين **تعريفات التدفق** في Cassandra وتحدد أسماء قوائم الانتظار عبر تعريفات الواجهة. +**تستخدم أسماء قوائم الانتظار قوالب** مع متغيرات `{id}` يتم استبدالها بمعرفات مثيلات التدفق. +**تقوم الخدمات بحل قوائم الانتظار ديناميكيًا** عن طريق البحث عن تكوينات التدفق في وقت الطلب. +**يمكن لكل مستأجر أن يكون لديه تدفقات فريدة** بأسماء قوائم انتظار مختلفة، مما يوفر عزلًا. + +مثال لتعريف واجهة التدفق: +```json +{ + "interfaces": { + "triples-store": "persistent://tg/flow/triples-store:{id}", + "graph-embeddings-store": "persistent://tg/flow/graph-embeddings-store:{id}" + } +} +``` + +عندما يبدأ المستأجر أ سير العمل `tenant-a-prod` ويبدأ المستأجر ب سير العمل `tenant-b-prod`، فإنهم يحصلون تلقائيًا على قوائم انتظار معزولة: +`persistent://tg/flow/triples-store:tenant-a-prod` +`persistent://tg/flow/triples-store:tenant-b-prod` + +**الخدمات المصممة بشكل صحيح لدعم تعدد المستأجرين:** +✅ **إدارة المعرفة (الأساسيات)** - تحل ديناميكيًا قوائم الانتظار من تكوين سير العمل الذي يتم تمريره في الطلبات. + +**الخدمات التي تحتاج إلى إصلاحات:** +🔴 **خدمة التكوين** - عدم تطابق اسم المعلمة يمنع تخصيص قائمة الانتظار. +🔴 **خدمة أمين المكتبة** - مواضيع إدارة التخزين المبرمجة بشكل ثابت (موضحة أدناه). +🔴 **جميع الخدمات** - لا يمكن تخصيص مساحة مفتاح Cassandra. + +## بيان المشكلة + +### المشكلة رقم 1: عدم تطابق اسم المعلمة في AsyncProcessor +**يعرف سطر الأوامر:** `--config-queue` (تسمية غير واضحة) +**يقوم Argparse بتحويلها إلى:** `config_queue` (في قاموس المعلمات) +**يبحث الكود عن:** `config_push_queue` +**النتيجة:** يتم تجاهل المعلمة، وتعود إلى القيمة الافتراضية `persistent://tg/config/config`. +**التأثير:** يؤثر على أكثر من 32 خدمة ترث من AsyncProcessor. +**يمنع:** لا يمكن لنشر تعدد المستأجرين استخدام قوائم انتظار تكوين خاصة بالمستأجر. +**الحل:** إعادة تسمية معلمة سطر الأوامر إلى `--config-push-queue` من أجل الوضوح (تغيير كاسر مقبول نظرًا لأن الميزة معطلة حاليًا). + +### المشكلة رقم 2: عدم تطابق اسم المعلمة في خدمة التكوين +**يعرف سطر الأوامر:** `--push-queue` (تسمية غامضة) +**يقوم Argparse بتحويلها إلى:** `push_queue` (في قاموس المعلمات) +**يبحث الكود عن:** `config_push_queue` +**النتيجة:** يتم تجاهل المعلمة. +**التأثير:** لا يمكن لخدمة التكوين استخدام قائمة انتظار دفع مخصصة. +**الحل:** إعادة تسمية معلمة سطر الأوامر إلى `--config-push-queue` من أجل الاتساق والوضوح (تغيير كاسر مقبول). + +### المشكلة رقم 3: مساحة مفتاح Cassandra مبرمجة بشكل ثابت +**الحالي:** مساحة المفتاح مبرمجة بشكل ثابت كـ `"config"`، `"knowledge"`، `"librarian"` في خدمات مختلفة. +**النتيجة:** لا يمكن تخصيص مساحة المفتاح لنشر تعدد المستأجرين. +**التأثير:** خدمات التكوين والأساسيات وأمين المكتبة. +**يمنع:** لا يمكن لعدة مستأجرين استخدام مساحات مفاتيح Cassandra منفصلة. + +### المشكلة رقم 4: بنية إدارة المجموعات ✅ مكتمل +**السابق:** تم تخزين المجموعات في مساحة مفاتيح Cassandra الخاصة بأمين المكتبة عبر جدول مجموعات منفصل. +**السابق:** استخدم أمين المكتبة 4 مواضيع إدارة تخزين مبرمجة بشكل ثابت لتنسيق إنشاء/حذف المجموعة: + `vector_storage_management_topic` + `object_storage_management_topic` + `triples_storage_management_topic` + `storage_management_response_topic` +**المشاكل (تم حلها):** + لا يمكن تخصيص المواضيع المبرمجة بشكل ثابت لنشر تعدد المستأجرين. + تنسيق غير متزامن معقد بين أمين المكتبة و 4+ خدمات تخزين. + جدول منفصل وبنية تحتية لإدارة. + قوائم انتظار طلب/استجابة غير دائمة للعمليات الهامة. +**الحل المنفذ:** تم نقل المجموعات إلى تخزين خدمة التكوين، واستخدام دفع التكوين للتوزيع. +**الحالة:** تم نقل جميع خلفيات التخزين إلى النمط `CollectionConfigHandler`. + +## الحل + +تعالج هذه المواصفات المشكلات رقم 1 و 2 و 3 و 4. + +### الجزء الأول: إصلاح عدم تطابق اسم المعلمة + +#### التغيير 1: فئة AsyncProcessor الأساسية - إعادة تسمية معلمة سطر الأوامر +**الملف:** `trustgraph-base/trustgraph/base/async_processor.py` +**السطر:** 260-264 + +**الحالي:** +```python +parser.add_argument( + '--config-queue', + default=default_config_queue, + help=f'Config push queue {default_config_queue}', +) +``` + +**ثابت:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_queue, + help=f'Config push queue (default: {default_config_queue})', +) +``` + +**السبب:** +تسمية أوضح وأكثر تفصيلاً. +تتطابق مع اسم المتغير الداخلي `config_push_queue`. +التغيير قد يكون مؤثراً، ولكن هذا مقبول لأن الميزة غير فعالة حاليًا. +لا حاجة لتغيير أي كود في `params.get()` - فهو يبحث بالفعل عن الاسم الصحيح. + +#### التغيير الثاني: خدمة التكوين - إعادة تسمية معلمة سطر الأوامر +**الملف:** `trustgraph-flow/trustgraph/config/service/service.py` +**السطر:** 276-279 + +**الحالي:** +```python +parser.add_argument( + '--push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**ثابت:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**السبب:** +تسمية أوضح - "config-push-queue" أكثر وضوحًا من مجرد "push-queue". +يتطابق مع اسم المتغير الداخلي `config_push_queue`. +متسق مع معلمة `--config-push-queue` الخاصة بـ AsyncProcessor. +التغيير غير المتوافق مقبول نظرًا لأن الميزة غير وظيفية حاليًا. +لا حاجة لتغيير التعليمات البرمجية في params.get() - فهو يبحث بالفعل عن الاسم الصحيح. + +### الجزء الثاني: إضافة معلمات مساحة مفاتيح Cassandra + +#### التغيير الثالث: إضافة معلمة مساحة المفاتيح إلى وحدة cassandra_config +**الملف:** `trustgraph-base/trustgraph/base/cassandra_config.py` + +**إضافة وسيط سطر الأوامر** (في دالة `add_cassandra_args()`): +```python +parser.add_argument( + '--cassandra-keyspace', + default=None, + help='Cassandra keyspace (default: service-specific)' +) +``` + +**إضافة دعم لمتغيرات البيئة** (في الدالة `resolve_cassandra_config()`): +```python +keyspace = params.get( + "cassandra_keyspace", + os.environ.get("CASSANDRA_KEYSPACE") +) +``` + +**تحديث قيمة الإرجاع** لـ `resolve_cassandra_config()`: +حاليًا، تُرجع: `(hosts, username, password)` +التغيير إلى إرجاع: `(hosts, username, password, keyspace)` + +**السبب:** +يتوافق مع نمط تكوين Cassandra الحالي +متاح لجميع الخدمات عبر `add_cassandra_args()` +يدعم كل من تكوين سطر الأوامر ومتغيرات البيئة + +#### التغيير الرابع: خدمة التكوين - استخدام مفاتيح مساحة المفاتيح المعلمة +**الملف:** `trustgraph-flow/trustgraph/config/service/service.py` + +**السطر 30** - إزالة اسم مساحة المفاتيح الثابت: +```python +# DELETE THIS LINE: +keyspace = "config" +``` + +**السطور من 69 إلى 73** - تحديث آلية حل مشاكل إعدادات كاساندرا: + +**الحالي:** +```python +cassandra_host, cassandra_username, cassandra_password = \ + resolve_cassandra_config(params) +``` + +**ثابت:** +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="config") +``` + +**السبب:** +يحافظ على التوافق مع الإصدارات السابقة باستخدام "config" كإعداد افتراضي. +يسمح بالتجاوز عبر `--cassandra-keyspace` أو `CASSANDRA_KEYSPACE`. + +#### التغيير 5: الخدمات الأساسية/خدمة المعرفة - استخدام مفاتيح مساحة معلمات. +**الملف:** `trustgraph-flow/trustgraph/cores/service.py` + +**السطر 37** - إزالة مفتاح مساحة مُبرمج بشكل ثابت: +```python +# DELETE THIS LINE: +keyspace = "knowledge" +``` + +**تحديث آلية حل إعدادات كاساندرا** (في نفس الموقع مثل خدمة الإعدادات): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="knowledge") +``` + +#### التغيير 6: خدمة أمين المكتبة - استخدام مفاتيح مساحة معلمات. +**الملف:** `trustgraph-flow/trustgraph/librarian/service.py` + +**السطر 51** - إزالة اسم مساحة المفاتيح المبرمج بشكل ثابت: +```python +# DELETE THIS LINE: +keyspace = "librarian" +``` + +**تحديث آلية حل إعدادات Cassandra** (في نفس الموقع مثل خدمة الإعدادات): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="librarian") +``` + +### الجزء الثالث: ترحيل إدارة المجموعات إلى خدمة التكوين + +#### نظرة عامة +ترحيل المجموعات من مساحة مفاتيح Cassandra librarian إلى تخزين خدمة التكوين. هذا يلغي مواضيع إدارة التخزين المضمنة ويبسط البنية باستخدام آلية دفع التكوين الحالية للتوزيع. + +#### البنية الحالية +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Cassandra Collections Table (librarian keyspace) + ↓ + Broadcast to 4 Storage Management Topics (hardcoded) + ↓ + Wait for 4+ Storage Service Responses + ↓ + Response to Gateway +``` + +#### العمارة الجديدة +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Config Service API (put/delete/getvalues) + ↓ + Cassandra Config Table (class='collections', key='user:collection') + ↓ + Config Push (to all subscribers on config-push-queue) + ↓ + All Storage Services receive config update independently +``` + +#### التغيير 7: مدير المجموعة - استخدام واجهة برمجة تطبيقات خدمة التكوين +**الملف:** `trustgraph-flow/trustgraph/librarian/collection_manager.py` + +**إزالة:** +استخدام `LibraryTableStore` (الأسطر 33، 40-41) +تهيئة منتجي إدارة التخزين (الأسطر 86-140) +طريقة `on_storage_response` (الأسطر 400-430) +تتبع `pending_deletions` (الأسطر 57، 90-96، والاستخدام في جميع أنحاء البرنامج) + +**إضافة:** +عميل خدمة التكوين لإجراء مكالمات واجهة برمجة التطبيقات (نمط الطلب/الاستجابة) + +**إعداد عميل التكوين:** +```python +# In __init__, add config request/response producers/consumers +from trustgraph.schema.services.config import ConfigRequest, ConfigResponse + +# Producer for config requests +self.config_request_producer = Producer( + client=pulsar_client, + topic=config_request_queue, + schema=ConfigRequest, +) + +# Consumer for config responses (with correlation ID) +self.config_response_consumer = Consumer( + taskgroup=taskgroup, + client=pulsar_client, + flow=None, + topic=config_response_queue, + subscriber=f"{id}-config", + schema=ConfigResponse, + handler=self.on_config_response, +) + +# Tracking for pending config requests +self.pending_config_requests = {} # request_id -> asyncio.Event +``` + +**تعديل `list_collections` (الأسطر من 145 إلى 180):** +```python +async def list_collections(self, user, tag_filter=None, limit=None): + """List collections from config service""" + # Send getvalues request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='getvalues', + type='collections', + ) + + # Send request and wait for response + response = await self.send_config_request(request) + + # Parse collections from response + collections = [] + for key, value_json in response.values.items(): + if ":" in key: + coll_user, collection = key.split(":", 1) + if coll_user == user: + metadata = json.loads(value_json) + collections.append(CollectionMetadata(**metadata)) + + # Apply tag filtering in-memory (as before) + if tag_filter: + collections = [c for c in collections if any(tag in c.tags for tag in tag_filter)] + + # Apply limit + if limit: + collections = collections[:limit] + + return collections + +async def send_config_request(self, request): + """Send config request and wait for response""" + event = asyncio.Event() + self.pending_config_requests[request.id] = event + + await self.config_request_producer.send(request) + await event.wait() + + return self.pending_config_requests.pop(request.id + "_response") + +async def on_config_response(self, message, consumer, flow): + """Handle config response""" + response = message.value() + if response.id in self.pending_config_requests: + self.pending_config_requests[response.id + "_response"] = response + self.pending_config_requests[response.id].set() +``` + +**تعديل `update_collection` (الأسطر من 182 إلى 312):** +```python +async def update_collection(self, user, collection, name, description, tags): + """Update collection via config service""" + # Create metadata + metadata = CollectionMetadata( + user=user, + collection=collection, + name=name, + description=description, + tags=tags, + ) + + # Send put request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='put', + type='collections', + key=f'{user}:{collection}', + value=json.dumps(metadata.to_dict()), + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config update failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and create collections +``` + +**تعديل `delete_collection` (الأسطر من 314 إلى 398):** +```python +async def delete_collection(self, user, collection): + """Delete collection via config service""" + # Send delete request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='delete', + type='collections', + key=f'{user}:{collection}', + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config delete failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and delete collections +``` + +**تنسيق بيانات التعريف للمجموعة:** +يتم تخزينها في جدول التكوين كـ: `class='collections', key='user:collection'` +القيمة هي بيانات تعريف المجموعة (CollectionMetadata) مُسلسلة بصيغة JSON (بدون حقول الطابع الزمني) +الحقول: `user`، `collection`، `name`، `description`، `tags` +مثال: `class='collections', key='alice:my-docs', value='{"user":"alice","collection":"my-docs","name":"My Documents","description":"...","tags":["work"]}'` + +#### التغيير 8: خدمة أمين المكتبة - إزالة بنية إدارة التخزين +**الملف:** `trustgraph-flow/trustgraph/librarian/service.py` + +**إزالة:** +منتجي إدارة التخزين (الأسطر 173-190): + `vector_storage_management_producer` + `object_storage_management_producer` + `triples_storage_management_producer` +مستهلك الاستجابة للتخزين (الأسطر 192-201) +معالج `on_storage_response` (الأسطر 467-473) + +**تعديل:** +تهيئة CollectionManager (الأسطر 215-224) - إزالة معلمات منتج التخزين + +**ملاحظة:** تظل واجهة برمجة التطبيقات الخارجية للمجموعة دون تغيير: +`list-collections` +`update-collection` +`delete-collection` + +#### التغيير 9: إزالة جدول المجموعات من LibraryTableStore +**الملف:** `trustgraph-flow/trustgraph/tables/library.py` + +**حذف:** +عبارة CREATE لجدول المجموعات (الأسطر 114-127) +عبارات Collections المُعدة (الأسطر 205-240) +جميع طرق المجموعة (الأسطر 578-717): + `ensure_collection_exists` + `list_collections` + `update_collection` + `delete_collection` + `get_collection` + `create_collection` + +**السبب:** +يتم الآن تخزين المجموعات في جدول التكوين +التغيير غير المتوافق مقبول - لا توجد حاجة لنقل البيانات +يبسط خدمة أمين المكتبة بشكل كبير + +#### التغيير 10: خدمات التخزين - إدارة المجموعة المستندة إلى التكوين ✅ تم + +**الحالة:** تم ترحيل جميع خدمات التخزين الـ 11 لاستخدام `CollectionConfigHandler`. + +**الخدمات المتأثرة (11 خدمة إجمالاً):** +تضمينات المستندات: milvus, pinecone, qdrant +تضمينات الرسم البياني: milvus, pinecone, qdrant +تخزين الكائنات: cassandra +تخزين الثلاثيات: cassandra, falkordb, memgraph, neo4j + +**الملفات:** +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +`trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +`trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` + +**نمط التنفيذ (جميع الخدمات):** + +1. **سجل معالج التكوين في `__init__`:** +```python +# Add after AsyncProcessor initialization +self.register_config_handler(self.on_collection_config) +self.known_collections = set() # Track (user, collection) tuples +``` + +2. **تنفيذ معالج التهيئة:** +```python +async def on_collection_config(self, config, version): + """Handle collection configuration updates""" + logger.info(f"Collection config version: {version}") + + if "collections" not in config: + return + + # Parse collections from config + # Key format: "user:collection" in config["collections"] + config_collections = set() + for key in config["collections"].keys(): + if ":" in key: + user, collection = key.split(":", 1) + config_collections.add((user, collection)) + + # Determine changes + to_create = config_collections - self.known_collections + to_delete = self.known_collections - config_collections + + # Create new collections (idempotent) + for user, collection in to_create: + try: + await self.create_collection_internal(user, collection) + self.known_collections.add((user, collection)) + logger.info(f"Created collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to create {user}/{collection}: {e}") + + # Delete removed collections (idempotent) + for user, collection in to_delete: + try: + await self.delete_collection_internal(user, collection) + self.known_collections.discard((user, collection)) + logger.info(f"Deleted collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to delete {user}/{collection}: {e}") +``` + +3. **تهيئة المجموعات المعروفة عند بدء التشغيل:** +```python +async def start(self): + """Start the processor""" + await super().start() + await self.sync_known_collections() + +async def sync_known_collections(self): + """Query backend to populate known_collections set""" + # Backend-specific implementation: + # - Milvus/Pinecone/Qdrant: List collections/indexes matching naming pattern + # - Cassandra: Query keyspaces or collection metadata + # - Neo4j/Memgraph/FalkorDB: Query CollectionMetadata nodes + pass +``` + +4. **إعادة هيكلة طرق المعالجة الحالية:** +```python +# Rename and remove response sending: +# handle_create_collection → create_collection_internal +# handle_delete_collection → delete_collection_internal + +async def create_collection_internal(self, user, collection): + """Create collection (idempotent)""" + # Same logic as current handle_create_collection + # But remove response producer calls + # Handle "already exists" gracefully + pass + +async def delete_collection_internal(self, user, collection): + """Delete collection (idempotent)""" + # Same logic as current handle_delete_collection + # But remove response producer calls + # Handle "not found" gracefully + pass +``` + +5. **إزالة البنية التحتية لإدارة التخزين:** + إزالة الإعداد والتشغيل `self.storage_request_consumer`. + إزالة الإعداد `self.storage_response_producer`. + إزالة طريقة الموزع `on_storage_management`. + إزالة المقاييس لإدارة التخزين. + إزالة الاستيرادات: `StorageManagementRequest`، `StorageManagementResponse`. + +**اعتبارات خاصة بالخلفية:** + +**مخازن المتجهات (Milvus, Pinecone, Qdrant):** تتبع `(user, collection)` المنطقية في `known_collections`، ولكن قد يتم إنشاء مجموعات خلفية متعددة لكل بُعد. استمر في نمط الإنشاء الكسول. يجب أن تزيل عمليات الحذف جميع المتغيرات الأبعاد. + +**Cassandra Objects:** المجموعات هي خصائص الصفوف، وليست هياكل. تتبع معلومات على مستوى مساحة المفاتيح. + +**مخازن الرسوم البيانية (Neo4j, Memgraph, FalkorDB):** استعلام عن عقد `CollectionMetadata` عند بدء التشغيل. إنشاء/حذف عقد البيانات الوصفية عند المزامنة. + +**Cassandra Triples:** استخدم واجهة برمجة التطبيقات `KnowledgeGraph` لعمليات المجموعة. + +**نقاط التصميم الرئيسية:** + +**الاتساق النهائي:** لا يوجد آلية طلب/استجابة، يتم بث دفع التكوين. +**التكرار:** يجب أن تكون جميع عمليات الإنشاء/الحذف آمنة لإعادة المحاولة. +**معالجة الأخطاء:** سجل الأخطاء ولكن لا تقاطع تحديثات التكوين. +**التعافي الذاتي:** ستعيد العمليات الفاشلة المحاولة في دفع التكوين التالي. +**تنسيق مفتاح المجموعة:** `"user:collection"` في `config["collections"]`. + +#### التغيير 11: تحديث مخطط المجموعة - إزالة الطوابع الزمنية +**الملف:** `trustgraph-base/trustgraph/schema/services/collection.py` + +**تعديل CollectionMetadata (الأسطر 13-21):** +إزالة الحقول `created_at` و `updated_at`: +```python +class CollectionMetadata(Record): + user = String() + collection = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() +``` + +**تعديل طلب إدارة المجموعة (الأسطر من 25 إلى 47):** +إزالة حقول الطابع الزمني: +```python +class CollectionManagementRequest(Record): + operation = String() + user = String() + collection = String() + timestamp = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() + tag_filter = Array(String()) + limit = Integer() +``` + +**السبب:** +لا تضيف الطوابع الزمنية قيمة للمجموعات. +خدمة التكوين تحتفظ بآلية تتبع الإصدار الخاصة بها. +تبسط المخطط وتقلل التخزين. + +#### فوائد ترحيل خدمة التكوين + +1. ✅ **تقضي على مواضيع إدارة التخزين المضمنة بشكل ثابت** - تحل مشكلة المستخدمين المتعددين. +2. ✅ **تنسيق أبسط** - لا يوجد انتظار غير متزامن معقد لـ 4+ استجابات للتخزين. +3. ✅ **الاتساق النهائي** - تقوم خدمات التخزين بالتحديث بشكل مستقل عبر دفع التكوين. +4. ✅ **موثوقية أفضل** - دفع تكوين دائم مقابل طلب/استجابة غير دائمة. +5. ✅ **نموذج تكوين موحد** - يتم التعامل مع المجموعات على أنها تكوين. +6. ✅ **تقلل التعقيد** - تزيل حوالي 300 سطر من كود التنسيق. +7. ✅ **جاهزة لدعم المستخدمين المتعددين** - تدعم التكوين بالفعل عزل المستخدمين عبر مساحة المفاتيح. +8. ✅ **تتبع الإصدار** - توفر آلية إصدار خدمة التكوين مسار تدقيق. + +## ملاحظات التنفيذ + +### التوافق مع الإصدارات السابقة + +**تغييرات في المعلمات:** +إعادة تسمية معلمات سطر الأوامر هي تغييرات جذرية ولكنها مقبولة (الميزة غير وظيفية حاليًا). +تعمل الخدمات بدون معلمات (تستخدم القيم الافتراضية). +تم الحفاظ على مساحات المفاتيح الافتراضية: "config" و "knowledge" و "librarian". +قائمة الانتظار الافتراضية: `persistent://tg/config/config` + +**إدارة المجموعات:** +**تغيير جذري:** تمت إزالة جدول المجموعات من مساحة مفاتيح librarian. +**لا يتم توفير ترحيل للبيانات** - مقبول لهذه المرحلة. +واجهة برمجة تطبيقات المجموعة الخارجية لم تتغير (عمليات القائمة/التحديث/الحذف). +تم تبسيط تنسيق بيانات تعريف المجموعة (تمت إزالة الطوابع الزمنية). + +### متطلبات الاختبار + +**اختبار المعلمات:** +1. تحقق من أن المعلمة `--config-push-queue` تعمل على خدمة graph-embeddings. +2. تحقق من أن المعلمة `--config-push-queue` تعمل على خدمة text-completion. +3. تحقق من أن المعلمة `--config-push-queue` تعمل على خدمة التكوين. +4. تحقق من أن المعلمة `--cassandra-keyspace` تعمل لخدمة التكوين. +5. تحقق من أن المعلمة `--cassandra-keyspace` تعمل لخدمة cores. +6. تحقق من أن المعلمة `--cassandra-keyspace` تعمل لخدمة librarian. +7. تحقق من أن الخدمات تعمل بدون معلمات (تستخدم القيم الافتراضية). +8. تحقق من نشر متعدد المستخدمين باستخدام أسماء قوائم الانتظار ومساحات المفاتيح المخصصة. + +**اختبار إدارة المجموعات:** +9. تحقق من العملية `list-collections` عبر خدمة التكوين. +10. تحقق من أن `update-collection` تقوم بإنشاء/تحديث في جدول التكوين. +11. تحقق من أن `delete-collection` تقوم بإزالة من جدول التكوين. +12. تحقق من أن دفع التكوين يتم تشغيله عند تحديث المجموعات. +13. تحقق من أن تصفية العلامات تعمل مع التخزين المستند إلى التكوين. +14. تحقق من أن عمليات المجموعة تعمل بدون حقول الطوابع الزمنية. + +### مثال النشر متعدد المستخدمين +```bash +# Tenant: tg-dev +graph-embeddings \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config + +config-service \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config \ + --cassandra-keyspace tg_dev_config +``` + +## تحليل الأثر + +### الخدمات المتأثرة بالتغيير 1-2 (إعادة تسمية معلمة سطر الأوامر) +جميع الخدمات التي ترث من AsyncProcessor أو FlowProcessor: +config-service +cores-service +librarian-service +graph-embeddings +document-embeddings +text-completion-* (جميع المزودين) +extract-* (جميع أدوات الاستخراج) +query-* (جميع خدمات الاستعلام) +retrieval-* (جميع خدمات استرجاع المعلومات) +storage-* (جميع خدمات التخزين) +وأكثر من 20 خدمة أخرى + +### الخدمات المتأثرة بالتغييرات 3-6 (مساحة مفاتيح Cassandra) +config-service +cores-service +librarian-service + +### الخدمات المتأثرة بالتغييرات 7-11 (إدارة المجموعات) + +**التغييرات الفورية:** +librarian-service (collection_manager.py, service.py) +tables/library.py (إزالة جدول المجموعات) +schema/services/collection.py (إزالة الطابع الزمني) + +**التغييرات المكتملة (التغيير 10):** ✅ +جميع خدمات التخزين (11 إجمالاً) - تم ترحيلها إلى دفع التكوين لتحديثات المجموعة عبر `CollectionConfigHandler` +تم إزالة مخطط إدارة التخزين من `storage.py` + +## اعتبارات مستقبلية + +### نموذج مساحة مفاتيح خاصة بالمستخدم + +تستخدم بعض الخدمات **مساحات مفاتيح خاصة بالمستخدم** ديناميكيًا، حيث يحصل كل مستخدم على مساحة مفاتيح Cassandra خاصة به: + +**الخدمات التي تستخدم مساحات مفاتيح خاصة بالمستخدم:** +1. **خدمة استعلام الثلاثيات** (`trustgraph-flow/trustgraph/query/triples/cassandra/service.py:65`) + تستخدم `keyspace=query.user` +2. **خدمة استعلام الكائنات** (`trustgraph-flow/trustgraph/query/objects/cassandra/service.py:479`) + تستخدم `keyspace=self.sanitize_name(user)` +3. **الوصول المباشر إلى الرسم البياني المعرفي** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py:18`) + المعلمة الافتراضية `keyspace="trustgraph"` + +**الحالة:** هذه **غير معدلة** في هذا المواصفات. + +**مراجعة مستقبلية مطلوبة:** +تقييم ما إذا كانت نموذج مساحة مفاتيح خاصة بالمستخدم تخلق مشاكل عزل المستأجر +ضع في اعتبارك ما إذا كانت عمليات النشر متعددة المستأجرين تحتاج إلى أنماط بادئة لمساحة مفاتيح (مثل `tenant_a_user1`) +مراجعة للاحتمالية المحتملة لتصادم معرف المستخدم عبر المستأجرين +تقييم ما إذا كانت مساحة مفاتيح مشتركة واحدة لكل مستأجر مع عزل الصفوف المستند إلى المستخدم هي الأفضل + +**ملاحظة:** هذا لا يمنع التنفيذ متعدد المستأجرين الحالي ولكنه يجب مراجعته قبل عمليات نشر متعددة المستأجرين في الإنتاج. + +## مراحل التنفيذ + +### المرحلة 1: إصلاحات المعلمات (التغييرات 1-6) +إصلاح تسمية المعلمة `--config-push-queue` +إضافة دعم المعلمة `--cassandra-keyspace` +**النتيجة:** تم تمكين قائمة الانتظار متعددة المستأجرين وتكوين مساحة المفاتيح + +### المرحلة 2: ترحيل إدارة المجموعة (التغييرات 7-9، 11) +ترحيل تخزين المجموعة إلى خدمة التكوين +إزالة جدول المجموعات من librarian +تحديث مخطط المجموعة (إزالة الطوابع الزمنية) +**النتيجة:** يلغي إدارة التخزين المضمنة، ويبسط librarian + +### المرحلة 3: تحديثات خدمة التخزين (التغيير 10) ✅ مكتمل +تم تحديث جميع خدمات التخزين لاستخدام دفع التكوين للمجموعات عبر `CollectionConfigHandler` +تمت إزالة البنية التحتية لطلبات واستجابات إدارة التخزين +تمت إزالة تعريفات المخطط القديمة +**النتيجة:** تم تحقيق إدارة المجموعة المستندة إلى التكوين بالكامل + +## المراجع +مشكلة GitHub: https://github.com/trustgraph-ai/trustgraph/issues/582 +الملفات ذات الصلة: + `trustgraph-base/trustgraph/base/async_processor.py` + `trustgraph-base/trustgraph/base/cassandra_config.py` + `trustgraph-base/trustgraph/schema/core/topic.py` + `trustgraph-base/trustgraph/schema/services/collection.py` + `trustgraph-flow/trustgraph/config/service/service.py` + `trustgraph-flow/trustgraph/cores/service.py` + `trustgraph-flow/trustgraph/librarian/service.py` + `trustgraph-flow/trustgraph/librarian/collection_manager.py` + `trustgraph-flow/trustgraph/tables/library.py` diff --git a/docs/tech-specs/multi-tenant-support.es.md b/docs/tech-specs/multi-tenant-support.es.md new file mode 100644 index 00000000..9e6f4241 --- /dev/null +++ b/docs/tech-specs/multi-tenant-support.es.md @@ -0,0 +1,772 @@ +# Especificación técnica: Soporte para entornos multi-inquilino + +## Resumen + +Habilite implementaciones multi-inquilino corrigiendo las discrepancias en los nombres de los parámetros que impiden la personalización de la cola y agregando la parametrización del espacio de claves de Cassandra. + +## Contexto de la arquitectura + +### Resolución de colas basada en flujos + +El sistema TrustGraph utiliza una **arquitectura basada en flujos** para la resolución dinámica de colas, lo que inherentemente admite la multi-inquilinización: + +Las **definiciones de flujo** se almacenan en Cassandra y especifican los nombres de las colas a través de definiciones de interfaz. +Los **nombres de las colas utilizan plantillas** con variables `{id}` que se reemplazan con los ID de las instancias de flujo. +Los **servicios resuelven dinámicamente las colas** buscando las configuraciones de flujo en el momento de la solicitud. +**Cada inquilino puede tener flujos únicos** con diferentes nombres de cola, lo que proporciona aislamiento. + +Ejemplo de definición de interfaz de flujo: +```json +{ + "interfaces": { + "triples-store": "persistent://tg/flow/triples-store:{id}", + "graph-embeddings-store": "persistent://tg/flow/graph-embeddings-store:{id}" + } +} +``` + +Cuando el inquilino A inicia el flujo `tenant-a-prod` y el inquilino B inicia el flujo `tenant-b-prod`, automáticamente obtienen colas aisladas: +`persistent://tg/flow/triples-store:tenant-a-prod` +`persistent://tg/flow/triples-store:tenant-b-prod` + +**Servicios diseñados correctamente para la multi-inquilinización:** +✅ **Knowledge Management (núcleos)** - Resuelve dinámicamente las colas a partir de la configuración del flujo que se pasa en las solicitudes. + +**Servicios que necesitan correcciones:** +🔴 **Config Service** - La falta de coincidencia en el nombre del parámetro impide la personalización de la cola. +🔴 **Librarian Service** - Temas de gestión de almacenamiento codificados (se discute a continuación). +🔴 **Todos los servicios** - No se puede personalizar el keyspace de Cassandra. + +## Declaración del problema + +### Problema #1: Falta de coincidencia en el nombre del parámetro en AsyncProcessor +**CLI define:** `--config-queue` (nombre poco claro) +**Argparse convierte a:** `config_queue` (en el diccionario de parámetros) +**El código busca:** `config_push_queue` +**Resultado:** El parámetro se ignora, por defecto a `persistent://tg/config/config` +**Impacto:** Afecta a más de 32 servicios que heredan de AsyncProcessor. +**Bloquea:** Los despliegues multi-inquilinos no pueden usar colas de configuración específicas del inquilino. +**Solución:** Cambiar el nombre del parámetro de la CLI a `--config-push-queue` para mayor claridad (el cambio importante es aceptable, ya que la función actualmente está rota). + +### Problema #2: Falta de coincidencia en el nombre del parámetro en Config Service +**CLI define:** `--push-queue` (nombre ambiguo) +**Argparse convierte a:** `push_queue` (en el diccionario de parámetros) +**El código busca:** `config_push_queue` +**Resultado:** El parámetro se ignora. +**Impacto:** El servicio de configuración no puede usar una cola de envío personalizada. +**Solución:** Cambiar el nombre del parámetro de la CLI a `--config-push-queue` para mayor coherencia y claridad (el cambio importante es aceptable). + +### Problema #3: Keyspace de Cassandra codificado +**Actual:** El keyspace está codificado como `"config"`, `"knowledge"`, `"librarian"` en varios servicios. +**Resultado:** No se puede personalizar el keyspace para los despliegues multi-inquilinos. +**Impacto:** Servicios de configuración, núcleos y bibliotecario. +**Bloquea:** Múltiples inquilinos no pueden usar keyspaces de Cassandra separados. + +### Problema #4: Arquitectura de gestión de colecciones ✅ COMPLETADO +**Anterior:** Las colecciones se almacenaban en el keyspace de Cassandra del bibliotecario a través de una tabla de colecciones separada. +**Anterior:** El bibliotecario utilizaba 4 temas de gestión de almacenamiento codificados para coordinar la creación/eliminación de colecciones: + `vector_storage_management_topic` + `object_storage_management_topic` + `triples_storage_management_topic` + `storage_management_response_topic` +**Problemas (Resueltos):** + Los temas codificados no se podían personalizar para los despliegues multi-inquilinos. + Coordinación asíncrona compleja entre el bibliotecario y 4 o más servicios de almacenamiento. + Infraestructura de tabla y gestión de Cassandra separada. + Colas de solicitud/respuesta no persistentes para operaciones críticas. +**Solución implementada:** Se migraron las colecciones al almacenamiento del servicio de configuración, se utiliza el envío de configuración para la distribución. +**Estado:** Todos los backends de almacenamiento se han migrado al patrón `CollectionConfigHandler`. + +## Solución + +Esta especificación aborda los problemas #1, #2, #3 y #4. + +### Parte 1: Corregir las faltas de coincidencia en el nombre del parámetro + +#### Cambio 1: Clase base AsyncProcessor - Cambiar el nombre del parámetro de la CLI +**Archivo:** `trustgraph-base/trustgraph/base/async_processor.py` +**Línea:** 260-264 + +**Actual:** +```python +parser.add_argument( + '--config-queue', + default=default_config_queue, + help=f'Config push queue {default_config_queue}', +) +``` + +**Fijo:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_queue, + help=f'Config push queue (default: {default_config_queue})', +) +``` + +**Justificación:** +Nombres más claros y explícitos. +Coincide con el nombre de la variable interna `config_push_queue`. +El cambio es aceptable ya que la función actualmente no está operativa. +No se necesita ningún cambio en el código de params.get() - ya busca el nombre correcto. + +#### Cambio 2: Servicio de Configuración - Renombrar Parámetro de la Interfaz de Línea de Comandos +**Archivo:** `trustgraph-flow/trustgraph/config/service/service.py` +**Línea:** 276-279 + +**Actual:** +```python +parser.add_argument( + '--push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**Fijo:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**Justificación:** +Nombres más claros: "config-push-queue" es más explícito que simplemente "push-queue". +Coincide con el nombre de la variable interna `config_push_queue`. +Consistente con el parámetro `--config-push-queue` de AsyncProcessor. +El cambio es aceptable ya que la función actualmente no está operativa. +No se necesita ningún cambio en el código en params.get() - ya busca el nombre correcto. + +### Parte 2: Agregar la parametrización del espacio de claves de Cassandra + +#### Cambio 3: Agregar el parámetro de espacio de claves al módulo cassandra_config +**Archivo:** `trustgraph-base/trustgraph/base/cassandra_config.py` + +**Agregar argumento de la línea de comandos** (en la función `add_cassandra_args()`): +```python +parser.add_argument( + '--cassandra-keyspace', + default=None, + help='Cassandra keyspace (default: service-specific)' +) +``` + +**Agregar soporte para variables de entorno** (en la función `resolve_cassandra_config()`): +```python +keyspace = params.get( + "cassandra_keyspace", + os.environ.get("CASSANDRA_KEYSPACE") +) +``` + +**Actualizar el valor de retorno** de `resolve_cassandra_config()`: +Actualmente devuelve: `(hosts, username, password)` +Cambiar para que devuelva: `(hosts, username, password, keyspace)` + +**Justificación:** +Coherente con el patrón de configuración de Cassandra existente +Disponible para todos los servicios a través de `add_cassandra_args()` +Admite la configuración mediante la línea de comandos y variables de entorno + +#### Cambio 4: Servicio de Configuración - Utilizar Espacios de Claves Parametrizados +**Archivo:** `trustgraph-flow/trustgraph/config/service/service.py` + +**Línea 30** - Eliminar el espacio de claves codificado de forma rígida: +```python +# DELETE THIS LINE: +keyspace = "config" +``` + +**Líneas 69-73** - Actualización de la resolución de la configuración de Cassandra: + +**Actual:** +```python +cassandra_host, cassandra_username, cassandra_password = \ + resolve_cassandra_config(params) +``` + +**Fijo:** +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="config") +``` + +**Justificación:** +Mantiene la compatibilidad con versiones anteriores, utilizando "config" como valor predeterminado. +Permite la sobrescritura a través de `--cassandra-keyspace` o `CASSANDRA_KEYSPACE`. + +#### Cambio 5: Servicio de Conocimiento (Cores) - Utilizar Espacios de Claves Parametrizados +**Archivo:** `trustgraph-flow/trustgraph/cores/service.py` + +**Línea 37** - Eliminar el espacio de claves codificado de forma rígida: +```python +# DELETE THIS LINE: +keyspace = "knowledge" +``` + +**Actualización de la resolución de la configuración de Cassandra** (ubicación similar a la del servicio de configuración): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="knowledge") +``` + +#### Cambio 6: Servicio de Bibliotecario - Utilizar Claves de Espacio de Claves Parametrizadas +**Archivo:** `trustgraph-flow/trustgraph/librarian/service.py` + +**Línea 51** - Eliminar el espacio de claves codificado de forma rígida: +```python +# DELETE THIS LINE: +keyspace = "librarian" +``` + +**Actualización de la resolución de la configuración de Cassandra** (ubicación similar a la del servicio de configuración): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="librarian") +``` + +### Parte 3: Migrar la gestión de colecciones al servicio de configuración + +#### Resumen +Migrar las colecciones del espacio de claves de Cassandra librarian al almacenamiento del servicio de configuración. Esto elimina los temas de gestión de almacenamiento codificados de forma rígida y simplifica la arquitectura utilizando el mecanismo de envío de configuración existente para la distribución. + +#### Arquitectura actual +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Cassandra Collections Table (librarian keyspace) + ↓ + Broadcast to 4 Storage Management Topics (hardcoded) + ↓ + Wait for 4+ Storage Service Responses + ↓ + Response to Gateway +``` + +#### Nueva Arquitectura +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Config Service API (put/delete/getvalues) + ↓ + Cassandra Config Table (class='collections', key='user:collection') + ↓ + Config Push (to all subscribers on config-push-queue) + ↓ + All Storage Services receive config update independently +``` + +#### Cambio 7: Administrador de Colecciones - Utilizar la API del Servicio de Configuración +**Archivo:** `trustgraph-flow/trustgraph/librarian/collection_manager.py` + +**Eliminar:** +Uso de `LibraryTableStore` (Líneas 33, 40-41) +Inicialización de productores de gestión de almacenamiento (Líneas 86-140) +Método `on_storage_response` (Líneas 400-430) +Seguimiento de `pending_deletions` (Líneas 57, 90-96 y uso en todo el código) + +**Añadir:** +Cliente del servicio de configuración para llamadas a la API (patrón de solicitud/respuesta) + +**Configuración del Cliente:** +```python +# In __init__, add config request/response producers/consumers +from trustgraph.schema.services.config import ConfigRequest, ConfigResponse + +# Producer for config requests +self.config_request_producer = Producer( + client=pulsar_client, + topic=config_request_queue, + schema=ConfigRequest, +) + +# Consumer for config responses (with correlation ID) +self.config_response_consumer = Consumer( + taskgroup=taskgroup, + client=pulsar_client, + flow=None, + topic=config_response_queue, + subscriber=f"{id}-config", + schema=ConfigResponse, + handler=self.on_config_response, +) + +# Tracking for pending config requests +self.pending_config_requests = {} # request_id -> asyncio.Event +``` + +**Modificar `list_collections` (Líneas 145-180):** +```python +async def list_collections(self, user, tag_filter=None, limit=None): + """List collections from config service""" + # Send getvalues request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='getvalues', + type='collections', + ) + + # Send request and wait for response + response = await self.send_config_request(request) + + # Parse collections from response + collections = [] + for key, value_json in response.values.items(): + if ":" in key: + coll_user, collection = key.split(":", 1) + if coll_user == user: + metadata = json.loads(value_json) + collections.append(CollectionMetadata(**metadata)) + + # Apply tag filtering in-memory (as before) + if tag_filter: + collections = [c for c in collections if any(tag in c.tags for tag in tag_filter)] + + # Apply limit + if limit: + collections = collections[:limit] + + return collections + +async def send_config_request(self, request): + """Send config request and wait for response""" + event = asyncio.Event() + self.pending_config_requests[request.id] = event + + await self.config_request_producer.send(request) + await event.wait() + + return self.pending_config_requests.pop(request.id + "_response") + +async def on_config_response(self, message, consumer, flow): + """Handle config response""" + response = message.value() + if response.id in self.pending_config_requests: + self.pending_config_requests[response.id + "_response"] = response + self.pending_config_requests[response.id].set() +``` + +**Modificar `update_collection` (Líneas 182-312):** +```python +async def update_collection(self, user, collection, name, description, tags): + """Update collection via config service""" + # Create metadata + metadata = CollectionMetadata( + user=user, + collection=collection, + name=name, + description=description, + tags=tags, + ) + + # Send put request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='put', + type='collections', + key=f'{user}:{collection}', + value=json.dumps(metadata.to_dict()), + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config update failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and create collections +``` + +**Modificar `delete_collection` (Líneas 314-398):** +```python +async def delete_collection(self, user, collection): + """Delete collection via config service""" + # Send delete request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='delete', + type='collections', + key=f'{user}:{collection}', + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config delete failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and delete collections +``` + +**Formato de Metadatos de Colección:** +Almacenado en la tabla de configuración como: `class='collections', key='user:collection'` +El valor es una instancia de CollectionMetadata serializada en formato JSON (sin campos de marca de tiempo) +Campos: `user`, `collection`, `name`, `description`, `tags` +Ejemplo: `class='collections', key='alice:my-docs', value='{"user":"alice","collection":"my-docs","name":"My Documents","description":"...","tags":["work"]}'` + +#### Cambio 8: Servicio de Bibliotecario - Eliminar la Infraestructura de Gestión de Almacenamiento +**Archivo:** `trustgraph-flow/trustgraph/librarian/service.py` + +**Eliminar:** +Productores de gestión de almacenamiento (Líneas 173-190): + `vector_storage_management_producer` + `object_storage_management_producer` + `triples_storage_management_producer` +Consumidor de respuesta de almacenamiento (Líneas 192-201) +Controlador `on_storage_response` (Líneas 467-473) + +**Modificar:** +Inicialización de CollectionManager (Líneas 215-224) - eliminar los parámetros del productor de almacenamiento + +**Nota:** La API externa de colecciones permanece sin cambios: +`list-collections` +`update-collection` +`delete-collection` + +#### Cambio 9: Eliminar la Tabla de Colecciones de LibraryTableStore +**Archivo:** `trustgraph-flow/trustgraph/tables/library.py` + +**Eliminar:** +Sentencia CREATE de la tabla de colecciones (Líneas 114-127) +Sentencias preparadas de colecciones (Líneas 205-240) +Todos los métodos de colección (Líneas 578-717): + `ensure_collection_exists` + `list_collections` + `update_collection` + `delete_collection` + `get_collection` + `create_collection` + +**Justificación:** +Las colecciones ahora se almacenan en la tabla de configuración +El cambio importante es aceptable: no se necesita migración de datos +Simplifica significativamente el servicio de bibliotecario + +#### Cambio 10: Servicios de Almacenamiento - Gestión de Colecciones Basada en Configuración ✅ COMPLETADO + +**Estado:** Todos los 11 backends de almacenamiento se han migrado para usar `CollectionConfigHandler`. + +**Servicios Afectados (11 en total):** +Incrustaciones de documentos: milvus, pinecone, qdrant +Incrustaciones de grafos: milvus, pinecone, qdrant +Almacenamiento de objetos: cassandra +Almacenamiento de triples: cassandra, falkordb, memgraph, neo4j + +**Archivos:** +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +`trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +`trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` + +**Patrón de Implementación (todos los servicios):** + +1. **Registrar el controlador de configuración en `__init__`:** +```python +# Add after AsyncProcessor initialization +self.register_config_handler(self.on_collection_config) +self.known_collections = set() # Track (user, collection) tuples +``` + +2. **Implementar el manejador de configuración:** +```python +async def on_collection_config(self, config, version): + """Handle collection configuration updates""" + logger.info(f"Collection config version: {version}") + + if "collections" not in config: + return + + # Parse collections from config + # Key format: "user:collection" in config["collections"] + config_collections = set() + for key in config["collections"].keys(): + if ":" in key: + user, collection = key.split(":", 1) + config_collections.add((user, collection)) + + # Determine changes + to_create = config_collections - self.known_collections + to_delete = self.known_collections - config_collections + + # Create new collections (idempotent) + for user, collection in to_create: + try: + await self.create_collection_internal(user, collection) + self.known_collections.add((user, collection)) + logger.info(f"Created collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to create {user}/{collection}: {e}") + + # Delete removed collections (idempotent) + for user, collection in to_delete: + try: + await self.delete_collection_internal(user, collection) + self.known_collections.discard((user, collection)) + logger.info(f"Deleted collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to delete {user}/{collection}: {e}") +``` + +3. **Inicializar colecciones conocidas al inicio:** +```python +async def start(self): + """Start the processor""" + await super().start() + await self.sync_known_collections() + +async def sync_known_collections(self): + """Query backend to populate known_collections set""" + # Backend-specific implementation: + # - Milvus/Pinecone/Qdrant: List collections/indexes matching naming pattern + # - Cassandra: Query keyspaces or collection metadata + # - Neo4j/Memgraph/FalkorDB: Query CollectionMetadata nodes + pass +``` + +4. **Refactorizar los métodos de manejo existentes:** +```python +# Rename and remove response sending: +# handle_create_collection → create_collection_internal +# handle_delete_collection → delete_collection_internal + +async def create_collection_internal(self, user, collection): + """Create collection (idempotent)""" + # Same logic as current handle_create_collection + # But remove response producer calls + # Handle "already exists" gracefully + pass + +async def delete_collection_internal(self, user, collection): + """Delete collection (idempotent)""" + # Same logic as current handle_delete_collection + # But remove response producer calls + # Handle "not found" gracefully + pass +``` + +5. **Eliminar la infraestructura de administración de almacenamiento:** + Eliminar la configuración y el inicio de `self.storage_request_consumer` + Eliminar la configuración de `self.storage_response_producer` + Eliminar el método de despachador de `on_storage_management` + Eliminar las métricas para la administración de almacenamiento + Eliminar las importaciones: `StorageManagementRequest`, `StorageManagementResponse` + +**Consideraciones específicas del backend:** + +**Almacenes de vectores (Milvus, Pinecone, Qdrant):** Realizar un seguimiento de `(user, collection)` lógico en `known_collections`, pero puede crear múltiples colecciones de backend por dimensión. Continuar con el patrón de creación perezosa. Las operaciones de eliminación deben eliminar todas las variantes de dimensión. + +**Objetos Cassandra:** Las colecciones son propiedades de fila, no estructuras. Realizar un seguimiento de la información a nivel de keyspace. + +**Almacenes de grafos (Neo4j, Memgraph, FalkorDB):** Consultar nodos `CollectionMetadata` al inicio. Crear/eliminar nodos de metadatos durante la sincronización. + +**Triples de Cassandra:** Utilizar la API `KnowledgeGraph` para las operaciones de colección. + +**Puntos clave de diseño:** + +**Consistencia eventual:** No hay mecanismo de solicitud/respuesta, el empuje de configuración se transmite. +**Idempotencia:** Todas las operaciones de creación/eliminación deben ser seguras para reintentar. +**Manejo de errores:** Registrar los errores, pero no bloquear las actualizaciones de configuración. +**Autocuración:** Las operaciones fallidas se volverán a intentar en el siguiente empuje de configuración. +**Formato de clave de colección:** `"user:collection"` en `config["collections"]` + +#### Cambio 11: Actualizar el esquema de la colección: eliminar las marcas de tiempo +**Archivo:** `trustgraph-base/trustgraph/schema/services/collection.py` + +**Modificar CollectionMetadata (líneas 13-21):** +Eliminar los campos `created_at` y `updated_at`: +```python +class CollectionMetadata(Record): + user = String() + collection = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() +``` + +**Modificar CollectionManagementRequest (líneas 25-47):** +Eliminar campos de marca de tiempo: +```python +class CollectionManagementRequest(Record): + operation = String() + user = String() + collection = String() + timestamp = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() + tag_filter = Array(String()) + limit = Integer() +``` + +**Justificación:** +Las marcas de tiempo no aportan valor a las colecciones. +El servicio de configuración mantiene su propio seguimiento de versiones. +Simplifica el esquema y reduce el almacenamiento. + +#### Beneficios de la migración del servicio de configuración + +1. ✅ **Elimina los temas de gestión de almacenamiento codificados de forma rígida** - Soluciona el bloqueo de multi-inquilino. +2. ✅ **Coordinación más sencilla** - No hay esperas asíncronas complejas para 4 o más respuestas de almacenamiento. +3. ✅ **Consistencia eventual** - Los servicios de almacenamiento se actualizan de forma independiente a través de la configuración. +4. ✅ **Mayor fiabilidad** - Configuración persistente frente a solicitud/respuesta no persistente. +5. ✅ **Modelo de configuración unificado** - Las colecciones se tratan como configuración. +6. ✅ **Reduce la complejidad** - Elimina aproximadamente 300 líneas de código de coordinación. +7. ✅ **Listo para multi-inquilino** - La configuración ya admite el aislamiento de inquilinos a través de espacios de claves. +8. ✅ **Seguimiento de versiones** - El mecanismo de versión del servicio de configuración proporciona un registro de auditoría. + +## Notas de implementación + +### Compatibilidad con versiones anteriores + +**Cambios de parámetros:** +Los cambios de nombre de los parámetros de la CLI son cambios importantes, pero aceptables (la función actualmente no está operativa). +Los servicios funcionan sin parámetros (utilizan los valores predeterminados). +Los espacios de claves predeterminados se conservan: "config", "knowledge", "librarian". +Cola predeterminada: `persistent://tg/config/config` + +**Gestión de colecciones:** +**Cambio importante:** La tabla de colecciones se elimina del espacio de claves de librarian. +**No se proporciona migración de datos** - aceptable para esta fase. +La API externa de colecciones no cambia (operaciones de lista, actualización y eliminación). +El formato de los metadatos de la colección se simplifica (se eliminan las marcas de tiempo). + +### Requisitos de prueba + +**Pruebas de parámetros:** +1. Verificar que el parámetro `--config-push-queue` funciona en el servicio graph-embeddings. +2. Verificar que el parámetro `--config-push-queue` funciona en el servicio text-completion. +3. Verificar que el parámetro `--config-push-queue` funciona en el servicio de configuración. +4. Verificar que el parámetro `--cassandra-keyspace` funciona para el servicio de configuración. +5. Verificar que el parámetro `--cassandra-keyspace` funciona para el servicio cores. +6. Verificar que el parámetro `--cassandra-keyspace` funciona para el servicio librarian. +7. Verificar que los servicios funcionan sin parámetros (utiliza los valores predeterminados). +8. Verificar la implementación multi-inquilino con nombres de cola y espacios de claves personalizados. + +**Pruebas de gestión de colecciones:** +9. Verificar la operación `list-collections` a través del servicio de configuración. +10. Verificar que `update-collection` crea/actualiza en la tabla de configuración. +11. Verificar que `delete-collection` elimina de la tabla de configuración. +12. Verificar que se activa la propagación de la configuración cuando se actualizan las colecciones. +13. Verificar que el filtrado de etiquetas funciona con el almacenamiento basado en la configuración. +14. Verificar que las operaciones de la colección funcionan sin campos de marca de tiempo. + +### Ejemplo de implementación multi-inquilino +```bash +# Tenant: tg-dev +graph-embeddings \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config + +config-service \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config \ + --cassandra-keyspace tg_dev_config +``` + +## Análisis de Impacto + +### Servicios Afectados por el Cambio 1-2 (Renombramiento de Parámetro de la CLI) +Todos los servicios que heredan de AsyncProcessor o FlowProcessor: +config-service +cores-service +librarian-service +graph-embeddings +document-embeddings +text-completion-* (todos los proveedores) +extract-* (todos los extractores) +query-* (todos los servicios de consulta) +retrieval-* (todos los servicios RAG) +storage-* (todos los servicios de almacenamiento) +Y más de 20 servicios + +### Servicios Afectados por los Cambios 3-6 (Espacio de Claves de Cassandra) +config-service +cores-service +librarian-service + +### Servicios Afectados por los Cambios 7-11 (Gestión de Colecciones) + +**Cambios Inmediatos:** +librarian-service (collection_manager.py, service.py) +tables/library.py (eliminación de la tabla de colecciones) +schema/services/collection.py (eliminación de la marca de tiempo) + +**Cambios Completados (Cambio 10):** ✅ +Todos los servicios de almacenamiento (11 en total) - migrados a la configuración push para las actualizaciones de colecciones a través de `CollectionConfigHandler` +Esquema de gestión de almacenamiento eliminado de `storage.py` + +## Consideraciones Futuras + +### Modelo de Espacio de Claves por Usuario + +Algunos servicios utilizan **espacios de claves por usuario** dinámicamente, donde cada usuario obtiene su propio espacio de claves de Cassandra: + +**Servicios con espacios de claves por usuario:** +1. **Servicio de Consulta de Triples** (`trustgraph-flow/trustgraph/query/triples/cassandra/service.py:65`) + Utiliza `keyspace=query.user` +2. **Servicio de Consulta de Objetos** (`trustgraph-flow/trustgraph/query/objects/cassandra/service.py:479`) + Utiliza `keyspace=self.sanitize_name(user)` +3. **Acceso Directo al Gráfico de Conocimiento** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py:18`) + Parámetro predeterminado `keyspace="trustgraph"` + +**Estado:** Estos **no se modifican** en esta especificación. + +**Revisión Futura Requerida:** +Evaluar si el modelo de espacio de claves por usuario crea problemas de aislamiento de inquilinos +Considerar si las implementaciones multi-inquilino necesitan patrones de prefijos de espacio de claves (por ejemplo, `tenant_a_user1`) +Revisar posibles colisiones de ID de usuario entre inquilinos +Evaluar si un espacio de claves compartido único por inquilino con aislamiento de filas basado en el usuario es preferible + +**Nota:** Esto no bloquea la implementación multi-inquilino actual, pero debe revisarse antes de las implementaciones multi-inquilino de producción. + +## Fases de Implementación + +### Fase 1: Correcciones de Parámetros (Cambios 1-6) +Corregir el nombre del parámetro `--config-push-queue` +Agregar soporte para el parámetro `--cassandra-keyspace` +**Resultado:** Configuración de cola y espacio de claves multi-inquilino habilitada + +### Fase 2: Migración de la Gestión de Colecciones (Cambios 7-9, 11) +Migrar el almacenamiento de colecciones al servicio de configuración +Eliminar la tabla de colecciones de librarian +Actualizar el esquema de colecciones (eliminar marcas de tiempo) +**Resultado:** Elimina la gestión de almacenamiento codificada, simplifica librarian + +### Fase 3: Actualizaciones del Servicio de Almacenamiento (Cambio 10) ✅ COMPLETADO +Se actualizaron todos los servicios de almacenamiento para usar la configuración push para las colecciones a través de `CollectionConfigHandler` +Se eliminó la infraestructura de solicitud/respuesta de gestión de almacenamiento +Se eliminaron las definiciones de esquema heredadas +**Resultado:** Se logró una gestión de colecciones basada en configuración completa + +## Referencias +Problema de GitHub: https://github.com/trustgraph-ai/trustgraph/issues/582 +Archivos relacionados: + `trustgraph-base/trustgraph/base/async_processor.py` + `trustgraph-base/trustgraph/base/cassandra_config.py` + `trustgraph-base/trustgraph/schema/core/topic.py` + `trustgraph-base/trustgraph/schema/services/collection.py` + `trustgraph-flow/trustgraph/config/service/service.py` + `trustgraph-flow/trustgraph/cores/service.py` + `trustgraph-flow/trustgraph/librarian/service.py` + `trustgraph-flow/trustgraph/librarian/collection_manager.py` + `trustgraph-flow/trustgraph/tables/library.py` diff --git a/docs/tech-specs/multi-tenant-support.he.md b/docs/tech-specs/multi-tenant-support.he.md new file mode 100644 index 00000000..49493641 --- /dev/null +++ b/docs/tech-specs/multi-tenant-support.he.md @@ -0,0 +1,772 @@ +# מפרט טכני: תמיכה בריבוי דיירים + +## סקירה כללית + +אפשר ריבוי פריסות דיירים על ידי תיקון חוסר התאמות בשמות הפרמטרים שמונע התאמה אישית של תורים, והוספת פרמטריזציה של מרחבי מפתחות Cassandra. + +## הקשר ארכיטקטוני + +### פתרון תורים מבוסס זרימה + +מערכת TrustGraph משתמשת בארכיטקטורה **מבוססת זרימה** לפתרון דינמי של תורים, התומכת באופן מובנה בריבוי דיירים: + +**הגדרות זרימה** מאוחסנות ב-Cassandra ומציינות שמות תורים באמצעות הגדרות ממשק. +**שמות התורים משתמשים בתבניות** עם משתנים `{id}` שמוחלפים במזהי מופעי זרימה. +**השירותים פותרים באופן דינמי את התורים** על ידי חיפוש תצורות זרימה בזמן בקשה. +**לכל דייר יכולות להיות זרימות ייחודיות** עם שמות תורים שונים, המספקות בידוד. + +דוגמה להגדרת ממשק זרימה: +```json +{ + "interfaces": { + "triples-store": "persistent://tg/flow/triples-store:{id}", + "graph-embeddings-store": "persistent://tg/flow/graph-embeddings-store:{id}" + } +} +``` + +כאשר שוכר א מתחיל זרימה `tenant-a-prod` ושוכר ב מתחיל זרימה `tenant-b-prod`, הם באופן אוטומטי מקבלים תורים מבודדים: +`persistent://tg/flow/triples-store:tenant-a-prod` +`persistent://tg/flow/triples-store:tenant-b-prod` + +**שירותים המעוצבים כראוי עבור ריבוי שוכרים:** +✅ **ניהול ידע (ליבה)** - פותר באופן דינמי תורים מהגדרת הזרימה המועברת בבקשות + +**שירותים הדורשים תיקונים:** +🔴 **שירות תצורה** - חוסר התאמה בשם הפרמטר מונע התאמה אישית של תורים +🔴 **שירות ספרית** - נושאים של ניהול אחסון מקודדים (נדון בהמשך) +🔴 **כל השירותים** - לא ניתן להתאים אישית את מרחב המפתחות של Cassandra + +## הצהרת בעיה + +### בעיה #1: חוסר התאמה בשם פרמטר ב-AsyncProcessor +**הגדרות CLI:** `--config-queue` (שם לא ברור) +**Argparse ממיר ל:** `config_queue` (במילון הפרמטרים) +**הקוד מחפש:** `config_push_queue` +**תוצאה:** הפרמטר מתעלם, ברירת מחדל ל-`persistent://tg/config/config` +**השפעה:** משפיע על כל 32+ שירותים היורשים מ-AsyncProcessor +**חוסם:** פריסות מרובות שוכרים לא יכולות להשתמש בתורי תצורה ספציפיים לשוכר +**פתרון:** לשנות את שם הפרמטר ב-CLI ל-`--config-push-queue` לצורך בהירות (שינוי שבירה מקובל מכיוון שהתכונה שבורה כרגע) + +### בעיה #2: חוסר התאמה בשם פרמטר בשירות התצורה +**הגדרות CLI:** `--push-queue` (שם מעורפל) +**Argparse ממיר ל:** `push_queue` (במילון הפרמטרים) +**הקוד מחפש:** `config_push_queue` +**תוצאה:** הפרמטר מתעלם +**השפעה:** שירות התצורה לא יכול להשתמש בתור דחיפה מותאם אישית +**פתרון:** לשנות את שם הפרמטר ב-CLI ל-`--config-push-queue` לצורך עקביות ובהירות (שינוי שבירה מקובל) + +### בעיה #3: מרחב מפתחות Cassandra מקודד +**נוכחי:** מרחב המפתחות מקודד כ-`"config"`, `"knowledge"`, `"librarian"` בשירותים שונים +**תוצאה:** לא ניתן להתאים אישית את מרחב המפתחות עבור פריסות מרובות שוכרים +**השפעה:** שירותי תצורה, ליבה וספריה +**חוסם:** מספר שוכרים לא יכולים להשתמש במרחבי מפתחות Cassandra נפרדים + +### בעיה #4: ארכיטקטורת ניהול אוספים ✅ הושלם +**קודם:** אוספים שמורים במרחב המפתחות של Cassandra של הספריה באמצעות טבלת אוספים נפרדת +**קודם:** הספריה השתמשה ב-4 נושאים מקודדים לניהול אחסון לתאם יצירה/מחיקה של אוספים: + `vector_storage_management_topic` + `object_storage_management_topic` + `triples_storage_management_topic` + `storage_management_response_topic` +**בעיות (טופלו):** + נושאים מקודדים לא ניתן להתאים אישית עבור פריסות מרובות שוכרים + תיאום אסינכרוני מורכב בין הספריה לבין 4+ שירותי אחסון + טבלה נפרדת ותשתית ניהול + תורי בקשה/תגובה לא מתמידים עבור פעולות קריטיות +**פתרון מיושם:** העברנו אוספים לשירות האחסון של התצורה, השתמשנו בדחיפה של תצורה להפצה +**סטטוס:** כל בסיסי האחסון עברו לדפוס `CollectionConfigHandler` + +## פתרון + +מפרט זה מתייחס לבעיות #1, #2, #3 ו-#4. + +### חלק 1: תיקון חוסר התאמה בשמות פרמטרים + +#### שינוי 1: מחלקת בסיס AsyncProcessor - שינוי שם פרמטר CLI +**קובץ:** `trustgraph-base/trustgraph/base/async_processor.py` +**שורה:** 260-264 + +**נוכחי:** +```python +parser.add_argument( + '--config-queue', + default=default_config_queue, + help=f'Config push queue {default_config_queue}', +) +``` + +**קבוע:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_queue, + help=f'Config push queue (default: {default_config_queue})', +) +``` + +**הסבר:** +שם ברור וחד יותר +תואם לשם המשתנה הפנימי `config_push_queue` +שינוי משמעותי מקובל מכיוון שהפיצ'ר אינו פעיל כרגע +אין צורך בשינוי קוד בפונקציה params.get() - היא כבר מחפשת את השם הנכון + +#### שינוי 2: שירות תצורה - שינוי שם פרמטר שורת הפקודה +**קובץ:** `trustgraph-flow/trustgraph/config/service/service.py` +**שורה:** 276-279 + +**נוכחי:** +```python +parser.add_argument( + '--push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**קבוע:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**הסבר:** +שמות ברורים יותר - "config-push-queue" מפורט יותר מ-"push-queue" בלבד. +תואם לשם המשתנה הפנימי `config_push_queue`. +עקבי עם הפרמטר `--config-push-queue` של AsyncProcessor. +שינוי שעלול לשבור תאימות מקובל מכיוון שהפיצ'ר אינו פונקציונלי כרגע. +אין צורך בשינוי קוד בפונקציה params.get() - היא כבר מחפשת את השם הנכון. + +### חלק 2: הוספת פרמטריזציה של Keyspace של Cassandra + +#### שינוי 3: הוספת פרמטר Keyspace למודול cassandra_config +**קובץ:** `trustgraph-base/trustgraph/base/cassandra_config.py` + +**הוספת ארגומנט שורת פקודה** (בפונקציה `add_cassandra_args()`): +```python +parser.add_argument( + '--cassandra-keyspace', + default=None, + help='Cassandra keyspace (default: service-specific)' +) +``` + +**הוספת תמיכה במשתני סביבה** (בפונקציה `resolve_cassandra_config()`): +```python +keyspace = params.get( + "cassandra_keyspace", + os.environ.get("CASSANDRA_KEYSPACE") +) +``` + +**עדכון ערך ההחזרה** של `resolve_cassandra_config()`: +כרגע מחזיר: `(hosts, username, password)` +לשנות כך שיחזיר: `(hosts, username, password, keyspace)` + +**הצדקה:** +עקבי עם תבנית התצורה הקיימת של Cassandra +זמין לכל השירותים דרך `add_cassandra_args()` +תומך בתצורה הן דרך שורת הפקודה והן דרך משתני סביבה + +#### שינוי 4: שירות תצורה - שימוש במפתחות מרחב (Keyspace) מוגדרים +**קובץ:** `trustgraph-flow/trustgraph/config/service/service.py` + +**שורה 30** - הסרת שם מרחב (Keyspace) מקודד: +```python +# DELETE THIS LINE: +keyspace = "config" +``` + +**שורות 69-73** - עדכון פתרון תצורת Cassandra: + +**נוכחי:** +```python +cassandra_host, cassandra_username, cassandra_password = \ + resolve_cassandra_config(params) +``` + +**קבוע:** +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="config") +``` + +**הסבר:** +שומר על תאימות לאחור עם "config" כברירת מחדל. +מאפשר ביטול באמצעות `--cassandra-keyspace` או `CASSANDRA_KEYSPACE`. + +#### שינוי 5: שירות ליבה/ידע - שימוש במרחבי מפתחות מוגדרים +**קובץ:** `trustgraph-flow/trustgraph/cores/service.py` + +**שורה 37** - הסרת מרחב מפתחות מקודד: +```python +# DELETE THIS LINE: +keyspace = "knowledge" +``` + +**עדכון פתרון תצורת Cassandra** (במיקום דומה לשירות התצורה): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="knowledge") +``` + +#### שינוי 6: שירות סוכן מידע - שימוש במפתחות פרמטריים +**קובץ:** `trustgraph-flow/trustgraph/librarian/service.py` + +**שורה 51** - הסרת מרחב מפתחות מקודד: +```python +# DELETE THIS LINE: +keyspace = "librarian" +``` + +**עדכון פתרון תצורת Cassandra** (במיקום דומה לשירות התצורה): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="librarian") +``` + +### חלק 3: העברת ניהול אוספים לשירות התצורה + +#### סקירה כללית +העברת אוספים ממערכת ה-Cassandra librarian keyspace לאחסון בשירות התצורה. פעולה זו מבטלת נושאים מובנים לניהול אחסון ומפשטת את הארכיטקטורה על ידי שימוש במנגנון הדחיפה הקיים של התצורה לצורך הפצה. + +#### ארכיטקטורה נוכחית +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Cassandra Collections Table (librarian keyspace) + ↓ + Broadcast to 4 Storage Management Topics (hardcoded) + ↓ + Wait for 4+ Storage Service Responses + ↓ + Response to Gateway +``` + +#### ארכיטקטורה חדשה +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Config Service API (put/delete/getvalues) + ↓ + Cassandra Config Table (class='collections', key='user:collection') + ↓ + Config Push (to all subscribers on config-push-queue) + ↓ + All Storage Services receive config update independently +``` + +#### שינוי 7: מנהל אוספים - שימוש ב-API של שירות התצורה +**קובץ:** `trustgraph-flow/trustgraph/librarian/collection_manager.py` + +**הסרה:** +שימוש ב-`LibraryTableStore` (שורות 33, 40-41) +אתחול מפיקי ניהול אחסון (שורות 86-140) +שיטה `on_storage_response` (שורות 400-430) +מעקב `pending_deletions` (שורות 57, 90-96 ושימוש לאורך כל הקוד) + +**הוספה:** +לקוח שירות תצורה עבור קריאות API (תבנית בקשה/תגובה) + +**הגדרת לקוח תצורה:** +```python +# In __init__, add config request/response producers/consumers +from trustgraph.schema.services.config import ConfigRequest, ConfigResponse + +# Producer for config requests +self.config_request_producer = Producer( + client=pulsar_client, + topic=config_request_queue, + schema=ConfigRequest, +) + +# Consumer for config responses (with correlation ID) +self.config_response_consumer = Consumer( + taskgroup=taskgroup, + client=pulsar_client, + flow=None, + topic=config_response_queue, + subscriber=f"{id}-config", + schema=ConfigResponse, + handler=self.on_config_response, +) + +# Tracking for pending config requests +self.pending_config_requests = {} # request_id -> asyncio.Event +``` + +**שנה את `list_collections` (שורות 145-180):** +```python +async def list_collections(self, user, tag_filter=None, limit=None): + """List collections from config service""" + # Send getvalues request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='getvalues', + type='collections', + ) + + # Send request and wait for response + response = await self.send_config_request(request) + + # Parse collections from response + collections = [] + for key, value_json in response.values.items(): + if ":" in key: + coll_user, collection = key.split(":", 1) + if coll_user == user: + metadata = json.loads(value_json) + collections.append(CollectionMetadata(**metadata)) + + # Apply tag filtering in-memory (as before) + if tag_filter: + collections = [c for c in collections if any(tag in c.tags for tag in tag_filter)] + + # Apply limit + if limit: + collections = collections[:limit] + + return collections + +async def send_config_request(self, request): + """Send config request and wait for response""" + event = asyncio.Event() + self.pending_config_requests[request.id] = event + + await self.config_request_producer.send(request) + await event.wait() + + return self.pending_config_requests.pop(request.id + "_response") + +async def on_config_response(self, message, consumer, flow): + """Handle config response""" + response = message.value() + if response.id in self.pending_config_requests: + self.pending_config_requests[response.id + "_response"] = response + self.pending_config_requests[response.id].set() +``` + +**שנה את `update_collection` (שורות 182-312):** +```python +async def update_collection(self, user, collection, name, description, tags): + """Update collection via config service""" + # Create metadata + metadata = CollectionMetadata( + user=user, + collection=collection, + name=name, + description=description, + tags=tags, + ) + + # Send put request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='put', + type='collections', + key=f'{user}:{collection}', + value=json.dumps(metadata.to_dict()), + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config update failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and create collections +``` + +**שנה את `delete_collection` (שורות 314-398):** +```python +async def delete_collection(self, user, collection): + """Delete collection via config service""" + # Send delete request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='delete', + type='collections', + key=f'{user}:{collection}', + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config delete failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and delete collections +``` + +**פורמט מטא-דאטה לאוספים:** +נשמר בטבלת התצורה כ: `class='collections', key='user:collection'` +הערך הוא CollectionMetadata ממוין ב-JSON (ללא שדות תאריך ושעה) +שדות: `user`, `collection`, `name`, `description`, `tags` +דוגמה: `class='collections', key='alice:my-docs', value='{"user":"alice","collection":"my-docs","name":"My Documents","description":"...","tags":["work"]}'` + +#### שינוי 8: שירות הספרייה - הסרת תשתית ניהול אחסון +**קובץ:** `trustgraph-flow/trustgraph/librarian/service.py` + +**הסרה:** +מפיקי ניהול אחסון (שורות 173-190): + `vector_storage_management_producer` + `object_storage_management_producer` + `triples_storage_management_producer` +צרכן תגובות אחסון (שורות 192-201) +מטפל `on_storage_response` (שורות 467-473) + +**שינוי:** +אתחול CollectionManager (שורות 215-224) - הסרת פרמטרים של מפיק אחסון + +**הערה:** ממשק ה-API החיצוני לאוספים נשאר ללא שינוי: +`list-collections` +`update-collection` +`delete-collection` + +#### שינוי 9: הסרת טבלת האוספים מ-LibraryTableStore +**קובץ:** `trustgraph-flow/trustgraph/tables/library.py` + +**מחיקה:** +הצהרת CREATE של טבלת האוספים (שורות 114-127) +הצהרות מוכנות של האוספים (שורות 205-240) +כל שיטות האוספים (שורות 578-717): + `ensure_collection_exists` + `list_collections` + `update_collection` + `delete_collection` + `get_collection` + `create_collection` + +**הצדקה:** +האוספים כעת מאוחסנים בטבלת התצורה +שינוי שמשפיע על השינויים - אין צורך בהעברת נתונים +מפשט את שירות הספרייה באופן משמעותי + +#### שינוי 10: שירותי אחסון - ניהול אוספים מבוסס תצורה ✅ הושלם + +**סטטוס:** כל 11 ה-backends של האחסון עברו לשימוש ב-`CollectionConfigHandler`. + +**שירותים מושפעים (סה"כ 11):** +הטמעות מסמכים: milvus, pinecone, qdrant +הטמעות גרפים: milvus, pinecone, qdrant +אחסון אובייקטים: cassandra +אחסון משולשות: cassandra, falkordb, memgraph, neo4j + +**קבצים:** +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +`trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +`trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` + +**תבנית יישום (לכל השירותים):** + +1. **רישום מטפל תצורה ב-`__init__`:** +```python +# Add after AsyncProcessor initialization +self.register_config_handler(self.on_collection_config) +self.known_collections = set() # Track (user, collection) tuples +``` + +2. **יישום מנהל תצורה:** +```python +async def on_collection_config(self, config, version): + """Handle collection configuration updates""" + logger.info(f"Collection config version: {version}") + + if "collections" not in config: + return + + # Parse collections from config + # Key format: "user:collection" in config["collections"] + config_collections = set() + for key in config["collections"].keys(): + if ":" in key: + user, collection = key.split(":", 1) + config_collections.add((user, collection)) + + # Determine changes + to_create = config_collections - self.known_collections + to_delete = self.known_collections - config_collections + + # Create new collections (idempotent) + for user, collection in to_create: + try: + await self.create_collection_internal(user, collection) + self.known_collections.add((user, collection)) + logger.info(f"Created collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to create {user}/{collection}: {e}") + + # Delete removed collections (idempotent) + for user, collection in to_delete: + try: + await self.delete_collection_internal(user, collection) + self.known_collections.discard((user, collection)) + logger.info(f"Deleted collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to delete {user}/{collection}: {e}") +``` + +3. **אתחול אוספים ידועים בעת ההפעלה:** +```python +async def start(self): + """Start the processor""" + await super().start() + await self.sync_known_collections() + +async def sync_known_collections(self): + """Query backend to populate known_collections set""" + # Backend-specific implementation: + # - Milvus/Pinecone/Qdrant: List collections/indexes matching naming pattern + # - Cassandra: Query keyspaces or collection metadata + # - Neo4j/Memgraph/FalkorDB: Query CollectionMetadata nodes + pass +``` + +4. **שכתוב של שיטות טיפול קיימות:** +```python +# Rename and remove response sending: +# handle_create_collection → create_collection_internal +# handle_delete_collection → delete_collection_internal + +async def create_collection_internal(self, user, collection): + """Create collection (idempotent)""" + # Same logic as current handle_create_collection + # But remove response producer calls + # Handle "already exists" gracefully + pass + +async def delete_collection_internal(self, user, collection): + """Delete collection (idempotent)""" + # Same logic as current handle_delete_collection + # But remove response producer calls + # Handle "not found" gracefully + pass +``` + +5. **הסרת תשתית ניהול אחסון:** + הסרת הגדרות והתחלה של `self.storage_request_consumer` + הסרת הגדרות של `self.storage_response_producer` + הסרת שיטת ה-dispatcher של `on_storage_management` + הסרת מדדים לניהול אחסון + הסרת יבוא: `StorageManagementRequest`, `StorageManagementResponse` + +**שיקולים ספציפיים ל-Backend:** + +**מאגרי וקטורים (Milvus, Pinecone, Qdrant):** לעקוב אחר `(user, collection)` לוגי ב-`known_collections`, אך ייתכן שייווצרו מספר אוספים ב-backend עבור כל מימד. להמשיך בדפוס היצירה המאוחרת. פעולות מחיקה חייבות להסיר את כל הווריאציות של המימד. + +**Cassandra Objects:** אוספים הם מאפייני שורות, ולא מבנים. לעקוב אחר מידע ברמת ה-keyspace. + +**מאגרי גרפים (Neo4j, Memgraph, FalkorDB):** לשאול צמתים של `CollectionMetadata` בעת ההפעלה. ליצור/למחוק צמתי מטא-נתונים בעת הסנכרון. + +**Cassandra Triples:** להשתמש ב-API של `KnowledgeGraph` עבור פעולות אוסף. + +**נקודות עיצוב מרכזיות:** + +**עקביות בסופו של דבר:** אין מנגנון בקשה/תגובה, דחיפת תצורה משודרת +**אידמפוטנטיות:** כל פעולות היצירה/מחיקה חייבות להיות בטוחות לניסיון חוזר +**טיפול בשגיאות:** לרשום שגיאות אך לא לחסום עדכוני תצורה +**ריפוי עצמי:** פעולות שנכשלו ינסו שוב בדחיפת התצורה הבאה +**פורמט מפתח אוסף:** `"user:collection"` ב-`config["collections"]` + +#### שינוי 11: עדכון סכימת האוסף - הסרת חותמות זמן +**קובץ:** `trustgraph-base/trustgraph/schema/services/collection.py` + +**שינוי CollectionMetadata (שורות 13-21):** +להסיר את השדות `created_at` ו-`updated_at`: +```python +class CollectionMetadata(Record): + user = String() + collection = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() +``` + +**שינוי ב-CollectionManagementRequest (שורות 25-47):** +הסרת שדות חותמת זמן: +```python +class CollectionManagementRequest(Record): + operation = String() + user = String() + collection = String() + timestamp = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() + tag_filter = Array(String()) + limit = Integer() +``` + +**ההצדקה:** +חותמות זמן אינן מוסיפות ערך לאוספים +שירות התצורה שומר על מעקב גרסאות משלו +מפשט את הסכימה ומקטין את נפח האחסון + +#### יתרונות של מעבר לשירות התצורה + +1. ✅ **מבטל נושאים של ניהול אחסון מקודדים קשות** - פותר את החסימה של ריבוי דיירים +2. ✅ **תיאום פשוט יותר** - אין המתנה אסינכרונית מורכבת לתגובות של 4+ שירותי אחסון +3. ✅ **עקביות בסופו של דבר** - שירותי האחסון מתעדכנים באופן עצמאי באמצעות דחיפה של תצורה +4. ✅ **אמינות טובה יותר** - דחיפה קבועה של תצורה לעומת בקשה/תגובה לא קבועה +5. ✅ **מודל תצורה מאוחד** - אוספים מטופלים כתצורה +6. ✅ **מפחית מורכבות** - מסיר כ-300 שורות של קוד תיאום +7. ✅ **מוכן לריבוי דיירים** - התצורה כבר תומכת בבידוד דיירים באמצעות מרחבי מפתחות +8. ✅ **מעקב גרסאות** - מנגנון גרסאות של שירות התצורה מספק תיעוד ביקורת + +## הערות יישום + +### תאימות לאחור + +**שינויים בפרמטרים:** +שינויי שמות של פרמטרים בשורת הפקודה הם שינויים שוברים אך מקובלים (התכונה אינה פונקציונלית כרגע) +השירותים עובדים ללא פרמטרים (משתמשים בברירות המחדל) +מרחבי מפתחות ברירת מחדל נשמרו: "config", "knowledge", "librarian" +תור ברירת מחדל: `persistent://tg/config/config` + +**ניהול אוספים:** +**שינוי שובר:** הטבלה של האוספים הוסרה מממרחב המפתחות של librarian +**לא סופקה העברת נתונים** - מקובל לשלב זה +ממשק API חיצוני לאוספים לא השתנה (פעולות רשימה/עדכון/מחיקה) +פורמט מטא-נתונים של אוספים פושט (הוסרו חותמות זמן) + +### דרישות בדיקה + +**בדיקת פרמטרים:** +1. ודאו שהפרמטר `--config-push-queue` עובד בשירות graph-embeddings +2. ודאו שהפרמטר `--config-push-queue` עובד בשירות text-completion +3. ודאו שהפרמטר `--config-push-queue` עובד בשירות התצורה +4. ודאו שהפרמטר `--cassandra-keyspace` עובד עבור שירות התצורה +5. ודאו שהפרמטר `--cassandra-keyspace` עובד עבור שירות cores +6. ודאו שהפרמטר `--cassandra-keyspace` עובד עבור שירות librarian +7. ודאו שהשירותים עובדים ללא פרמטרים (משתמשים בברירות המחדל) +8. ודאו פריסה מרובת דיירים עם שמות תורים ומרחבי מפתחות מותאמים אישית + +**בדיקת ניהול אוספים:** +9. ודאו את הפעולה `list-collections` באמצעות שירות התצורה +10. ודאו ש-`update-collection` יוצר/מעדכן בטבלת התצורה +11. ודאו ש-`delete-collection` מסיר מטבלת התצורה +12. ודאו שדחיפה של תצורה מופעלת בעת עדכונים של אוספים +13. ודאו שסינון תגים עובד עם אחסון מבוסס תצורה +14. ודאו שפעולות על אוספים עובדות ללא שדות חותמות זמן + +### דוגמה לפריסה מרובת דיירים +```bash +# Tenant: tg-dev +graph-embeddings \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config + +config-service \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config \ + --cassandra-keyspace tg_dev_config +``` + +## ניתוח השפעה + +### שירותים המושפעים משינוי 1-2 (שינוי שם פרמטר CLI) +כל השירותים היורשים מ-AsyncProcessor או FlowProcessor: +config-service +cores-service +librarian-service +graph-embeddings +document-embeddings +text-completion-* (כל הספקיות) +extract-* (כל ה-extractors) +query-* (כל שירותי השאילתות) +retrieval-* (כל שירותי ה-RAG) +storage-* (כל שירותי האחסון) +ועוד 20+ שירותים + +### שירותים המושפעים משינויים 3-6 (Keyspace של Cassandra) +config-service +cores-service +librarian-service + +### שירותים המושפעים משינויים 7-11 (ניהול אוספים) + +**שינויים מיידיים:** +librarian-service (collection_manager.py, service.py) +tables/library.py (הסרת טבלת אוספים) +schema/services/collection.py (הסרת חותמת זמן) + +**שינויים שהושלמו (שינוי 10):** ✅ +כל שירותי האחסון (11 בסך הכל) - עברו ל-config push לעדכוני אוספים דרך `CollectionConfigHandler` +סכימת ניהול האחסון הוסרה מ-`storage.py` + +## שיקולים עתידיים + +### מודל Keyspace מבוסס משתמש + +חלק מהשירותים משתמשים באופן דינמי ב-**keyspace מבוסס משתמש**, כאשר לכל משתמש יש את ה-keyspace של Cassandra שלו: + +**שירותים עם keyspace מבוסס משתמש:** +1. **Triples Query Service** (`trustgraph-flow/trustgraph/query/triples/cassandra/service.py:65`) + משתמש ב-`keyspace=query.user` +2. **Objects Query Service** (`trustgraph-flow/trustgraph/query/objects/cassandra/service.py:479`) + משתמש ב-`keyspace=self.sanitize_name(user)` +3. **KnowledgeGraph Direct Access** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py:18`) + פרמטר ברירת מחדל `keyspace="trustgraph"` + +**סטטוס:** אלה **לא משתנים** במפרט זה. + +**נדרשת בדיקה עתידית:** +להעריך האם מודל ה-keyspace מבוסס משתמש יוצר בעיות בידוד שוכרים +לשקול האם פריסות מרובות שוכרים צריכות דפוסי קידומת keyspace (לדוגמה, `tenant_a_user1`) +לבדוק לגבי התנגשות פוטנציאלית של מזהי משתמש בין שוכרים +להעריך האם keyspace משותף יחיד לכל שוכר עם בידוד שורות מבוסס משתמש עדיף + +**הערה:** זה לא חוסם את יישום הריבוי שוכרים הנוכחי, אך יש לבדוק אותו לפני פריסות ריבוי שוכרים לייצור. + +## שלבי יישום + +### שלב 1: תיקוני פרמטרים (שינויים 1-6) +לתקן את שם הפרמטר `--config-push-queue` +להוסיף תמיכה בפרמטר `--cassandra-keyspace` +**תוצאה:** תצורה של תור ו-keyspace מרובי שוכרים מופעלת + +### שלב 2: הגירת ניהול אוספים (שינויים 7-9, 11) +להגר את אחסון האוספים לשירות התצורה +להסיר את טבלת האוספים מ-librarian +לעדכן את סכימת האוספים (להסיר חותמות זמן) +**תוצאה:** מבטלת את נושאי ניהול האחסון המקודדים קשות, מפשטת את librarian + +### שלב 3: עדכוני שירותי אחסון (שינוי 10) ✅ הושלם +עדכנו את כל שירותי האחסון להשתמש ב-config push עבור אוספים דרך `CollectionConfigHandler` +הסרנו את תשתית הבקשות/תגובות לניהול אחסון +הסרנו הגדרות סכימה מיושנות +**תוצאה:** השגת ניהול אוספים מבוסס תצורה מלא + +## הפניות +GitHub Issue: https://github.com/trustgraph-ai/trustgraph/issues/582 +קבצים קשורים: + `trustgraph-base/trustgraph/base/async_processor.py` + `trustgraph-base/trustgraph/base/cassandra_config.py` + `trustgraph-base/trustgraph/schema/core/topic.py` + `trustgraph-base/trustgraph/schema/services/collection.py` + `trustgraph-flow/trustgraph/config/service/service.py` + `trustgraph-flow/trustgraph/cores/service.py` + `trustgraph-flow/trustgraph/librarian/service.py` + `trustgraph-flow/trustgraph/librarian/collection_manager.py` + `trustgraph-flow/trustgraph/tables/library.py` diff --git a/docs/tech-specs/multi-tenant-support.hi.md b/docs/tech-specs/multi-tenant-support.hi.md new file mode 100644 index 00000000..a1878055 --- /dev/null +++ b/docs/tech-specs/multi-tenant-support.hi.md @@ -0,0 +1,772 @@ +# तकनीकी विनिर्देश: मल्टी-टेनेंट समर्थन + +## अवलोकन + +पैरामीटर नाम विसंगतियों को ठीक करके मल्टी-टेनेंट परिनियोजन सक्षम करें जो कतार अनुकूलन को रोकते हैं, और कैसेंड्रा कीस्पेस पैरामीटराइज़ेशन जोड़ें। + +## आर्किटेक्चर संदर्भ + +### फ्लो-आधारित कतार समाधान + +ट्रस्टग्राफ सिस्टम गतिशील कतार समाधान के लिए एक **फ्लो-आधारित आर्किटेक्चर** का उपयोग करता है, जो स्वाभाविक रूप से मल्टी-टेनेंसी का समर्थन करता है: + +**फ्लो परिभाषाएँ** कैसेंड्रा में संग्रहीत हैं और इंटरफ़ेस परिभाषाओं के माध्यम से कतार नामों को निर्दिष्ट करती हैं। +**कतार नाम टेम्प्लेट का उपयोग करते हैं** जिसमें `{id}` चर होते हैं जिन्हें फ्लो इंस्टेंस आईडी के साथ प्रतिस्थापित किया जाता है। +**सेवाएँ गतिशील रूप से कतारों को हल करती हैं** अनुरोध समय पर फ्लो कॉन्फ़िगरेशन की खोज करके। +**प्रत्येक किरायेदार के पास अलग-अलग कतार नामों के साथ अद्वितीय फ्लो हो सकते हैं**, जो अलगाव प्रदान करते हैं। + +फ्लो इंटरफ़ेस परिभाषा का उदाहरण: +```json +{ + "interfaces": { + "triples-store": "persistent://tg/flow/triples-store:{id}", + "graph-embeddings-store": "persistent://tg/flow/graph-embeddings-store:{id}" + } +} +``` + +जब किरायेदार ए प्रवाह `tenant-a-prod` शुरू करता है और किरायेदार बी प्रवाह `tenant-b-prod` शुरू करता है, तो उन्हें स्वचालित रूप से अलग-अलग कतारें मिलती हैं: +`persistent://tg/flow/triples-store:tenant-a-prod` +`persistent://tg/flow/triples-store:tenant-b-prod` + +**मल्टी-टेनेंसी के लिए सही ढंग से डिज़ाइन की गई सेवाएं:** +✅ **नॉलेज मैनेजमेंट (कोर)** - अनुरोधों में पारित प्रवाह कॉन्फ़िगरेशन से कतारों को गतिशील रूप से हल करता है + +**जिन सेवाओं को ठीक करने की आवश्यकता है:** +🔴 **कॉन्फ़िग सर्विस** - पैरामीटर नाम बेमेल होने से कतार अनुकूलन में बाधा आती है +🔴 **लाइब्रेरियन सर्विस** - हार्डकोडेड स्टोरेज मैनेजमेंट टॉपिक (नीचे चर्चा की गई है) +🔴 **सभी सेवाएं** - कैसेंड्रा कीस्पेस को अनुकूलित नहीं किया जा सकता है + +## समस्या विवरण + +### मुद्दा #1: एसिंक्रोनसप्रोसेसर में पैरामीटर नाम बेमेल +**CLI द्वारा परिभाषित:** `--config-queue` (अस्पष्ट नामकरण) +**Argparse द्वारा रूपांतरण:** `config_queue` (पैरामीटर डिक्ट में) +**कोड द्वारा खोजा गया:** `config_push_queue` +**परिणाम:** पैरामीटर को अनदेखा किया जाता है, डिफ़ॉल्ट रूप से `persistent://tg/config/config` +**प्रभाव:** 32 से अधिक सेवाओं पर प्रभाव पड़ता है जो AsyncProcessor से विरासत में मिली हैं +**बाधा:** मल्टी-टेनेंट डिप्लॉयमेंट किरायेदार-विशिष्ट कॉन्फ़िग कतारों का उपयोग नहीं कर सकते हैं +**समाधान:** स्पष्टता के लिए CLI पैरामीटर का नाम बदलकर `--config-push-queue` करें (ब्रेकिंग चेंज स्वीकार्य है क्योंकि सुविधा वर्तमान में टूटी हुई है) + +### मुद्दा #2: कॉन्फ़िग सर्विस में पैरामीटर नाम बेमेल +**CLI द्वारा परिभाषित:** `--push-queue` (अस्पष्ट नामकरण) +**Argparse द्वारा रूपांतरण:** `push_queue` (पैरामीटर डिक्ट में) +**कोड द्वारा खोजा गया:** `config_push_queue` +**परिणाम:** पैरामीटर को अनदेखा किया जाता है +**प्रभाव:** कॉन्फ़िग सर्विस कस्टम पुश कतार का उपयोग नहीं कर सकती है +**समाधान:** स्थिरता और स्पष्टता के लिए CLI पैरामीटर का नाम बदलकर `--config-push-queue` करें (ब्रेकिंग चेंज स्वीकार्य है) + +### मुद्दा #3: हार्डकोडेड कैसेंड्रा कीस्पेस +**वर्तमान:** विभिन्न सेवाओं में कीस्पेस को हार्डकोडेड के रूप में `"config"`, `"knowledge"`, `"librarian"` के रूप में परिभाषित किया गया है +**परिणाम:** मल्टी-टेनेंट डिप्लॉयमेंट के लिए कीस्पेस को अनुकूलित नहीं किया जा सकता है +**प्रभाव:** कॉन्फ़िग, कोर और लाइब्रेरियन सेवाएं +**बाधा:** कई किरायेदार अलग-अलग कैसेंड्रा कीस्पेस का उपयोग नहीं कर सकते हैं + +### मुद्दा #4: कलेक्शन मैनेजमेंट आर्किटेक्चर ✅ पूर्ण +**पिछला:** कलेक्शन को लाइब्रेरियन कीस्पेस में एक अलग कलेक्शन टेबल के माध्यम से संग्रहीत किया जाता था +**पिछला:** लाइब्रेरियन ने कलेक्शन बनाने/हटाने के लिए 4 हार्डकोडेड स्टोरेज मैनेजमेंट टॉपिक का उपयोग किया: + `vector_storage_management_topic` + `object_storage_management_topic` + `triples_storage_management_topic` + `storage_management_response_topic` +**समस्याएं (हल की गई):** + हार्डकोडेड टॉपिक को मल्टी-टेनेंट डिप्लॉयमेंट के लिए अनुकूलित नहीं किया जा सकता था + लाइब्रेरियन और 4+ स्टोरेज सेवाओं के बीच जटिल एसिंक्रोनस समन्वय + अलग कैसेंड्रा टेबल और प्रबंधन अवसंरचना + महत्वपूर्ण कार्यों के लिए गैर-स्थायी अनुरोध/प्रतिक्रिया कतारें +**कार्यान्वित समाधान:** कलेक्शन को कॉन्फ़िग सर्विस स्टोरेज में माइग्रेट किया गया, वितरण के लिए कॉन्फ़िग पुश का उपयोग किया गया +**स्थिति:** सभी स्टोरेज बैकएंड को `CollectionConfigHandler` पैटर्न में माइग्रेट किया गया है + +## समाधान + +यह विनिर्देश मुद्दों #1, #2, #3 और #4 को संबोधित करता है। + +### भाग 1: पैरामीटर नाम बेमेल को ठीक करें + +#### परिवर्तन 1: AsyncProcessor बेस क्लास - CLI पैरामीटर का नाम बदलें +**फ़ाइल:** `trustgraph-base/trustgraph/base/async_processor.py` +**पंक्ति:** 260-264 + +**वर्तमान:** +```python +parser.add_argument( + '--config-queue', + default=default_config_queue, + help=f'Config push queue {default_config_queue}', +) +``` + +**निश्चित:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_queue, + help=f'Config push queue (default: {default_config_queue})', +) +``` + +**तर्क:** +अधिक स्पष्ट और विस्तृत नामकरण +आंतरिक चर नाम से मेल खाता है `config_push_queue` +परिवर्तन स्वीकार्य है क्योंकि सुविधा वर्तमान में गैर-कार्यात्मक है +params.get() में कोई कोड परिवर्तन आवश्यक नहीं है - यह पहले से ही सही नाम की तलाश करता है + +#### परिवर्तन 2: कॉन्फ़िगरेशन सेवा - CLI पैरामीटर का नाम बदलें +**फ़ाइल:** `trustgraph-flow/trustgraph/config/service/service.py` +**पंक्ति:** 276-279 + +**वर्तमान:** +```python +parser.add_argument( + '--push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**निश्चित:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**तर्क:** +अधिक स्पष्ट नामकरण - "config-push-queue" केवल "push-queue" से अधिक स्पष्ट है। +आंतरिक चर नाम `config_push_queue` से मेल खाता है। +AsyncProcessor के `--config-push-queue` पैरामीटर के साथ संगत। +परिवर्तन स्वीकार्य है क्योंकि सुविधा वर्तमान में गैर-कार्यात्मक है। +params.get() में कोई कोड परिवर्तन आवश्यक नहीं है - यह पहले से ही सही नाम की तलाश करता है। + +### भाग 2: कैसेंड्रा कीस्पेस पैरामीटराइज़ेशन जोड़ें + +#### परिवर्तन 3: cassandra_config मॉड्यूल में कीस्पेस पैरामीटर जोड़ें +**फ़ाइल:** `trustgraph-base/trustgraph/base/cassandra_config.py` + +**CLI तर्क जोड़ें** (`add_cassandra_args()` फ़ंक्शन में): +```python +parser.add_argument( + '--cassandra-keyspace', + default=None, + help='Cassandra keyspace (default: service-specific)' +) +``` + +**पर्यावरण चर समर्थन जोड़ें** (फ़ंक्शन `resolve_cassandra_config()` में): +```python +keyspace = params.get( + "cassandra_keyspace", + os.environ.get("CASSANDRA_KEYSPACE") +) +``` + +**`resolve_cassandra_config()` का रिटर्न वैल्यू अपडेट करें:** +वर्तमान में रिटर्न करता है: `(hosts, username, password)` +बदलने पर रिटर्न करेगा: `(hosts, username, password, keyspace)` + +**तर्क:** +मौजूदा कैसेंड्रा कॉन्फ़िगरेशन पैटर्न के अनुरूप +`add_cassandra_args()` के माध्यम से सभी सेवाओं के लिए उपलब्ध +CLI और पर्यावरण चर कॉन्फ़िगरेशन दोनों का समर्थन करता है + +#### परिवर्तन 4: कॉन्फ़िगरेशन सर्विस - पैरामीटराइज़्ड कीस्पेस का उपयोग करें +**फ़ाइल:** `trustgraph-flow/trustgraph/config/service/service.py` + +**पंक्ति 30** - हार्डकोडेड कीस्पेस हटाएं: +```python +# DELETE THIS LINE: +keyspace = "config" +``` + +**पंक्तियाँ 69-73** - कैसेंड्रा कॉन्फ़िगरेशन रिज़ॉल्यूशन को अपडेट करें: + +**वर्तमान:** +```python +cassandra_host, cassandra_username, cassandra_password = \ + resolve_cassandra_config(params) +``` + +**निश्चित:** +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="config") +``` + +**तर्क:** +"config" को डिफ़ॉल्ट के रूप में रखते हुए पिछली अनुकूलता बनाए रखता है। +`--cassandra-keyspace` या `CASSANDRA_KEYSPACE` के माध्यम से ओवरराइड करने की अनुमति देता है। + +#### परिवर्तन 5: कोर/नॉलेज सर्विस - पैरामीटराइज़्ड कीस्पेस का उपयोग करें। +**फ़ाइल:** `trustgraph-flow/trustgraph/cores/service.py` + +**पंक्ति 37** - हार्डकोडेड कीस्पेस को हटाएँ: +```python +# DELETE THIS LINE: +keyspace = "knowledge" +``` + +**कैसेंड्रा कॉन्फ़िगरेशन रिज़ॉल्यूशन को अपडेट करें** (कॉन्फ़िगरेशन सेवा के समान स्थान पर): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="knowledge") +``` + +#### परिवर्तन 6: लाइब्रेरियन सेवा - पैरामीटराइज़्ड कीस्पेस का उपयोग करें +**फ़ाइल:** `trustgraph-flow/trustgraph/librarian/service.py` + +**पंक्ति 51** - हार्डकोडेड कीस्पेस हटाएं: +```python +# DELETE THIS LINE: +keyspace = "librarian" +``` + +**कैसेंड्रा कॉन्फ़िगरेशन रिज़ॉल्यूशन को अपडेट करें** (कॉन्फ़िगरेशन सेवा के समान स्थान पर): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="librarian") +``` + +### भाग 3: संग्रह प्रबंधन को कॉन्फ़िगरेशन सेवा में स्थानांतरित करें + +#### अवलोकन +संग्रहों को कैसेंड्रा लाइब्रेरियन कीस्पेस से कॉन्फ़िगरेशन सेवा भंडारण में स्थानांतरित करें। यह हार्ड-कोडेड भंडारण प्रबंधन विषयों को समाप्त करता है और मौजूदा कॉन्फ़िगरेशन पुश तंत्र का उपयोग करके वितरण के लिए वास्तुकला को सरल बनाता है। + +#### वर्तमान वास्तुकला +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Cassandra Collections Table (librarian keyspace) + ↓ + Broadcast to 4 Storage Management Topics (hardcoded) + ↓ + Wait for 4+ Storage Service Responses + ↓ + Response to Gateway +``` + +#### नई वास्तुकला +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Config Service API (put/delete/getvalues) + ↓ + Cassandra Config Table (class='collections', key='user:collection') + ↓ + Config Push (to all subscribers on config-push-queue) + ↓ + All Storage Services receive config update independently +``` + +#### परिवर्तन 7: संग्रह प्रबंधक - कॉन्फ़िगरेशन सेवा एपीआई का उपयोग करें +**फ़ाइल:** `trustgraph-flow/trustgraph/librarian/collection_manager.py` + +**हटाएं:** +`LibraryTableStore` का उपयोग (पंक्तियाँ 33, 40-41) +स्टोरेज प्रबंधन उत्पादकों का आरंभीकरण (पंक्तियाँ 86-140) +`on_storage_response` विधि (पंक्तियाँ 400-430) +`pending_deletions` ट्रैकिंग (पंक्तियाँ 57, 90-96, और पूरे में उपयोग) + +**जोड़ें:** +एपीआई कॉल के लिए कॉन्फ़िगरेशन सेवा क्लाइंट (अनुरोध/प्रतिक्रिया पैटर्न) + +**कॉन्फ़िगरेशन क्लाइंट सेटअप:** +```python +# In __init__, add config request/response producers/consumers +from trustgraph.schema.services.config import ConfigRequest, ConfigResponse + +# Producer for config requests +self.config_request_producer = Producer( + client=pulsar_client, + topic=config_request_queue, + schema=ConfigRequest, +) + +# Consumer for config responses (with correlation ID) +self.config_response_consumer = Consumer( + taskgroup=taskgroup, + client=pulsar_client, + flow=None, + topic=config_response_queue, + subscriber=f"{id}-config", + schema=ConfigResponse, + handler=self.on_config_response, +) + +# Tracking for pending config requests +self.pending_config_requests = {} # request_id -> asyncio.Event +``` + +**`list_collections` को संशोधित करें (पंक्तियाँ 145-180):** +```python +async def list_collections(self, user, tag_filter=None, limit=None): + """List collections from config service""" + # Send getvalues request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='getvalues', + type='collections', + ) + + # Send request and wait for response + response = await self.send_config_request(request) + + # Parse collections from response + collections = [] + for key, value_json in response.values.items(): + if ":" in key: + coll_user, collection = key.split(":", 1) + if coll_user == user: + metadata = json.loads(value_json) + collections.append(CollectionMetadata(**metadata)) + + # Apply tag filtering in-memory (as before) + if tag_filter: + collections = [c for c in collections if any(tag in c.tags for tag in tag_filter)] + + # Apply limit + if limit: + collections = collections[:limit] + + return collections + +async def send_config_request(self, request): + """Send config request and wait for response""" + event = asyncio.Event() + self.pending_config_requests[request.id] = event + + await self.config_request_producer.send(request) + await event.wait() + + return self.pending_config_requests.pop(request.id + "_response") + +async def on_config_response(self, message, consumer, flow): + """Handle config response""" + response = message.value() + if response.id in self.pending_config_requests: + self.pending_config_requests[response.id + "_response"] = response + self.pending_config_requests[response.id].set() +``` + +**`update_collection` को संशोधित करें (पंक्तियाँ 182-312):** +```python +async def update_collection(self, user, collection, name, description, tags): + """Update collection via config service""" + # Create metadata + metadata = CollectionMetadata( + user=user, + collection=collection, + name=name, + description=description, + tags=tags, + ) + + # Send put request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='put', + type='collections', + key=f'{user}:{collection}', + value=json.dumps(metadata.to_dict()), + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config update failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and create collections +``` + +**`delete_collection` में संशोधन करें (पंक्तियाँ 314-398):** +```python +async def delete_collection(self, user, collection): + """Delete collection via config service""" + # Send delete request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='delete', + type='collections', + key=f'{user}:{collection}', + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config delete failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and delete collections +``` + +**संग्रह मेटाडेटा प्रारूप:** +कॉन्फ़िगरेशन तालिका में इस प्रकार संग्रहीत: `class='collections', key='user:collection'` +मान JSON-सीरियलाइज़्ड CollectionMetadata है (समय-मुद्रांकन फ़ील्ड के बिना) +फ़ील्ड: `user`, `collection`, `name`, `description`, `tags` +उदाहरण: `class='collections', key='alice:my-docs', value='{"user":"alice","collection":"my-docs","name":"My Documents","description":"...","tags":["work"]}'` + +#### परिवर्तन 8: लाइब्रेरियन सेवा - स्टोरेज मैनेजमेंट इंफ्रास्ट्रक्चर को हटाएं +**फ़ाइल:** `trustgraph-flow/trustgraph/librarian/service.py` + +**हटाएं:** +स्टोरेज मैनेजमेंट प्रोड्यूसर (पंक्ति 173-190): + `vector_storage_management_producer` + `object_storage_management_producer` + `triples_storage_management_producer` +स्टोरेज रिस्पांस कंज्यूमर (पंक्ति 192-201) +`on_storage_response` हैंडलर (पंक्ति 467-473) + +**संशोधित करें:** +CollectionManager इनिशियलाइज़ेशन (पंक्ति 215-224) - स्टोरेज प्रोड्यूसर पैरामीटर हटाएं + +**ध्यान दें:** बाहरी संग्रह एपीआई अपरिवर्तित रहता है: +`list-collections` +`update-collection` +`delete-collection` + +#### परिवर्तन 9: LibraryTableStore से Collections टेबल को हटाएं +**फ़ाइल:** `trustgraph-flow/trustgraph/tables/library.py` + +**हटाएं:** +Collections टेबल CREATE स्टेटमेंट (पंक्ति 114-127) +Collections तैयार स्टेटमेंट (पंक्ति 205-240) +सभी संग्रह विधियाँ (पंक्ति 578-717): + `ensure_collection_exists` + `list_collections` + `update_collection` + `delete_collection` + `get_collection` + `create_collection` + +**तर्क:** +संग्रह अब कॉन्फ़िगरेशन तालिका में संग्रहीत हैं। +परिवर्तन स्वीकार्य है - डेटा माइग्रेशन की आवश्यकता नहीं है। +लाइब्रेरियन सेवा को काफी सरल बनाता है। + +#### परिवर्तन 10: स्टोरेज सेवाएं - कॉन्फ़िगरेशन-आधारित संग्रह प्रबंधन ✅ पूर्ण + +**स्थिति:** सभी 11 स्टोरेज बैकएंड को `CollectionConfigHandler` का उपयोग करने के लिए माइग्रेट किया गया है। + +**प्रभावित सेवाएं (कुल 11):** +दस्तावेज़ एम्बेडिंग: मिलवस, पाइनकोन, क्यूड्रांट +ग्राफ एम्बेडिंग: मिलवस, पाइनकोन, क्यूड्रांट +ऑब्जेक्ट स्टोरेज: कैसेंड्रा +ट्रिपल स्टोरेज: कैसेंड्रा, फाल्कोडीबी, मेमग्राफ, नियो4जे + +**फाइलें:** +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +`trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +`trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` + +**कार्यान्वयन पैटर्न (सभी सेवाएं):** + +1. **`__init__` में कॉन्फ़िगरेशन हैंडलर पंजीकृत करें:** +```python +# Add after AsyncProcessor initialization +self.register_config_handler(self.on_collection_config) +self.known_collections = set() # Track (user, collection) tuples +``` + +2. **कॉन्फ़िगरेशन हैंडलर को लागू करें:** +```python +async def on_collection_config(self, config, version): + """Handle collection configuration updates""" + logger.info(f"Collection config version: {version}") + + if "collections" not in config: + return + + # Parse collections from config + # Key format: "user:collection" in config["collections"] + config_collections = set() + for key in config["collections"].keys(): + if ":" in key: + user, collection = key.split(":", 1) + config_collections.add((user, collection)) + + # Determine changes + to_create = config_collections - self.known_collections + to_delete = self.known_collections - config_collections + + # Create new collections (idempotent) + for user, collection in to_create: + try: + await self.create_collection_internal(user, collection) + self.known_collections.add((user, collection)) + logger.info(f"Created collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to create {user}/{collection}: {e}") + + # Delete removed collections (idempotent) + for user, collection in to_delete: + try: + await self.delete_collection_internal(user, collection) + self.known_collections.discard((user, collection)) + logger.info(f"Deleted collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to delete {user}/{collection}: {e}") +``` + +3. **प्रारंभ में ज्ञात संग्रहों को आरंभीकृत करें:** +```python +async def start(self): + """Start the processor""" + await super().start() + await self.sync_known_collections() + +async def sync_known_collections(self): + """Query backend to populate known_collections set""" + # Backend-specific implementation: + # - Milvus/Pinecone/Qdrant: List collections/indexes matching naming pattern + # - Cassandra: Query keyspaces or collection metadata + # - Neo4j/Memgraph/FalkorDB: Query CollectionMetadata nodes + pass +``` + +4. **मौजूदा हैंडलर विधियों को पुनर्गठित करें:** +```python +# Rename and remove response sending: +# handle_create_collection → create_collection_internal +# handle_delete_collection → delete_collection_internal + +async def create_collection_internal(self, user, collection): + """Create collection (idempotent)""" + # Same logic as current handle_create_collection + # But remove response producer calls + # Handle "already exists" gracefully + pass + +async def delete_collection_internal(self, user, collection): + """Delete collection (idempotent)""" + # Same logic as current handle_delete_collection + # But remove response producer calls + # Handle "not found" gracefully + pass +``` + +5. **भंडारण प्रबंधन अवसंरचना को हटाएं:** + `self.storage_request_consumer` सेटअप और प्रारंभ को हटाएं + `self.storage_response_producer` सेटअप को हटाएं + `on_storage_management` डिस्पैचर विधि को हटाएं + भंडारण प्रबंधन के लिए मेट्रिक्स को हटाएं + इम्पोर्ट को हटाएं: `StorageManagementRequest`, `StorageManagementResponse` + +**बैकएंड-विशिष्ट विचार:** + +**वेक्टर स्टोर (मिलवस, पाइनकोन, क्यूड्रांट):** `known_collections` में लॉजिकल `(user, collection)` को ट्रैक करें, लेकिन प्रत्येक आयाम के लिए कई बैकएंड संग्रह बनाए जा सकते हैं। आलसी निर्माण पैटर्न जारी रखें। हटाने के कार्यों को सभी आयाम वेरिएंट को हटाना चाहिए। + +**कैसेंड्रा ऑब्जेक्ट्स:** संग्रह पंक्ति गुण हैं, संरचनाएं नहीं। कीस्पेस-स्तरीय जानकारी को ट्रैक करें। + +**ग्राफ स्टोर (नियो4जे, मेमग्राफ, फाल्कोर्डबी):** स्टार्टअप पर `CollectionMetadata` नोड्स को क्वेरी करें। सिंक पर मेटाडेटा नोड्स बनाएं/हटाएं। + +**कैसेंड्रा ट्रिपल्स:** संग्रह संचालन के लिए `KnowledgeGraph` एपीआई का उपयोग करें। + +**मुख्य डिज़ाइन बिंदु:** + +**अंतिम स्थिरता:** कोई अनुरोध/प्रतिक्रिया तंत्र नहीं, कॉन्फ़िगरेशन पुश प्रसारित किया जाता है +**अपरिवर्तनीयता:** सभी निर्माण/हटाने के संचालन को पुनः प्रयास करना सुरक्षित होना चाहिए +**त्रुटि प्रबंधन:** त्रुटियों को लॉग करें लेकिन कॉन्फ़िगरेशन अपडेट को अवरुद्ध न करें +**स्व-सुधार:** विफल संचालन अगले कॉन्फ़िगरेशन पुश पर पुनः प्रयास करेंगे +**संग्रह कुंजी प्रारूप:** `config["collections"]` में `"user:collection"` + +#### परिवर्तन 11: संग्रह स्कीमा अपडेट करें - टाइमस्टैम्प हटाएं +**फ़ाइल:** `trustgraph-base/trustgraph/schema/services/collection.py` + +**संग्रहMetadata (पंक्ति 13-21) को संशोधित करें:** +`created_at` और `updated_at` फ़ील्ड को हटाएं: +```python +class CollectionMetadata(Record): + user = String() + collection = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() +``` + +**कलेक्शनमैनेजमेंट रिक्वेस्ट में बदलाव (पंक्ति 25-47):** +टाइमस्टैम्प फ़ील्ड हटाएं: +```python +class CollectionManagementRequest(Record): + operation = String() + user = String() + collection = String() + timestamp = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() + tag_filter = Array(String()) + limit = Integer() +``` + +**तर्क:** +टाइमस्टैम्प संग्रह के लिए कोई मूल्य नहीं जोड़ते हैं। +कॉन्फ़िगरेशन सेवा अपनी संस्करण ट्रैकिंग बनाए रखती है। +स्कीमा को सरल बनाता है और भंडारण को कम करता है। + +#### कॉन्फ़िगरेशन सेवा माइग्रेशन के लाभ + +1. ✅ **हार्डकोडेड स्टोरेज प्रबंधन विषयों को समाप्त करता है** - मल्टी-टेनेंट अवरोध को हल करता है। +2. ✅ **सरल समन्वय** - 4+ स्टोरेज प्रतिक्रियाओं के लिए कोई जटिल एसिंक्रोनस प्रतीक्षा नहीं। +3. ✅ **अंतिम स्थिरता** - स्टोरेज सेवाएं कॉन्फ़िगरेशन पुश के माध्यम से स्वतंत्र रूप से अपडेट करती हैं। +4. ✅ **बेहतर विश्वसनीयता** - गैर-स्थायी अनुरोध/प्रतिक्रिया के विपरीत, लगातार कॉन्फ़िगरेशन पुश। +5. ✅ **एकीकृत कॉन्फ़िगरेशन मॉडल** - संग्रह को कॉन्फ़िगरेशन के रूप में माना जाता है। +6. ✅ **जटिलता को कम करता है** - ~300 लाइनों के समन्वय कोड को हटाता है। +7. ✅ **मल्टी-टेनेंट के लिए तैयार** - कॉन्फ़िगरेशन पहले से ही कीस्पेस के माध्यम से किरायेदार अलगाव का समर्थन करता है। +8. ✅ **संस्करण ट्रैकिंग** - कॉन्फ़िगरेशन सेवा संस्करण तंत्र ऑडिट ट्रेल प्रदान करता है। + +## कार्यान्वयन नोट्स + +### पिछड़ा संगतता + +**पैरामीटर परिवर्तन:** +CLI पैरामीटर का नाम बदलना एक ब्रेकिंग परिवर्तन है लेकिन स्वीकार्य है (फ़ीचर वर्तमान में गैर-कार्यात्मक है)। +सेवाएं पैरामीटर के बिना काम करती हैं (डिफ़ॉल्ट का उपयोग करें)। +डिफ़ॉल्ट कीस्पेस संरक्षित हैं: "config", "knowledge", "librarian" +डिफ़ॉल्ट कतार: `persistent://tg/config/config` + +**संग्रह प्रबंधन:** +**ब्रेकिंग परिवर्तन:** लाइब्रेरियन कीस्पेस से संग्रह तालिका हटा दी गई है। +**कोई डेटा माइग्रेशन प्रदान नहीं किया गया है** - इस चरण के लिए स्वीकार्य है। +बाहरी संग्रह API अपरिवर्तित है (सूची/अपडेट/हटाने के संचालन)। +संग्रह मेटाडेटा प्रारूप को सरल बनाया गया है (टाइमस्टैम्प हटा दिए गए हैं)। + +### परीक्षण आवश्यकताएँ + +**पैरामीटर परीक्षण:** +1. सत्यापित करें कि `--config-push-queue` पैरामीटर ग्राफ-एम्बेडिंग सेवा पर काम करता है। +2. सत्यापित करें कि `--config-push-queue` पैरामीटर टेक्स्ट-कंप्लीशन सेवा पर काम करता है। +3. सत्यापित करें कि `--config-push-queue` पैरामीटर कॉन्फ़िगरेशन सेवा पर काम करता है। +4. सत्यापित करें कि `--cassandra-keyspace` पैरामीटर कॉन्फ़िगरेशन सेवा के लिए काम करता है। +5. सत्यापित करें कि `--cassandra-keyspace` पैरामीटर कोर सेवा के लिए काम करता है। +6. सत्यापित करें कि `--cassandra-keyspace` पैरामीटर लाइब्रेरियन सेवा के लिए काम करता है। +7. सत्यापित करें कि सेवाएं पैरामीटर के बिना काम करती हैं (डिफ़ॉल्ट का उपयोग करती हैं)। +8. कस्टम कतार नामों और कीस्पेस के साथ मल्टी-टेनेंट परिनियोजन सत्यापित करें। + +**संग्रह प्रबंधन परीक्षण:** +9. कॉन्फ़िगरेशन सेवा के माध्यम से `list-collections` ऑपरेशन सत्यापित करें। +10. सत्यापित करें कि `update-collection` कॉन्फ़िगरेशन तालिका में बनाता/अपडेट करता है। +11. सत्यापित करें कि `delete-collection` कॉन्फ़िगरेशन तालिका से हटाता है। +12. सत्यापित करें कि संग्रह अपडेट पर कॉन्फ़िगरेशन पुश ट्रिगर होता है। +13. सत्यापित करें कि कॉन्फ़िगरेशन-आधारित स्टोरेज के साथ टैग फ़िल्टरिंग काम करता है। +14. सत्यापित करें कि संग्रह ऑपरेशन टाइमस्टैम्प फ़ील्ड के बिना काम करते हैं। + +### मल्टी-टेनेंट परिनियोजन उदाहरण +```bash +# Tenant: tg-dev +graph-embeddings \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config + +config-service \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config \ + --cassandra-keyspace tg_dev_config +``` + +## प्रभाव विश्लेषण + +### परिवर्तन 1-2 से प्रभावित सेवाएं (CLI पैरामीटर का नाम बदलना) +सभी सेवाएं जो AsyncProcessor या FlowProcessor से विरासत में मिली हैं: +config-service +cores-service +librarian-service +graph-embeddings +document-embeddings +text-completion-* (सभी प्रदाता) +extract-* (सभी एक्सट्रैक्टर) +query-* (सभी क्वेरी सेवाएं) +retrieval-* (सभी RAG सेवाएं) +storage-* (सभी स्टोरेज सेवाएं) +और 20+ से अधिक सेवाएं + +### परिवर्तन 3-6 से प्रभावित सेवाएं (कैसेंड्रा कीस्पेस) +config-service +cores-service +librarian-service + +### परिवर्तन 7-11 से प्रभावित सेवाएं (संग्रह प्रबंधन) + +**तत्काल परिवर्तन:** +librarian-service (collection_manager.py, service.py) +tables/library.py (संग्रह तालिका को हटाना) +schema/services/collection.py (टाइमस्टैम्प को हटाना) + +**पूरे हुए परिवर्तन (परिवर्तन 10):** ✅ +सभी स्टोरेज सेवाएं (कुल 11) - संग्रह अपडेट के लिए कॉन्फ़िगरेशन पुश के माध्यम से `CollectionConfigHandler` में माइग्रेट किया गया +`storage.py` से स्टोरेज प्रबंधन स्कीमा को हटाया गया + +## भविष्य के विचार + +### प्रति-उपयोगकर्ता कीस्पेस मॉडल + +कुछ सेवाएं **प्रति-उपयोगकर्ता कीस्पेस** गतिशील रूप से उपयोग करती हैं, जहां प्रत्येक उपयोगकर्ता का अपना कैसेंड्रा कीस्पेस होता है: + +**प्रति-उपयोगकर्ता कीस्पेस वाली सेवाएं:** +1. **ट्रिपल्स क्वेरी सर्विस** (`trustgraph-flow/trustgraph/query/triples/cassandra/service.py:65`) + `keyspace=query.user` का उपयोग करता है +2. **ऑब्जेक्ट्स क्वेरी सर्विस** (`trustgraph-flow/trustgraph/query/objects/cassandra/service.py:479`) + `keyspace=self.sanitize_name(user)` का उपयोग करता है +3. **नॉलेज ग्राफ डायरेक्ट एक्सेस** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py:18`) + डिफ़ॉल्ट पैरामीटर `keyspace="trustgraph"` + +**स्थिति:** ये इस विनिर्देश में **बदले नहीं गए** हैं। + +**भविष्य की समीक्षा आवश्यक:** +मूल्यांकन करें कि क्या प्रति-उपयोगकर्ता कीस्पेस मॉडल किरायेदार अलगाव के मुद्दे बनाता है +इस पर विचार करें कि क्या मल्टी-टेनेन्ट डिप्लॉयमेंट को कीस्पेस उपसर्ग पैटर्न (जैसे, `tenant_a_user1`) की आवश्यकता है +किरायेदारों में संभावित उपयोगकर्ता आईडी टकराव के लिए समीक्षा करें +मूल्यांकन करें कि क्या प्रति किरायेदार एकल साझा कीस्पेस उपयोगकर्ता-आधारित पंक्ति अलगाव के साथ अधिक उपयुक्त है + +**नोट:** यह वर्तमान मल्टी-टेनेन्ट कार्यान्वयन को अवरुद्ध नहीं करता है, लेकिन उत्पादन मल्टी-टेनेन्ट डिप्लॉयमेंट से पहले इसकी समीक्षा की जानी चाहिए। + +## कार्यान्वयन चरण + +### चरण 1: पैरामीटर सुधार (परिवर्तन 1-6) +`--config-push-queue` पैरामीटर नामकरण को ठीक करें +`--cassandra-keyspace` पैरामीटर समर्थन जोड़ें +**परिणाम:** मल्टी-टेनेन्ट कतार और कीस्पेस कॉन्फ़िगरेशन सक्षम + +### चरण 2: संग्रह प्रबंधन माइग्रेशन (परिवर्तन 7-9, 11) +संग्रह स्टोरेज को कॉन्फ़िगरेशन सेवा में माइग्रेट करें +लाइब्रेरियन से संग्रह तालिका को हटा दें +संग्रह स्कीमा को अपडेट करें (टाइमस्टैम्प हटाएं) +**परिणाम:** हार्डकोडेड स्टोरेज प्रबंधन विषयों को समाप्त करता है, लाइब्रेरियन को सरल बनाता है + +### चरण 3: स्टोरेज सर्विस अपडेट (परिवर्तन 10) ✅ पूर्ण +सभी स्टोरेज सेवाओं को `CollectionConfigHandler` के माध्यम से संग्रह के लिए कॉन्फ़िगरेशन पुश का उपयोग करने के लिए अपडेट किया गया +स्टोरेज प्रबंधन अनुरोध/प्रतिक्रिया बुनियादी ढांचे को हटा दिया गया +विरासत स्कीमा परिभाषाओं को हटा दिया गया +**परिणाम:** कॉन्फ़िगरेशन-आधारित संग्रह प्रबंधन प्राप्त हुआ + +## संदर्भ +GitHub मुद्दा: https://github.com/trustgraph-ai/trustgraph/issues/582 +संबंधित फाइलें: + `trustgraph-base/trustgraph/base/async_processor.py` + `trustgraph-base/trustgraph/base/cassandra_config.py` + `trustgraph-base/trustgraph/schema/core/topic.py` + `trustgraph-base/trustgraph/schema/services/collection.py` + `trustgraph-flow/trustgraph/config/service/service.py` + `trustgraph-flow/trustgraph/cores/service.py` + `trustgraph-flow/trustgraph/librarian/service.py` + `trustgraph-flow/trustgraph/librarian/collection_manager.py` + `trustgraph-flow/trustgraph/tables/library.py` diff --git a/docs/tech-specs/multi-tenant-support.pt.md b/docs/tech-specs/multi-tenant-support.pt.md new file mode 100644 index 00000000..daa3193c --- /dev/null +++ b/docs/tech-specs/multi-tenant-support.pt.md @@ -0,0 +1,772 @@ +# Especificação Técnica: Suporte para Multi-Tenancy + +## Visão Geral + +Habilite implantações multi-tenant corrigindo incompatibilidades de nomes de parâmetros que impedem a personalização da fila e adicionando parametrização do keyspace do Cassandra. + +## Contexto da Arquitetura + +### Resolução de Filas Baseada em Fluxo + +O sistema TrustGraph usa uma **arquitetura baseada em fluxo** para a resolução dinâmica de filas, que suporta inerentemente o multi-tenancy: + +As **Definições de Fluxo** são armazenadas no Cassandra e especificam os nomes das filas por meio de definições de interface. +**Os nomes das filas usam modelos** com variáveis `{id}` que são substituídas pelos IDs das instâncias de fluxo. +**Os serviços resolvem dinamicamente as filas** consultando as configurações de fluxo no momento da solicitação. +**Cada tenant pode ter fluxos únicos** com nomes de fila diferentes, proporcionando isolamento. + +Exemplo de definição de interface de fluxo: +```json +{ + "interfaces": { + "triples-store": "persistent://tg/flow/triples-store:{id}", + "graph-embeddings-store": "persistent://tg/flow/graph-embeddings-store:{id}" + } +} +``` + +Quando o tenant A inicia o fluxo `tenant-a-prod` e o tenant B inicia o fluxo `tenant-b-prod`, eles automaticamente recebem filas isoladas: +`persistent://tg/flow/triples-store:tenant-a-prod` +`persistent://tg/flow/triples-store:tenant-b-prod` + +**Serviços corretamente projetados para multi-tenancy:** +✅ **Knowledge Management (cores)** - Resolve dinamicamente as filas a partir da configuração do fluxo passada nas requisições + +**Serviços que precisam de correções:** +🔴 **Config Service** - Incompatibilidade no nome do parâmetro impede a personalização da fila +🔴 **Librarian Service** - Tópicos de gerenciamento de armazenamento codificados (discutido abaixo) +🔴 **Todos os Serviços** - Não é possível personalizar o keyspace do Cassandra + +## Declaração do Problema + +### Problema #1: Incompatibilidade no Nome do Parâmetro no AsyncProcessor +**CLI define:** `--config-queue` (nomeação pouco clara) +**Argparse converte para:** `config_queue` (no dicionário de parâmetros) +**Código procura por:** `config_push_queue` +**Resultado:** O parâmetro é ignorado, usa o valor padrão de `persistent://tg/config/config` +**Impacto:** Afeta todos os 32+ serviços que herdam do AsyncProcessor +**Bloqueia:** Impossibilita o uso de filas de configuração específicas do tenant em implantações multi-tenant +**Solução:** Renomear o parâmetro da CLI para `--config-push-queue` para maior clareza (alteração disruptiva aceitável, já que o recurso está atualmente com defeito) + +### Problema #2: Incompatibilidade no Nome do Parâmetro no Config Service +**CLI define:** `--push-queue` (nomeação ambígua) +**Argparse converte para:** `push_queue` (no dicionário de parâmetros) +**Código procura por:** `config_push_queue` +**Resultado:** O parâmetro é ignorado +**Impacto:** O Config service não pode usar uma fila de push personalizada +**Solução:** Renomear o parâmetro da CLI para `--config-push-queue` para consistência e clareza (alteração disruptiva aceitável) + +### Problema #3: Keyspace do Cassandra Codificado +**Atual:** Keyspace codificado como `"config"`, `"knowledge"`, `"librarian"` em vários serviços +**Resultado:** Impossibilita a personalização do keyspace para implantações multi-tenant +**Impacto:** Serviços Config, cores e librarian +**Bloqueia:** Múltiplos tenants não podem usar keyspaces separados do Cassandra + +### Problema #4: Arquitetura de Gerenciamento de Coleções ✅ CONCLUÍDO +**Anterior:** Coleções armazenadas no keyspace do librarian do Cassandra em uma tabela de coleções separada +**Anterior:** O librarian usava 4 tópicos de gerenciamento de armazenamento codificados para coordenar a criação/exclusão de coleções: + `vector_storage_management_topic` + `object_storage_management_topic` + `triples_storage_management_topic` + `storage_management_response_topic` +**Problemas (Resolvidos):** + Tópicos codificados não podiam ser personalizados para implantações multi-tenant + Coordenação assíncrona complexa entre o librarian e 4+ serviços de armazenamento + Tabela separada do Cassandra e infraestrutura de gerenciamento + Filas de requisição/resposta não persistentes para operações críticas +**Solução Implementada:** Migrou as coleções para o armazenamento do serviço de configuração, usa push de configuração para distribuição +**Status:** Todos os backends de armazenamento migrados para o padrão `CollectionConfigHandler` + +## Solução + +Esta especificação aborda os problemas #1, #2, #3 e #4. + +### Parte 1: Corrigir Incompatibilidades no Nome do Parâmetro + +#### Alteração 1: Classe Base AsyncProcessor - Renomear Parâmetro da CLI +**Arquivo:** `trustgraph-base/trustgraph/base/async_processor.py` +**Linha:** 260-264 + +**Atual:** +```python +parser.add_argument( + '--config-queue', + default=default_config_queue, + help=f'Config push queue {default_config_queue}', +) +``` + +**Corrigido:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_queue, + help=f'Config push queue (default: {default_config_queue})', +) +``` + +**Justificativa:** +Nomenclatura mais clara e explícita +Coincide com o nome da variável interna `config_push_queue` +Mudança disruptiva aceitável, já que a funcionalidade está atualmente inativa +Não é necessária nenhuma alteração no código em params.get() - ele já procura pelo nome correto + +#### Mudança 2: Serviço de Configuração - Renomear Parâmetro da CLI +**Arquivo:** `trustgraph-flow/trustgraph/config/service/service.py` +**Linha:** 276-279 + +**Atual:** +```python +parser.add_argument( + '--push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**Corrigido:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**Justificativa:** +Nomes mais claros - "config-push-queue" é mais explícito do que apenas "push-queue". +Compatível com o nome da variável interna `config_push_queue`. +Consistente com o parâmetro `--config-push-queue` do AsyncProcessor. +Mudança disruptiva aceitável, já que o recurso está atualmente inativo. +Nenhuma alteração de código necessária em params.get() - ele já procura pelo nome correto. + +### Parte 2: Adicionar Parametrização do Keyspace do Cassandra + +#### Mudança 3: Adicionar Parâmetro de Keyspace ao Módulo cassandra_config +**Arquivo:** `trustgraph-base/trustgraph/base/cassandra_config.py` + +**Adicionar argumento de linha de comando** (na função `add_cassandra_args()`): +```python +parser.add_argument( + '--cassandra-keyspace', + default=None, + help='Cassandra keyspace (default: service-specific)' +) +``` + +**Adicionar suporte para variáveis de ambiente** (na função `resolve_cassandra_config()`): +```python +keyspace = params.get( + "cassandra_keyspace", + os.environ.get("CASSANDRA_KEYSPACE") +) +``` + +**Atualizar o valor de retorno** de `resolve_cassandra_config()`: +Atualmente retorna: `(hosts, username, password)` +Alterar para retornar: `(hosts, username, password, keyspace)` + +**Justificativa:** +Consistente com o padrão de configuração existente do Cassandra +Disponível para todos os serviços via `add_cassandra_args()` +Suporta configuração via linha de comando e variáveis de ambiente + +#### Mudança 4: Serviço de Configuração - Usar Keyspace Parametrizados +**Arquivo:** `trustgraph-flow/trustgraph/config/service/service.py` + +**Linha 30** - Remover o keyspace codificado: +```python +# DELETE THIS LINE: +keyspace = "config" +``` + +**Linhas 69-73** - Atualização da resolução da configuração do Cassandra: + +**Atual:** +```python +cassandra_host, cassandra_username, cassandra_password = \ + resolve_cassandra_config(params) +``` + +**Corrigido:** +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="config") +``` + +**Justificativa:** +Mantém a compatibilidade com versões anteriores, utilizando "config" como padrão. +Permite a substituição através de `--cassandra-keyspace` ou `CASSANDRA_KEYSPACE`. + +#### Mudança 5: Cores/Serviço de Conhecimento - Utilizar Chaves de Espaço de Chaves Parametrizadas +**Arquivo:** `trustgraph-flow/trustgraph/cores/service.py` + +**Linha 37** - Remover o espaço de chaves codificado: +```python +# DELETE THIS LINE: +keyspace = "knowledge" +``` + +**Atualização da resolução de configuração do Cassandra** (localização semelhante ao serviço de configuração): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="knowledge") +``` + +#### Mudança 6: Serviço de Bibliotecário - Use Chaves de Espaço de Chaves Parametrizadas +**Arquivo:** `trustgraph-flow/trustgraph/librarian/service.py` + +**Linha 51** - Remova a chave de espaço de chaves codificada: +```python +# DELETE THIS LINE: +keyspace = "librarian" +``` + +**Atualização da resolução de configuração do Cassandra** (localização semelhante ao serviço de configuração): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="librarian") +``` + +### Parte 3: Migrar o Gerenciamento de Coleções para o Serviço de Configuração + +#### Visão Geral +Migrar as coleções do keyspace do Cassandra librarian para o armazenamento do serviço de configuração. Isso elimina os tópicos de gerenciamento de armazenamento codificados e simplifica a arquitetura, utilizando o mecanismo de push de configuração existente para distribuição. + +#### Arquitetura Atual +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Cassandra Collections Table (librarian keyspace) + ↓ + Broadcast to 4 Storage Management Topics (hardcoded) + ↓ + Wait for 4+ Storage Service Responses + ↓ + Response to Gateway +``` + +#### Nova Arquitetura +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Config Service API (put/delete/getvalues) + ↓ + Cassandra Config Table (class='collections', key='user:collection') + ↓ + Config Push (to all subscribers on config-push-queue) + ↓ + All Storage Services receive config update independently +``` + +#### Mudança 7: Gerenciador de Coleções - Usar API do Serviço de Configuração +**Arquivo:** `trustgraph-flow/trustgraph/librarian/collection_manager.py` + +**Remover:** +Uso de `LibraryTableStore` (Linhas 33, 40-41) +Inicialização de produtores de gerenciamento de armazenamento (Linhas 86-140) +Método `on_storage_response` (Linhas 400-430) +Rastreamento de `pending_deletions` (Linhas 57, 90-96 e uso em todo o código) + +**Adicionar:** +Cliente do serviço de configuração para chamadas de API (padrão de solicitação/resposta) + +**Configuração do Cliente:** +```python +# In __init__, add config request/response producers/consumers +from trustgraph.schema.services.config import ConfigRequest, ConfigResponse + +# Producer for config requests +self.config_request_producer = Producer( + client=pulsar_client, + topic=config_request_queue, + schema=ConfigRequest, +) + +# Consumer for config responses (with correlation ID) +self.config_response_consumer = Consumer( + taskgroup=taskgroup, + client=pulsar_client, + flow=None, + topic=config_response_queue, + subscriber=f"{id}-config", + schema=ConfigResponse, + handler=self.on_config_response, +) + +# Tracking for pending config requests +self.pending_config_requests = {} # request_id -> asyncio.Event +``` + +**Modificar `list_collections` (Linhas 145-180):** +```python +async def list_collections(self, user, tag_filter=None, limit=None): + """List collections from config service""" + # Send getvalues request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='getvalues', + type='collections', + ) + + # Send request and wait for response + response = await self.send_config_request(request) + + # Parse collections from response + collections = [] + for key, value_json in response.values.items(): + if ":" in key: + coll_user, collection = key.split(":", 1) + if coll_user == user: + metadata = json.loads(value_json) + collections.append(CollectionMetadata(**metadata)) + + # Apply tag filtering in-memory (as before) + if tag_filter: + collections = [c for c in collections if any(tag in c.tags for tag in tag_filter)] + + # Apply limit + if limit: + collections = collections[:limit] + + return collections + +async def send_config_request(self, request): + """Send config request and wait for response""" + event = asyncio.Event() + self.pending_config_requests[request.id] = event + + await self.config_request_producer.send(request) + await event.wait() + + return self.pending_config_requests.pop(request.id + "_response") + +async def on_config_response(self, message, consumer, flow): + """Handle config response""" + response = message.value() + if response.id in self.pending_config_requests: + self.pending_config_requests[response.id + "_response"] = response + self.pending_config_requests[response.id].set() +``` + +**Modificar `update_collection` (Linhas 182-312):** +```python +async def update_collection(self, user, collection, name, description, tags): + """Update collection via config service""" + # Create metadata + metadata = CollectionMetadata( + user=user, + collection=collection, + name=name, + description=description, + tags=tags, + ) + + # Send put request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='put', + type='collections', + key=f'{user}:{collection}', + value=json.dumps(metadata.to_dict()), + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config update failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and create collections +``` + +**Modificar `delete_collection` (Linhas 314-398):** +```python +async def delete_collection(self, user, collection): + """Delete collection via config service""" + # Send delete request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='delete', + type='collections', + key=f'{user}:{collection}', + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config delete failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and delete collections +``` + +**Formato de Metadados de Coleção:** +Armazenado na tabela de configuração como: `class='collections', key='user:collection'` +O valor é uma CollectionMetadata serializada em JSON (sem campos de timestamp) +Campos: `user`, `collection`, `name`, `description`, `tags` +Exemplo: `class='collections', key='alice:my-docs', value='{"user":"alice","collection":"my-docs","name":"My Documents","description":"...","tags":["work"]}'` + +#### Mudança 8: Serviço de Bibliotecário - Remover a Infraestrutura de Gerenciamento de Armazenamento +**Arquivo:** `trustgraph-flow/trustgraph/librarian/service.py` + +**Remover:** +Produtores de gerenciamento de armazenamento (Linhas 173-190): + `vector_storage_management_producer` + `object_storage_management_producer` + `triples_storage_management_producer` +Consumidor de resposta de armazenamento (Linhas 192-201) +Manipulador `on_storage_response` (Linhas 467-473) + +**Modificar:** +Inicialização do CollectionManager (Linhas 215-224) - remover os parâmetros do produtor de armazenamento + +**Observação:** A API externa de coleções permanece inalterada: +`list-collections` +`update-collection` +`delete-collection` + +#### Mudança 9: Remover a Tabela de Coleções do LibraryTableStore +**Arquivo:** `trustgraph-flow/trustgraph/tables/library.py` + +**Excluir:** +Instrução CREATE da tabela de coleções (Linhas 114-127) +Prepared statements de coleções (Linhas 205-240) +Todos os métodos de coleção (Linhas 578-717): + `ensure_collection_exists` + `list_collections` + `update_collection` + `delete_collection` + `get_collection` + `create_collection` + +**Justificativa:** +As coleções agora são armazenadas na tabela de configuração +Mudança disruptiva aceitável - nenhuma migração de dados necessária +Simplifica significativamente o serviço de bibliotecário + +#### Mudança 10: Serviços de Armazenamento - Gerenciamento de Coleção Baseado em Configuração ✅ CONCLUÍDO + +**Status:** Todos os 11 backends de armazenamento foram migrados para usar `CollectionConfigHandler`. + +**Serviços Afetados (11 no total):** +Embeddings de documentos: milvus, pinecone, qdrant +Embeddings de grafos: milvus, pinecone, qdrant +Armazenamento de objetos: cassandra +Armazenamento de triplas: cassandra, falkordb, memgraph, neo4j + +**Arquivos:** +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +`trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +`trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` + +**Padrão de Implementação (todos os serviços):** + +1. **Registrar o manipulador de configuração em `__init__`:** +```python +# Add after AsyncProcessor initialization +self.register_config_handler(self.on_collection_config) +self.known_collections = set() # Track (user, collection) tuples +``` + +2. **Implementar o gerenciador de configuração:** +```python +async def on_collection_config(self, config, version): + """Handle collection configuration updates""" + logger.info(f"Collection config version: {version}") + + if "collections" not in config: + return + + # Parse collections from config + # Key format: "user:collection" in config["collections"] + config_collections = set() + for key in config["collections"].keys(): + if ":" in key: + user, collection = key.split(":", 1) + config_collections.add((user, collection)) + + # Determine changes + to_create = config_collections - self.known_collections + to_delete = self.known_collections - config_collections + + # Create new collections (idempotent) + for user, collection in to_create: + try: + await self.create_collection_internal(user, collection) + self.known_collections.add((user, collection)) + logger.info(f"Created collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to create {user}/{collection}: {e}") + + # Delete removed collections (idempotent) + for user, collection in to_delete: + try: + await self.delete_collection_internal(user, collection) + self.known_collections.discard((user, collection)) + logger.info(f"Deleted collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to delete {user}/{collection}: {e}") +``` + +3. **Inicialize as coleções conhecidas na inicialização:** +```python +async def start(self): + """Start the processor""" + await super().start() + await self.sync_known_collections() + +async def sync_known_collections(self): + """Query backend to populate known_collections set""" + # Backend-specific implementation: + # - Milvus/Pinecone/Qdrant: List collections/indexes matching naming pattern + # - Cassandra: Query keyspaces or collection metadata + # - Neo4j/Memgraph/FalkorDB: Query CollectionMetadata nodes + pass +``` + +4. **Refatore os métodos de tratamento existentes:** +```python +# Rename and remove response sending: +# handle_create_collection → create_collection_internal +# handle_delete_collection → delete_collection_internal + +async def create_collection_internal(self, user, collection): + """Create collection (idempotent)""" + # Same logic as current handle_create_collection + # But remove response producer calls + # Handle "already exists" gracefully + pass + +async def delete_collection_internal(self, user, collection): + """Delete collection (idempotent)""" + # Same logic as current handle_delete_collection + # But remove response producer calls + # Handle "not found" gracefully + pass +``` + +5. **Remover a infraestrutura de gerenciamento de armazenamento:** + Remover a configuração e inicialização de `self.storage_request_consumer` + Remover a configuração de `self.storage_response_producer` + Remover o método de dispatcher de `on_storage_management` + Remover as métricas para o gerenciamento de armazenamento + Remover as importações: `StorageManagementRequest`, `StorageManagementResponse` + +**Considerações Específicas para o Backend:** + +**Bancos de dados vetoriais (Milvus, Pinecone, Qdrant):** Rastrear a lógica `(user, collection)` em `known_collections`, mas pode criar múltiplas coleções de backend por dimensão. Continuar o padrão de criação preguiçosa. As operações de exclusão devem remover todas as variantes de dimensão. + +**Cassandra Objects:** As coleções são propriedades de linha, não estruturas. Rastrear informações no nível do keyspace. + +**Bancos de dados de grafos (Neo4j, Memgraph, FalkorDB):** Consultar nós `CollectionMetadata` na inicialização. Criar/excluir nós de metadados na sincronização. + +**Cassandra Triples:** Usar a API `KnowledgeGraph` para operações de coleção. + +**Pontos-Chave do Design:** + +**Consistência eventual:** Não há mecanismo de solicitação/resposta, o envio de configuração é transmitido. +**Idempotência:** Todas as operações de criação/exclusão devem ser seguras para serem repetidas. +**Tratamento de erros:** Registrar erros, mas não bloquear as atualizações de configuração. +**Autorreparação:** As operações com falha serão repetidas na próxima atualização de configuração. +**Formato da chave da coleção:** `"user:collection"` em `config["collections"]` + +#### Mudança 11: Atualizar o Esquema da Coleção - Remover Timestamps +**Arquivo:** `trustgraph-base/trustgraph/schema/services/collection.py` + +**Modificar CollectionMetadata (Linhas 13-21):** +Remover os campos `created_at` e `updated_at`: +```python +class CollectionMetadata(Record): + user = String() + collection = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() +``` + +**Modificar CollectionManagementRequest (linhas 25-47):** +Remover campos de timestamp: +```python +class CollectionManagementRequest(Record): + operation = String() + user = String() + collection = String() + timestamp = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() + tag_filter = Array(String()) + limit = Integer() +``` + +**Justificativa:** +Os carimbos de data e hora não agregam valor para coleções. +O serviço de configuração mantém seu próprio rastreamento de versão. +Simplifica o esquema e reduz o armazenamento. + +#### Benefícios da Migração do Serviço de Configuração + +1. ✅ **Elimina tópicos de gerenciamento de armazenamento codificados** - Resolve o bloqueio multi-inquilino. +2. ✅ **Coordenação mais simples** - Sem espera assíncrona complexa por 4 ou mais respostas de armazenamento. +3. ✅ **Consistência eventual** - Os serviços de armazenamento são atualizados independentemente por meio de push de configuração. +4. ✅ **Melhor confiabilidade** - Push de configuração persistente versus solicitação/resposta não persistente. +5. ✅ **Modelo de configuração unificado** - Coleções tratadas como configuração. +6. ✅ **Reduz a complexidade** - Remove aproximadamente 300 linhas de código de coordenação. +7. ✅ **Pronto para multi-inquilino** - A configuração já suporta o isolamento de inquilinos por meio de keyspace. +8. ✅ **Rastreamento de versão** - O mecanismo de versão do serviço de configuração fornece um histórico de auditoria. + +## Notas de Implementação + +### Compatibilidade com versões anteriores + +**Alterações de parâmetros:** +As alterações de nome dos parâmetros da CLI são alterações disruptivas, mas aceitáveis (o recurso atualmente não está funcional). +Os serviços funcionam sem parâmetros (use os padrões). +Keyspaces padrão preservados: "config", "knowledge", "librarian". +Fila padrão: `persistent://tg/config/config` + +**Gerenciamento de coleções:** +**Alteração disruptiva:** A tabela de coleções foi removida do keyspace librarian. +**Nenhuma migração de dados fornecida** - aceitável para esta fase. +A API de coleção externa não foi alterada (operações de listagem, atualização e exclusão). +O formato de metadados da coleção foi simplificado (os carimbos de data e hora foram removidos). + +### Requisitos de teste + +**Teste de parâmetros:** +1. Verificar se o parâmetro `--config-push-queue` funciona no serviço graph-embeddings. +2. Verificar se o parâmetro `--config-push-queue` funciona no serviço text-completion. +3. Verificar se o parâmetro `--config-push-queue` funciona no serviço de configuração. +4. Verificar se o parâmetro `--cassandra-keyspace` funciona para o serviço de configuração. +5. Verificar se o parâmetro `--cassandra-keyspace` funciona para o serviço cores. +6. Verificar se o parâmetro `--cassandra-keyspace` funciona para o serviço librarian. +7. Verificar se os serviços funcionam sem parâmetros (usa os padrões). +8. Verificar a implantação multi-inquilino com nomes de fila e keyspace personalizados. + +**Teste de gerenciamento de coleções:** +9. Verificar a operação `list-collections` por meio do serviço de configuração. +10. Verificar se `update-collection` cria/atualiza na tabela de configuração. +11. Verificar se `delete-collection` remove da tabela de configuração. +12. Verificar se o push de configuração é acionado em atualizações de coleção. +13. Verificar se a filtragem de tags funciona com armazenamento baseado em configuração. +14. Verificar se as operações de coleção funcionam sem campos de carimbo de data e hora. + +### Exemplo de implantação multi-inquilino +```bash +# Tenant: tg-dev +graph-embeddings \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config + +config-service \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config \ + --cassandra-keyspace tg_dev_config +``` + +## Análise de Impacto + +### Serviços Afetados pela Alteração 1-2 (Renomeação de Parâmetro da CLI) +Todos os serviços que herdam de AsyncProcessor ou FlowProcessor: +config-service +cores-service +librarian-service +graph-embeddings +document-embeddings +text-completion-* (todos os provedores) +extract-* (todos os extractors) +query-* (todos os serviços de consulta) +retrieval-* (todos os serviços RAG) +storage-* (todos os serviços de armazenamento) +E mais 20 serviços + +### Serviços Afetados pelas Alterações 3-6 (Keyspace do Cassandra) +config-service +cores-service +librarian-service + +### Serviços Afetados pelas Alterações 7-11 (Gerenciamento de Coleções) + +**Alterações Imediatas:** +librarian-service (collection_manager.py, service.py) +tables/library.py (remoção da tabela de coleções) +schema/services/collection.py (remoção do timestamp) + +**Alterações Concluídas (Alteração 10):** ✅ +Todos os serviços de armazenamento (11 no total) - migrados para o push de configuração para atualizações de coleções via `CollectionConfigHandler` +Esquema de gerenciamento de armazenamento removido de `storage.py` + +## Considerações Futuras + +### Modelo de Keyspace por Usuário + +Alguns serviços usam **keyspaces por usuário** dinamicamente, onde cada usuário recebe seu próprio keyspace do Cassandra: + +**Serviços com keyspaces por usuário:** +1. **Triples Query Service** (`trustgraph-flow/trustgraph/query/triples/cassandra/service.py:65`) + Usa `keyspace=query.user` +2. **Objects Query Service** (`trustgraph-flow/trustgraph/query/objects/cassandra/service.py:479`) + Usa `keyspace=self.sanitize_name(user)` +3. **KnowledgeGraph Direct Access** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py:18`) + Parâmetro padrão `keyspace="trustgraph"` + +**Status:** Estes **não são modificados** nesta especificação. + +**Revisão Futura Necessária:** +Avaliar se o modelo de keyspace por usuário cria problemas de isolamento de locatários +Considerar se as implementações multi-locatário precisam de padrões de prefixo de keyspace (por exemplo, `tenant_a_user1`) +Revisar para possíveis colisões de ID de usuário entre locatários +Avaliar se um keyspace compartilhado único por locatário com isolamento de linha baseado em usuário é preferível + +**Observação:** Isso não impede a implementação multi-locatário atual, mas deve ser revisado antes das implementações multi-locatário de produção. + +## Fases de Implementação + +### Fase 1: Correções de Parâmetros (Alterações 1-6) +Corrigir a nomenclatura do parâmetro `--config-push-queue` +Adicionar suporte ao parâmetro `--cassandra-keyspace` +**Resultado:** Configuração de fila e keyspace multi-locatário habilitada + +### Fase 2: Migração do Gerenciamento de Coleções (Alterações 7-9, 11) +Migrar o armazenamento de coleções para o serviço de configuração +Remover a tabela de coleções do librarian +Atualizar o esquema de coleção (remover timestamps) +**Resultado:** Elimina tópicos de gerenciamento de armazenamento codificados, simplifica o librarian + +### Fase 3: Atualizações do Serviço de Armazenamento (Alteração 10) ✅ CONCLUÍDA +Atualizados todos os serviços de armazenamento para usar o push de configuração para coleções via `CollectionConfigHandler` +Removida a infraestrutura de solicitação/resposta de gerenciamento de armazenamento +Removidas as definições de esquema legadas +**Resultado:** Gerenciamento de coleções baseado em configuração completo alcançado + +## Referências +GitHub Issue: https://github.com/trustgraph-ai/trustgraph/issues/582 +Arquivos Relacionados: + `trustgraph-base/trustgraph/base/async_processor.py` + `trustgraph-base/trustgraph/base/cassandra_config.py` + `trustgraph-base/trustgraph/schema/core/topic.py` + `trustgraph-base/trustgraph/schema/services/collection.py` + `trustgraph-flow/trustgraph/config/service/service.py` + `trustgraph-flow/trustgraph/cores/service.py` + `trustgraph-flow/trustgraph/librarian/service.py` + `trustgraph-flow/trustgraph/librarian/collection_manager.py` + `trustgraph-flow/trustgraph/tables/library.py` diff --git a/docs/tech-specs/multi-tenant-support.ru.md b/docs/tech-specs/multi-tenant-support.ru.md new file mode 100644 index 00000000..c66e484b --- /dev/null +++ b/docs/tech-specs/multi-tenant-support.ru.md @@ -0,0 +1,772 @@ +# Техническое описание: Поддержка многопользовательской среды + +## Обзор + +Обеспечьте поддержку многопользовательской среды, устранив несоответствия в именах параметров, которые препятствуют настройке очередей, и добавив параметризацию пространства ключей Cassandra. + +## Контекст архитектуры + +### Разрешение очередей на основе потоков + +Система TrustGraph использует **архитектуру на основе потоков** для динамического разрешения очередей, что изначально поддерживает многопользовательскую среду: + +**Определения потоков** хранятся в Cassandra и указывают имена очередей через определения интерфейсов. +**Имена очередей используют шаблоны** с переменными `{id}`, которые заменяются идентификаторами экземпляров потоков. +**Сервисы динамически разрешают очереди**, получая конфигурации потоков в момент запроса. +**Каждый пользователь может иметь уникальные потоки** с разными именами очередей, что обеспечивает изоляцию. + +Пример определения интерфейса потока: +```json +{ + "interfaces": { + "triples-store": "persistent://tg/flow/triples-store:{id}", + "graph-embeddings-store": "persistent://tg/flow/graph-embeddings-store:{id}" + } +} +``` + +Когда арендатор A запускает поток `tenant-a-prod`, а арендатор B запускает поток `tenant-b-prod`, они автоматически получают изолированные очереди: +`persistent://tg/flow/triples-store:tenant-a-prod` +`persistent://tg/flow/triples-store:tenant-b-prod` + +**Сервисы, правильно разработанные для многоарендности:** +✅ **Knowledge Management (основные компоненты)** - Динамически определяет очереди из конфигурации потока, передаваемой в запросах + +**Сервисы, требующие исправления:** +🔴 **Config Service** - Несоответствие имен параметров препятствует настройке очереди +🔴 **Librarian Service** - Жестко заданные темы управления хранилищем (описано ниже) +🔴 **Все сервисы** - Невозможно настроить пространство ключей Cassandra + +## Описание проблемы + +### Проблема #1: Несоответствие имен параметров в AsyncProcessor +**CLI определяет:** `--config-queue` (неясное наименование) +**Argparse преобразует в:** `config_queue` (в словаре параметров) +**Код ищет:** `config_push_queue` +**Результат:** Параметр игнорируется, используется значение по умолчанию `persistent://tg/config/config` +**Влияние:** Затрагивает все 32+ сервиса, наследующие от AsyncProcessor +**Препятствует:** Многоарендные развертывания не могут использовать очереди, специфичные для арендатора +**Решение:** Переименовать параметр CLI в `--config-push-queue` для ясности (разрыв обратной совместимости допустим, так как функция в настоящее время не работает) + +### Проблема #2: Несоответствие имен параметров в Config Service +**CLI определяет:** `--push-queue` (двусмысленное наименование) +**Argparse преобразует в:** `push_queue` (в словаре параметров) +**Код ищет:** `config_push_queue` +**Результат:** Параметр игнорируется +**Влияние:** Сервис Config не может использовать пользовательскую очередь отправки +**Решение:** Переименовать параметр CLI в `--config-push-queue` для согласованности и ясности (разрыв обратной совместимости допустим) + +### Проблема #3: Жестко заданное пространство ключей Cassandra +**Текущее состояние:** Пространство ключей жестко задано как `"config"`, `"knowledge"`, `"librarian"` в различных сервисах +**Результат:** Невозможно настроить пространство ключей для многоарендных развертываний +**Влияние:** Сервисы Config, основные компоненты и Librarian +**Препятствует:** Несколько арендаторов не могут использовать отдельные пространства ключей Cassandra + +### Проблема #4: Архитектура управления коллекциями ✅ ВЫПОЛНЕНО +**Предыдущее состояние:** Коллекции хранились в пространстве ключей Cassandra Librarian через отдельную таблицу коллекций +**Предыдущее состояние:** Librarian использовал 4 жестко заданные темы управления хранилищем для координации создания/удаления коллекций: + `vector_storage_management_topic` + `object_storage_management_topic` + `triples_storage_management_topic` + `storage_management_response_topic` +**Проблемы (решены):** + Жестко заданные темы не могли быть настроены для многоарендных развертываний + Сложная асинхронная координация между Librarian и 4+ сервисами хранения + Отдельная таблица Cassandra и инфраструктура управления + Непостоянные очереди запросов/ответов для критических операций +**Решение реализовано:** Коллекции были перенесены в хранилище сервиса Config, используется отправка Config для распространения +**Статус:** Все хранилища были перенесены на шаблон `CollectionConfigHandler` + +## Решение + +Эта спецификация решает проблемы #1, #2, #3 и #4. + +### Часть 1: Исправление несоответствий имен параметров + +#### Изменение 1: Базовый класс AsyncProcessor - Переименование параметра CLI +**Файл:** `trustgraph-base/trustgraph/base/async_processor.py` +**Строка:** 260-264 + +**Текущее состояние:** +```python +parser.add_argument( + '--config-queue', + default=default_config_queue, + help=f'Config push queue {default_config_queue}', +) +``` + +**Исправлено:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_queue, + help=f'Config push queue (default: {default_config_queue})', +) +``` + +**Обоснование:** +Более понятное и явное наименование +Соответствует внутреннему имени переменной `config_push_queue` +Изменение, нарушающее обратную совместимость, допустимо, поскольку функция в настоящее время не функционирует +Не требуется изменение кода в params.get() - он уже ищет правильное имя + +#### Изменение 2: Сервис конфигурации - Переименование параметра командной строки +**Файл:** `trustgraph-flow/trustgraph/config/service/service.py` +**Строка:** 276-279 + +**Текущее:** +```python +parser.add_argument( + '--push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**Исправлено:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**Обоснование:** +Более понятное наименование - "config-push-queue" более явно, чем просто "push-queue". +Соответствует внутреннему имени переменной `config_push_queue`. +Соответствует параметру `--config-push-queue` класса AsyncProcessor. +Изменение, нарушающее обратную совместимость, допустимо, поскольку функция в настоящее время не работает. +Не требуется изменение кода в params.get() - он уже ищет правильное имя. + +### Часть 2: Добавление параметризации пространства ключей Cassandra + +#### Изменение 3: Добавление параметра пространства ключей в модуль cassandra_config +**Файл:** `trustgraph-base/trustgraph/base/cassandra_config.py` + +**Добавление аргумента командной строки** (в функции `add_cassandra_args()`): +```python +parser.add_argument( + '--cassandra-keyspace', + default=None, + help='Cassandra keyspace (default: service-specific)' +) +``` + +**Добавить поддержку переменных окружения** (в функции `resolve_cassandra_config()`): +```python +keyspace = params.get( + "cassandra_keyspace", + os.environ.get("CASSANDRA_KEYSPACE") +) +``` + +**Обновить возвращаемое значение** `resolve_cassandra_config()`: +В настоящее время возвращает: `(hosts, username, password)` +Изменить, чтобы возвращалось: `(hosts, username, password, keyspace)` + +**Обоснование:** +Соответствует существующей схеме конфигурации Cassandra +Доступно всем сервисам через `add_cassandra_args()` +Поддерживает конфигурацию как через командную строку, так и через переменные окружения + +#### Изменение 4: Сервис конфигурации - Использование параметризованных пространств ключей +**Файл:** `trustgraph-flow/trustgraph/config/service/service.py` + +**Строка 30** - Удалить жестко закодированное пространство ключей: +```python +# DELETE THIS LINE: +keyspace = "config" +``` + +**Строки 69-73** - Обновление разрешения конфигурации Cassandra: + +**Текущая версия:** +```python +cassandra_host, cassandra_username, cassandra_password = \ + resolve_cassandra_config(params) +``` + +**Исправлено:** +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="config") +``` + +**Обоснование:** +Обеспечивает обратную совместимость с "config" в качестве значения по умолчанию. +Позволяет переопределить значение с помощью `--cassandra-keyspace` или `CASSANDRA_KEYSPACE`. + +#### Изменение 5: Основные компоненты/Сервис знаний - Использование параметризованных пространств ключей. +**Файл:** `trustgraph-flow/trustgraph/cores/service.py` + +**Строка 37** - Удалить жестко закодированное пространство ключей: +```python +# DELETE THIS LINE: +keyspace = "knowledge" +``` + +**Обновление разрешения конфигурации Cassandra** (в том же месте, что и служба конфигурации): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="knowledge") +``` + +#### Изменение 6: Сервис библиотекаря - Использование параметризованных пространств ключей. +**Файл:** `trustgraph-flow/trustgraph/librarian/service.py` + +**Строка 51** - Удалить жестко закодированное пространство ключей: +```python +# DELETE THIS LINE: +keyspace = "librarian" +``` + +**Обновление разрешения конфигурации Cassandra** (в том же месте, что и служба конфигурации): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="librarian") +``` + +### Часть 3: Перенос управления коллекциями в службу конфигураций + +#### Обзор +Перенесите коллекции из пространства ключей Cassandra librarian в хранилище службы конфигураций. Это устраняет жестко закодированные темы управления хранилищем и упрощает архитектуру, используя существующий механизм распространения конфигураций. + +#### Текущая архитектура +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Cassandra Collections Table (librarian keyspace) + ↓ + Broadcast to 4 Storage Management Topics (hardcoded) + ↓ + Wait for 4+ Storage Service Responses + ↓ + Response to Gateway +``` + +#### Новая архитектура +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Config Service API (put/delete/getvalues) + ↓ + Cassandra Config Table (class='collections', key='user:collection') + ↓ + Config Push (to all subscribers on config-push-queue) + ↓ + All Storage Services receive config update independently +``` + +#### Изменение 7: Менеджер коллекций - Использование API сервиса конфигурации +**Файл:** `trustgraph-flow/trustgraph/librarian/collection_manager.py` + +**Удалить:** +Использование `LibraryTableStore` (строки 33, 40-41) +Инициализация производителей управления хранилищем (строки 86-140) +Метод `on_storage_response` (строки 400-430) +Отслеживание `pending_deletions` (строки 57, 90-96 и использование во всем коде) + +**Добавить:** +Клиент сервиса конфигурации для вызовов API (шаблон запрос/ответ) + +**Настройка клиента конфигурации:** +```python +# In __init__, add config request/response producers/consumers +from trustgraph.schema.services.config import ConfigRequest, ConfigResponse + +# Producer for config requests +self.config_request_producer = Producer( + client=pulsar_client, + topic=config_request_queue, + schema=ConfigRequest, +) + +# Consumer for config responses (with correlation ID) +self.config_response_consumer = Consumer( + taskgroup=taskgroup, + client=pulsar_client, + flow=None, + topic=config_response_queue, + subscriber=f"{id}-config", + schema=ConfigResponse, + handler=self.on_config_response, +) + +# Tracking for pending config requests +self.pending_config_requests = {} # request_id -> asyncio.Event +``` + +**Изменить `list_collections` (строки 145-180):** +```python +async def list_collections(self, user, tag_filter=None, limit=None): + """List collections from config service""" + # Send getvalues request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='getvalues', + type='collections', + ) + + # Send request and wait for response + response = await self.send_config_request(request) + + # Parse collections from response + collections = [] + for key, value_json in response.values.items(): + if ":" in key: + coll_user, collection = key.split(":", 1) + if coll_user == user: + metadata = json.loads(value_json) + collections.append(CollectionMetadata(**metadata)) + + # Apply tag filtering in-memory (as before) + if tag_filter: + collections = [c for c in collections if any(tag in c.tags for tag in tag_filter)] + + # Apply limit + if limit: + collections = collections[:limit] + + return collections + +async def send_config_request(self, request): + """Send config request and wait for response""" + event = asyncio.Event() + self.pending_config_requests[request.id] = event + + await self.config_request_producer.send(request) + await event.wait() + + return self.pending_config_requests.pop(request.id + "_response") + +async def on_config_response(self, message, consumer, flow): + """Handle config response""" + response = message.value() + if response.id in self.pending_config_requests: + self.pending_config_requests[response.id + "_response"] = response + self.pending_config_requests[response.id].set() +``` + +**Изменить `update_collection` (строки 182-312):** +```python +async def update_collection(self, user, collection, name, description, tags): + """Update collection via config service""" + # Create metadata + metadata = CollectionMetadata( + user=user, + collection=collection, + name=name, + description=description, + tags=tags, + ) + + # Send put request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='put', + type='collections', + key=f'{user}:{collection}', + value=json.dumps(metadata.to_dict()), + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config update failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and create collections +``` + +**Изменить `delete_collection` (строки 314-398):** +```python +async def delete_collection(self, user, collection): + """Delete collection via config service""" + # Send delete request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='delete', + type='collections', + key=f'{user}:{collection}', + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config delete failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and delete collections +``` + +**Формат метаданных коллекции:** +Хранится в таблице конфигурации как: `class='collections', key='user:collection'` +Значение является JSON-сериализованным объектом CollectionMetadata (без полей времени). +Поля: `user`, `collection`, `name`, `description`, `tags` +Пример: `class='collections', key='alice:my-docs', value='{"user":"alice","collection":"my-docs","name":"My Documents","description":"...","tags":["work"]}'` + +#### Изменение 8: Сервис Librarian - Удаление инфраструктуры управления хранилищем +**Файл:** `trustgraph-flow/trustgraph/librarian/service.py` + +**Удалить:** +Модули-производители управления хранилищем (строки 173-190): + `vector_storage_management_producer` + `object_storage_management_producer` + `triples_storage_management_producer` +Потребитель ответов хранилища (строки 192-201) +Обработчик `on_storage_response` (строки 467-473) + +**Изменить:** +Инициализация CollectionManager (строки 215-224) - удалить параметры модуля-производителя хранилища + +**Примечание:** Внешний API для коллекций остается неизменным: +`list-collections` +`update-collection` +`delete-collection` + +#### Изменение 9: Удаление таблицы Collections из LibraryTableStore +**Файл:** `trustgraph-flow/trustgraph/tables/library.py` + +**Удалить:** +Оператор CREATE для таблицы Collections (строки 114-127) +Подготовленные операторы для Collections (строки 205-240) +Все методы для работы с коллекциями (строки 578-717): + `ensure_collection_exists` + `list_collections` + `update_collection` + `delete_collection` + `get_collection` + `create_collection` + +**Обоснование:** +Коллекции теперь хранятся в таблице конфигурации. +Изменение, требующее обновления, приемлемо - миграция данных не требуется. +Значительно упрощает сервис Librarian. + +#### Изменение 10: Сервисы хранения - Управление коллекциями на основе конфигурации ✅ ВЫПОЛНЕНО + +**Статус:** Все 11 хранилищ были перенесены на использование `CollectionConfigHandler`. + +**Затронутые сервисы (всего 11):** +Векторные представления документов: milvus, pinecone, qdrant +Векторные представления графов: milvus, pinecone, qdrant +Объектное хранилище: cassandra +Хранилище троек: cassandra, falkordb, memgraph, neo4j + +**Файлы:** +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +`trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +`trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` + +**Шаблон реализации (для всех сервисов):** + +1. **Зарегистрировать обработчик конфигурации в `__init__`:** +```python +# Add after AsyncProcessor initialization +self.register_config_handler(self.on_collection_config) +self.known_collections = set() # Track (user, collection) tuples +``` + +2. **Реализовать обработчик конфигурации:** +```python +async def on_collection_config(self, config, version): + """Handle collection configuration updates""" + logger.info(f"Collection config version: {version}") + + if "collections" not in config: + return + + # Parse collections from config + # Key format: "user:collection" in config["collections"] + config_collections = set() + for key in config["collections"].keys(): + if ":" in key: + user, collection = key.split(":", 1) + config_collections.add((user, collection)) + + # Determine changes + to_create = config_collections - self.known_collections + to_delete = self.known_collections - config_collections + + # Create new collections (idempotent) + for user, collection in to_create: + try: + await self.create_collection_internal(user, collection) + self.known_collections.add((user, collection)) + logger.info(f"Created collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to create {user}/{collection}: {e}") + + # Delete removed collections (idempotent) + for user, collection in to_delete: + try: + await self.delete_collection_internal(user, collection) + self.known_collections.discard((user, collection)) + logger.info(f"Deleted collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to delete {user}/{collection}: {e}") +``` + +3. **Инициализация известных коллекций при запуске:** +```python +async def start(self): + """Start the processor""" + await super().start() + await self.sync_known_collections() + +async def sync_known_collections(self): + """Query backend to populate known_collections set""" + # Backend-specific implementation: + # - Milvus/Pinecone/Qdrant: List collections/indexes matching naming pattern + # - Cassandra: Query keyspaces or collection metadata + # - Neo4j/Memgraph/FalkorDB: Query CollectionMetadata nodes + pass +``` + +4. **Рефакторинг существующих методов обработчиков:** +```python +# Rename and remove response sending: +# handle_create_collection → create_collection_internal +# handle_delete_collection → delete_collection_internal + +async def create_collection_internal(self, user, collection): + """Create collection (idempotent)""" + # Same logic as current handle_create_collection + # But remove response producer calls + # Handle "already exists" gracefully + pass + +async def delete_collection_internal(self, user, collection): + """Delete collection (idempotent)""" + # Same logic as current handle_delete_collection + # But remove response producer calls + # Handle "not found" gracefully + pass +``` + +5. **Удаление инфраструктуры управления хранилищем:** + Удалить настройку и запуск `self.storage_request_consumer` + Удалить настройку `self.storage_response_producer` + Удалить метод диспетчера `on_storage_management` + Удалить метрики для управления хранилищем + Удалить импорты: `StorageManagementRequest`, `StorageManagementResponse` + +**Особенности, специфичные для бэкенда:** + +**Векторные хранилища (Milvus, Pinecone, Qdrant):** Отслеживать логическую `(user, collection)` в `known_collections`, но может создавать несколько бэкенд-коллекций для каждой размерности. Продолжить использование ленивой схемы создания. Операции удаления должны удалять все варианты размерностей. + +**Объекты Cassandra:** Коллекции являются свойствами строк, а не структурами. Отслеживать информацию на уровне пространства ключей. + +**Графовые хранилища (Neo4j, Memgraph, FalkorDB):** Запрашивать узлы `CollectionMetadata` при запуске. Создавать/удалять метаданные узлов при синхронизации. + +**Тройки Cassandra:** Использовать API `KnowledgeGraph` для операций с коллекциями. + +**Основные принципы проектирования:** + +**Итоговая согласованность:** Отсутствует механизм запрос/ответ, конфигурация распространяется широковещанием. +**Идемпотентность:** Все операции создания/удаления должны быть безопасными для повторной попытки. +**Обработка ошибок:** Регистрировать ошибки, но не блокировать обновления конфигурации. +**Самовосстановление:** Неудачные операции будут повторены при следующем распространении конфигурации. +**Формат ключа коллекции:** `"user:collection"` в `config["collections"]` + +#### Изменение 11: Обновление схемы коллекции - Удаление временных меток +**Файл:** `trustgraph-base/trustgraph/schema/services/collection.py` + +**Изменить CollectionMetadata (строки 13-21):** +Удалить поля `created_at` и `updated_at`: +```python +class CollectionMetadata(Record): + user = String() + collection = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() +``` + +**Изменить класс CollectionManagementRequest (строки 25-47):** +Удалить поля временной метки: +```python +class CollectionManagementRequest(Record): + operation = String() + user = String() + collection = String() + timestamp = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() + tag_filter = Array(String()) + limit = Integer() +``` + +**Обоснование:** +Временные метки не добавляют ценности для коллекций. +Сервис конфигурации самостоятельно отслеживает версии. +Упрощает схему и уменьшает объем хранения. + +#### Преимущества миграции на сервис конфигурации + +1. ✅ **Устраняет жестко закодированные темы управления хранилищем** - Решает проблему многопользовательской среды. +2. ✅ **Более простая координация** - Нет сложного асинхронного ожидания ответов от 4+ хранилищ. +3. ✅ **В конечном итоге согласованность** - Сервисы хранения обновляются независимо с помощью push-конфигурации. +4. ✅ **Более высокая надежность** - Постоянная push-конфигурация против неперсистентного запроса/ответа. +5. ✅ **Унифицированная модель конфигурации** - Коллекции рассматриваются как конфигурация. +6. ✅ **Уменьшает сложность** - Удаляет около 300 строк кода для координации. +7. ✅ **Готовность к многопользовательской среде** - Конфигурация уже поддерживает изоляцию пользователей с помощью пространств ключей. +8. ✅ **Отслеживание версий** - Механизм версионирования сервиса конфигурации обеспечивает аудит. + +## Замечания по реализации + +### Обратная совместимость + +**Изменения параметров:** +Переименование параметров командной строки является серьезным изменением, но допустимо (функция в настоящее время не работает). +Сервисы работают без параметров (используются значения по умолчанию). +Значения по умолчанию для пространств ключей сохранены: "config", "knowledge", "librarian". +Значение по умолчанию для очереди: `persistent://tg/config/config` + +**Управление коллекциями:** +**Серьезное изменение:** Таблица коллекций удалена из пространства ключей librarian. +**Миграция данных не предусмотрена** - приемлемо для этой фазы. +Внешний API для коллекций не изменен (операции list/update/delete). +Формат метаданных коллекций упрощен (временные метки удалены). + +### Требования к тестированию + +**Тестирование параметров:** +1. Проверить, работает ли параметр `--config-push-queue` для сервиса graph-embeddings. +2. Проверить, работает ли параметр `--config-push-queue` для сервиса text-completion. +3. Проверить, работает ли параметр `--config-push-queue` для сервиса конфигурации. +4. Проверить, работает ли параметр `--cassandra-keyspace` для сервиса конфигурации. +5. Проверить, работает ли параметр `--cassandra-keyspace` для сервиса cores. +6. Проверить, работает ли параметр `--cassandra-keyspace` для сервиса librarian. +7. Проверить, работают ли сервисы без параметров (используются значения по умолчанию). +8. Проверить развертывание в многопользовательской среде с использованием пользовательских имен очередей и пространств ключей. + +**Тестирование управления коллекциями:** +9. Проверить операцию `list-collections` через сервис конфигурации. +10. Проверить, создает ли `update-collection` записи/обновления в таблице конфигурации. +11. Проверить, удаляет ли `delete-collection` записи из таблицы конфигурации. +12. Проверить, запускается ли push-конфигурации при обновлениях коллекций. +13. Проверить, работает ли фильтрация по тегам с использованием хранилища на основе конфигурации. +14. Проверить, работают ли операции с коллекциями без полей временных меток. + +### Пример развертывания в многопользовательской среде +```bash +# Tenant: tg-dev +graph-embeddings \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config + +config-service \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config \ + --cassandra-keyspace tg_dev_config +``` + +## Анализ влияния + +### Сервисы, затронутые изменением 1-2 (Переименование параметра CLI) +Все сервисы, наследующие AsyncProcessor или FlowProcessor: +config-service +cores-service +librarian-service +graph-embeddings +document-embeddings +text-completion-* (все провайдеры) +extract-* (все экстракторы) +query-* (все сервисы запросов) +retrieval-* (все сервисы RAG) +storage-* (все сервисы хранения) +И еще 20+ сервисов + +### Сервисы, затронутые изменениями 3-6 (Keyspace Cassandra) +config-service +cores-service +librarian-service + +### Сервисы, затронутые изменениями 7-11 (Управление коллекциями) + +**Немедленные изменения:** +librarian-service (collection_manager.py, service.py) +tables/library.py (удаление таблицы collections) +schema/services/collection.py (удаление метки времени) + +**Выполненные изменения (изменение 10):** ✅ +Все сервисы хранения (всего 11) - перенесены на push-конфигурацию для обновлений коллекций через `CollectionConfigHandler` +Схема управления хранилищем удалена из `storage.py` + +## Будущие соображения + +### Модель keyspace на уровне пользователя + +Некоторые сервисы динамически используют **keyspace на уровне пользователя**, когда каждый пользователь получает свой собственный keyspace Cassandra: + +**Сервисы с keyspace на уровне пользователя:** +1. **Сервис запросов Triple** (`trustgraph-flow/trustgraph/query/triples/cassandra/service.py:65`) + Использует `keyspace=query.user` +2. **Сервис запросов объектов** (`trustgraph-flow/trustgraph/query/objects/cassandra/service.py:479`) + Использует `keyspace=self.sanitize_name(user)` +3. **Прямой доступ к графу знаний** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py:18`) + Параметр по умолчанию `keyspace="trustgraph"` + +**Статус:** Эти параметры **не изменяются** в этой спецификации. + +**Требуется дальнейший анализ:** +Оценить, создает ли модель keyspace на уровне пользователя проблемы изоляции арендаторов +Рассмотреть, нужны ли многопользовательским развертываниям префиксы keyspace (например, `tenant_a_user1`) +Проверить на потенциальные конфликты идентификаторов пользователей между арендаторами +Оценить, является ли единый общий keyspace на арендатора с изоляцией строк на уровне пользователя более предпочтительным + +**Примечание:** Это не блокирует текущую многопользовательскую реализацию, но должно быть рассмотрено перед производственными многопользовательскими развертываниями. + +## Этапы реализации + +### Этап 1: Исправление параметров (изменения 1-6) +Исправить именование параметра `--config-push-queue` +Добавить поддержку параметра `--cassandra-keyspace` +**Результат:** Многопользовательская очередь и конфигурация keyspace включены + +### Этап 2: Миграция управления коллекциями (изменения 7-9, 11) +Перенести хранение коллекций в сервис конфигурации +Удалить таблицу collections из librarian +Обновить схему коллекций (удалить метки времени) +**Результат:** Устраняет жестко закодированные темы управления хранилищем, упрощает librarian + +### Этап 3: Обновления сервисов хранения (изменение 10) ✅ ВЫПОЛНЕНО +Обновлены все сервисы хранения для использования push-конфигурации для коллекций через `CollectionConfigHandler` +Удалена инфраструктура запросов/ответов управления хранилищем +Удалены устаревшие определения схемы +**Результат:** Достигнуто полное управление коллекциями на основе конфигурации + +## Ссылки +GitHub Issue: https://github.com/trustgraph-ai/trustgraph/issues/582 +Связанные файлы: + `trustgraph-base/trustgraph/base/async_processor.py` + `trustgraph-base/trustgraph/base/cassandra_config.py` + `trustgraph-base/trustgraph/schema/core/topic.py` + `trustgraph-base/trustgraph/schema/services/collection.py` + `trustgraph-flow/trustgraph/config/service/service.py` + `trustgraph-flow/trustgraph/cores/service.py` + `trustgraph-flow/trustgraph/librarian/service.py` + `trustgraph-flow/trustgraph/librarian/collection_manager.py` + `trustgraph-flow/trustgraph/tables/library.py` diff --git a/docs/tech-specs/multi-tenant-support.sw.md b/docs/tech-specs/multi-tenant-support.sw.md new file mode 100644 index 00000000..18bd9e10 --- /dev/null +++ b/docs/tech-specs/multi-tenant-support.sw.md @@ -0,0 +1,772 @@ +# Maelezo ya Kiufundi: Usaidizi wa Matumizi Mbalimbali (Multi-Tenant) + +## Muhtasari + +Wezesha matumizi mbalimbali kwa kurekebisha kutofautiana kwa majina ya vigezo ambavyo huuzuia utengenezaji wa folyo (queue) na kwa kuongeza utaratibu wa kuweka vigezo kwa Cassandra. + +## Mfumo wa Uendeshaji + +### Utatuzi wa Folyo Kulingana na Mchakato + +Mfumo wa TrustGraph hutumia **mfumo wa usanifu unaozingatia mchakato** (flow-based architecture) kwa utatuzi wa folyo, ambao kwa asili unao na uwezo wa kuunga mkono matumizi mbalimbali: + +**Maelezo ya Mchakato** (Flow Definitions) huhifadhiwa katika Cassandra na yanaeleza majina ya folyo kupitia maelezo ya kiungo (interface). +**Majina ya folyo hutumia vipengele** (templates) na vigezo vya `{id}` ambavyo hubadilishwa na kitambulisho cha mfano wa mchakato. +**Huduma zinatatua folyo kwa njia ya moja kwa moja** kwa kutafuta mipangilio ya mchakato wakati wa ombi. +**Kila mtumiaji anaweza kuwa na mchakato wake wa kipekee** na majina tofauti ya folyo, ambayo hutoa upekee. + +Kielelezo cha maelezo ya kiungo ya mchakato: +```json +{ + "interfaces": { + "triples-store": "persistent://tg/flow/triples-store:{id}", + "graph-embeddings-store": "persistent://tg/flow/graph-embeddings-store:{id}" + } +} +``` + +Wakati mwendeshaji A anaanza mtiririko `tenant-a-prod` na mwendeshaji B anaanza mtiririko `tenant-b-prod`, wanapata moja kwa moja folyo zisizo na muunganisho: +`persistent://tg/flow/triples-store:tenant-a-prod` +`persistent://tg/flow/triples-store:tenant-b-prod` + +**Huduma zilizoundwa vizuri kwa utumiaji wa wateja wengi:** +✅ **Usimamizi wa Maarifa (msingi)** - Inatatua moja kwa moja folyo kutoka usanidi wa mtiririko uliopitishwa katika ombi. + +**Huduma zinazohitaji marekebisho:** +🔴 **Huduma ya Usanidi** - Utangamano wa jina la parameter unazuia utengenezaji wa folyo +🔴 **Huduma ya Maktaba** - Mada ya uhifadhi iliyopangwa (iliyozungumzwa hapa chini) +🔴 **Huduma Zote** - Haiwezi kubadilisha nafasi ya Cassandra + +## Taarifa ya Tatizo + +### Tatizo #1: Utangamano wa Jina la Parameter katika AsyncProcessor +**CLI inafafanua:** `--config-queue` (jina lisilo wazi) +**Argparse inabadilisha kuwa:** `config_queue` (katika kamusi ya params) +**Msimu unatafuta:** `config_push_queue` +**Matokeo:** Parameter inakwama, inarudisha `persistent://tg/config/config` +**Athari:** Huathiri huduma zote 32+ zinazorithi kutoka kwa AsyncProcessor +**Inazuia:** Uwekaji wa wateja wengi hauna uwezo wa kutumia folyo maalum za mteja +**Suluhisho:** Badilisha parameter ya CLI kuwa `--config-push-queue` kwa uwazi (mabadiliko ya kuvunja yanakubalika kwani kipengele hicho kwa sasa kimevunjika) + +### Tatizo #2: Utangamano wa Jina la Parameter katika Huduma ya Usanidi +**CLI inafafanua:** `--push-queue` (jina lisilo wazi) +**Argparse inabadilisha kuwa:** `push_queue` (katika kamusi ya params) +**Msimu unatafuta:** `config_push_queue` +**Matokeo:** Parameter inakwama +**Athari:** Huduma ya usanidi haiwezi kutumia folyo ya kushinikiza maalum +**Suluhisho:** Badilisha parameter ya CLI kuwa `--config-push-queue` kwa utangamano na uwazi (mabadiliko ya kuvunja yanakubalika) + +### Tatizo #3: Nafasi ya Cassandra Iliyopangwa +**Sasa:** Nafasi ya Cassandra imepangwa kama `"config"`, `"knowledge"`, `"librarian"` katika huduma mbalimbali +**Matokeo:** Haiwezi kubadilisha nafasi ya utumiaji wa wateja wengi +**Athari:** Huduma za usanidi, msingi, na maktaba +**Inazuia:** Wateja wengi hawawezi kutumia nafasi tofauti za Cassandra + +### Tatizo #4: Usanidi wa Usimamizi wa Mkusanyiko ✅ IMEKAMILIKA +**Hapo awali:** Mkusanyiko ulihifadhiwa katika nafasi ya maktaba ya Cassandra kupitia meza tofauti ya mkusanyiko +**Hapo awali:** Maktaba ilitumia mada 4 zilizopangwa za usimamizi wa uhifadhi ili kuratibu uundaji/ufutaji wa mkusanyiko: + `vector_storage_management_topic` + `object_storage_management_topic` + `triples_storage_management_topic` + `storage_management_response_topic` +**Matatizo (Yaliyoshughulikiwa):** + Mada iliyopangwa haikuweza kubadilishwa kwa utumiaji wa wateja wengi + Uratibu wa async tata kati ya maktaba na huduma 4+ za uhifadhi + Meza tofauti ya Cassandra na miundombinu ya usimamizi + Folyo za ombi/jibu zisizo na uhai kwa operesheni muhimu +**Suluhisho Liliofanywa:** Kuhamishia mkusanyiko kwenye uhifadhi wa huduma ya usanidi, tumia kushinikiza usanidi kwa usambazaji +**Hali:** Uhifadhi wote wa nyuma umehamishwa kwenye mtindo wa `CollectionConfigHandler` + +## Suluhisho + +Hii inahusu Matatizo #1, #2, #3, na #4. + +### Sehemu ya 1: Marekebisho ya Utangamano wa Jina la Parameter + +#### Mabadiliko ya 1: Darasa la Msingi la AsyncProcessor - Badilisha Jina la Parameter ya CLI +**Faili:** `trustgraph-base/trustgraph/base/async_processor.py` +**Laini:** 260-264 + +**Sasa:** +```python +parser.add_argument( + '--config-queue', + default=default_config_queue, + help=f'Config push queue {default_config_queue}', +) +``` + +**Imara:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_queue, + help=f'Config push queue (default: {default_config_queue})', +) +``` + +**Sababu:** +Majina wazi na ya dhahiri zaidi +Inafanana na jina la ndani la `config_push_queue` +Mabadiliko yanayoweza kusababisha migogoro yanafaa kwani kipengele hivi sasa hakifanyi kazi +Hakuna mabadiliko ya msimbo yanayohitajika katika params.get() - tayari inatafuta jina sahihi + +#### Mabadiliko ya 2: Huduma ya Usanidi - Badilisha Jina la Paramu ya CLI +**Faili:** `trustgraph-flow/trustgraph/config/service/service.py` +**Laini:** 276-279 + +**Sasa:** +```python +parser.add_argument( + '--push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**Imara:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**Sababu:** +Majina wazi zaidi - "config-push-queue" yanaeleza zaidi kuliko "push-queue" tu. +Inalingana na jina la ndani `config_push_queue`. +Inafanana na parameter ya `--config-push-queue` ya AsyncProcessor. +Mabadiliko yanayoweza kusababisha migogoro yanafaa kwani kipengele hicho kwa sasa hakifanyi kazi. +Hakuna mabadiliko ya msimbo yanayohitajika katika params.get() - tayari inatafuta jina sahihi. + +### Sehemu ya 2: Ongeza Uwekaji wa Vigezo vya Keyspace ya Cassandra + +#### Mabadiliko ya 3: Ongeza Parameter ya Keyspace kwenye Moduli ya cassandra_config +**Faili:** `trustgraph-base/trustgraph/base/cassandra_config.py` + +**Ongeza hoja ya CLI** (katika kazi ya `add_cassandra_args()`): +```python +parser.add_argument( + '--cassandra-keyspace', + default=None, + help='Cassandra keyspace (default: service-specific)' +) +``` + +**Ongeza utumiaji wa vigezo vya mazingira** (katika kitendwa `resolve_cassandra_config()`): +```python +keyspace = params.get( + "cassandra_keyspace", + os.environ.get("CASSANDRA_KEYSPACE") +) +``` + +**Sasisha thamani ya kurudiwa** ya `resolve_cassandra_config()`: +Hivi sasa inarudisha: `(hosts, username, password)` +Badilisha ili irudishe: `(hosts, username, password, keyspace)` + +**Sababu:** +Inafanana na mtindo uliopo wa usanidi wa Cassandra +Inapatikana kwa huduma zote kupitia `add_cassandra_args()` +Inasaidia usanidi wa CLI na wa vigezo vya mazingira + +#### Mabadiliko ya 4: Huduma ya Usanidi - Tumia Vipengele Vilivyobadilishwa +**Faili:** `trustgraph-flow/trustgraph/config/service/service.py` + +**Laini ya 30** - Ondoa jina la keyspace lililokodishwa: +```python +# DELETE THIS LINE: +keyspace = "config" +``` + +**Mishale 69-73** - Sasisha utatuzi wa usanidi wa Cassandra: + +**Sasa:** +```python +cassandra_host, cassandra_username, cassandra_password = \ + resolve_cassandra_config(params) +``` + +**Imara:** +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="config") +``` + +**Sababu:** +Inahifadhi utangamano na "config" kama chaguo-msingi. +Inaruhusu kubadilishwa kupitia `--cassandra-keyspace` au `CASSANDRA_KEYSPACE`. + +#### Mabadiliko ya 5: Huduma za Msingi/Huduma ya Maarifa - Tumia Vipengele vya Kubadilika vya Nafasi ya Kuhifadhia +**Faili:** `trustgraph-flow/trustgraph/cores/service.py` + +**Laini ya 37** - Ondoa jina la nafasi ya kuhifadhia lililopangwa: +```python +# DELETE THIS LINE: +keyspace = "knowledge" +``` + +**Sasisha utatuzi wa usanidi wa Cassandra** (katika eneo sawa kama huduma ya usanidi): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="knowledge") +``` + +#### Mabadiliko ya 6: Huduma ya Maktaba - Tumia Vipengele Vilivyobadilika +**Faili:** `trustgraph-flow/trustgraph/librarian/service.py` + +**Laini ya 51** - Ondoa jina la eneo la kuhifadhi data lililopangwa: +```python +# DELETE THIS LINE: +keyspace = "librarian" +``` + +**Sasisha utatuzi wa usanidi wa Cassandra** (katika eneo sawa na huduma ya usanidi): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="librarian") +``` + +### Sehemu ya 3: Hamisha Usimamizi wa Mkusanyiko hadi Huduma ya Usanidi + +#### Muhtasari +Hamisha mkusanyiko kutoka kwa nafasi ya kuhifadhi "Cassandra librarian" hadi uhifadhi wa huduma ya usanidi. Hii huondoa mada za usimamizi wa uhifadhi zilizopangwa mapema na hurahisisha usanifu kwa kutumia mfumo uliopo wa usambazaji wa usanidi. + +#### Usanifu wa Sasa +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Cassandra Collections Table (librarian keyspace) + ↓ + Broadcast to 4 Storage Management Topics (hardcoded) + ↓ + Wait for 4+ Storage Service Responses + ↓ + Response to Gateway +``` + +#### Usanifu Mpya +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Config Service API (put/delete/getvalues) + ↓ + Cassandra Config Table (class='collections', key='user:collection') + ↓ + Config Push (to all subscribers on config-push-queue) + ↓ + All Storage Services receive config update independently +``` + +#### Mabadiliko ya 7: Msimamizi wa Mkusanyiko - Tumia API ya Huduma ya Usanidi +**Faili:** `trustgraph-flow/trustgraph/librarian/collection_manager.py` + +**Ondoa:** +Matumizi ya `LibraryTableStore` (Mistari 33, 40-41) +Uanzishaji wa watengenezaji wa usimamizi wa hifadhi (Mistari 86-140) +Njia ya `on_storage_response` (Mistari 400-430) +Ufuatiliaji wa `pending_deletions` (Mistari 57, 90-96, na matumizi katika maeneo mengine) + +**Ongeza:** +Mteja wa huduma ya usanidi kwa simu za API (mfumo wa ombi/jibu) + +**Uwekaji wa Mteja wa Usanidi:** +```python +# In __init__, add config request/response producers/consumers +from trustgraph.schema.services.config import ConfigRequest, ConfigResponse + +# Producer for config requests +self.config_request_producer = Producer( + client=pulsar_client, + topic=config_request_queue, + schema=ConfigRequest, +) + +# Consumer for config responses (with correlation ID) +self.config_response_consumer = Consumer( + taskgroup=taskgroup, + client=pulsar_client, + flow=None, + topic=config_response_queue, + subscriber=f"{id}-config", + schema=ConfigResponse, + handler=self.on_config_response, +) + +# Tracking for pending config requests +self.pending_config_requests = {} # request_id -> asyncio.Event +``` + +**Badilisha `list_collections` (Mistari 145-180):** +```python +async def list_collections(self, user, tag_filter=None, limit=None): + """List collections from config service""" + # Send getvalues request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='getvalues', + type='collections', + ) + + # Send request and wait for response + response = await self.send_config_request(request) + + # Parse collections from response + collections = [] + for key, value_json in response.values.items(): + if ":" in key: + coll_user, collection = key.split(":", 1) + if coll_user == user: + metadata = json.loads(value_json) + collections.append(CollectionMetadata(**metadata)) + + # Apply tag filtering in-memory (as before) + if tag_filter: + collections = [c for c in collections if any(tag in c.tags for tag in tag_filter)] + + # Apply limit + if limit: + collections = collections[:limit] + + return collections + +async def send_config_request(self, request): + """Send config request and wait for response""" + event = asyncio.Event() + self.pending_config_requests[request.id] = event + + await self.config_request_producer.send(request) + await event.wait() + + return self.pending_config_requests.pop(request.id + "_response") + +async def on_config_response(self, message, consumer, flow): + """Handle config response""" + response = message.value() + if response.id in self.pending_config_requests: + self.pending_config_requests[response.id + "_response"] = response + self.pending_config_requests[response.id].set() +``` + +**Badilisha `update_collection` (Mistari 182-312):** +```python +async def update_collection(self, user, collection, name, description, tags): + """Update collection via config service""" + # Create metadata + metadata = CollectionMetadata( + user=user, + collection=collection, + name=name, + description=description, + tags=tags, + ) + + # Send put request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='put', + type='collections', + key=f'{user}:{collection}', + value=json.dumps(metadata.to_dict()), + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config update failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and create collections +``` + +**Badilisha `delete_collection` (Mistari 314-398):** +```python +async def delete_collection(self, user, collection): + """Delete collection via config service""" + # Send delete request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='delete', + type='collections', + key=f'{user}:{collection}', + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config delete failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and delete collections +``` + +**Muundo wa Meta Data ya Mkusanyiko:** +Hifadhiwa katika jedwali la usanidi kama: `class='collections', key='user:collection'` +Thamani ni CollectionMetadata iliyopigwa muundo wa JSON (bila mashamba ya wakati) +Mashamba: `user`, `collection`, `name`, `description`, `tags` +Mfano: `class='collections', key='alice:my-docs', value='{"user":"alice","collection":"my-docs","name":"My Documents","description":"...","tags":["work"]}'` + +#### Mabadiliko ya 8: Huduma ya Maktaba - Ondoa Miundombinu ya Usimamizi wa Uhifadhi +**Faili:** `trustgraph-flow/trustgraph/librarian/service.py` + +**Ondoa:** +Wafalme wa usimamizi wa uhifadhi (Mistari 173-190): + `vector_storage_management_producer` + `object_storage_management_producer` + `triples_storage_management_producer` +Mfumo wa matumizi ya majibu ya uhifadhi (Mistari 192-201) +Msimamizi `on_storage_response` (Mistari 467-473) + +**Badilisha:** +Uanzishaji wa CollectionManager (Mistari 215-224) - ondoa vigezo vya mtayarishaji wa uhifadhi + +**Kumbuka:** API ya nje ya mkusanyiko inabaki bila kubadilika: +`list-collections` +`update-collection` +`delete-collection` + +#### Mabadiliko ya 9: Ondoa Jedwali la Mkusanyiko kutoka LibraryTableStore +**Faili:** `trustgraph-flow/trustgraph/tables/library.py` + +**Futa:** +Kauli ya kuunda jedwali la Mkusanyiko (Mistari 114-127) +Maneno yaliyotayarishwa ya Mkusanyiko (Mistari 205-240) +Mbinu zote za mkusanyiko (Mistari 578-717): + `ensure_collection_exists` + `list_collections` + `update_collection` + `delete_collection` + `get_collection` + `create_collection` + +**Mazingatio:** +Mkusanyiko sasa huhifadhiwa kwenye meza ya usanidi. +Mabadiliko yanayoweza kusababisha migogoro yanayokubalika - hakuna uhamisho wa data unaohitajika. +Inarahisisha huduma ya "librarian" kwa kiasi kikubwa. + +#### Mabadiliko ya 10: Huduma za Uhifadhi - Usimamizi wa Mkusanyiko Kulingana na Usanidi ✅ IMEKAMILIKA + +**Hali:** Vifaa vyote 11 vya uhifadhi vimehamishwa ili kutumia `CollectionConfigHandler`. + +**Huduma Zinazoathirika (jumla ya 11):** +Uingizaji wa hati: milvus, pinecone, qdrant +Uingizaji wa grafu: milvus, pinecone, qdrant +Uhifadhi wa vitu: cassandra +Uhifadhi wa "triples": cassandra, falkordb, memgraph, neo4j + +**Faili:** +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +`trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +`trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` + +**Mfumo wa Utendaji (huduma zote):** + +1. **Jisajili "config handler" katika `__init__`:** +```python +# Add after AsyncProcessor initialization +self.register_config_handler(self.on_collection_config) +self.known_collections = set() # Track (user, collection) tuples +``` + +2. **Teleza kidhibiti cha usanidi:** +```python +async def on_collection_config(self, config, version): + """Handle collection configuration updates""" + logger.info(f"Collection config version: {version}") + + if "collections" not in config: + return + + # Parse collections from config + # Key format: "user:collection" in config["collections"] + config_collections = set() + for key in config["collections"].keys(): + if ":" in key: + user, collection = key.split(":", 1) + config_collections.add((user, collection)) + + # Determine changes + to_create = config_collections - self.known_collections + to_delete = self.known_collections - config_collections + + # Create new collections (idempotent) + for user, collection in to_create: + try: + await self.create_collection_internal(user, collection) + self.known_collections.add((user, collection)) + logger.info(f"Created collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to create {user}/{collection}: {e}") + + # Delete removed collections (idempotent) + for user, collection in to_delete: + try: + await self.delete_collection_internal(user, collection) + self.known_collections.discard((user, collection)) + logger.info(f"Deleted collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to delete {user}/{collection}: {e}") +``` + +3. **Anzisha kukusanya data inayojulikana wakati wa kuanza:** +```python +async def start(self): + """Start the processor""" + await super().start() + await self.sync_known_collections() + +async def sync_known_collections(self): + """Query backend to populate known_collections set""" + # Backend-specific implementation: + # - Milvus/Pinecone/Qdrant: List collections/indexes matching naming pattern + # - Cassandra: Query keyspaces or collection metadata + # - Neo4j/Memgraph/FalkorDB: Query CollectionMetadata nodes + pass +``` + +4. **Kuboresha mbinu zilizopo za utendaji:** +```python +# Rename and remove response sending: +# handle_create_collection → create_collection_internal +# handle_delete_collection → delete_collection_internal + +async def create_collection_internal(self, user, collection): + """Create collection (idempotent)""" + # Same logic as current handle_create_collection + # But remove response producer calls + # Handle "already exists" gracefully + pass + +async def delete_collection_internal(self, user, collection): + """Delete collection (idempotent)""" + # Same logic as current handle_delete_collection + # But remove response producer calls + # Handle "not found" gracefully + pass +``` + +5. **Ondoa miundomino ya usimamizi wa hifadhi:** + Ondoa usanidi na uanzishaji wa `self.storage_request_consumer` + Ondoa usanidi wa `self.storage_response_producer` + Ondoa njia ya utaratibu wa `on_storage_management` + Ondoa vipimo (metrics) vya usimamizi wa hifadhi + Ondoa uingizaji (imports): `StorageManagementRequest`, `StorageManagementResponse` + +**Mazingatio Maalum ya Seva ya Nyuma (Backend):** + +**Vihifadhi vya data (Vector stores) (Milvus, Pinecone, Qdrant):** Fuatilia `(user, collection)` ya kimantiki katika `known_collections`, lakini inaweza kuunda mkusanyiko mwingi wa seva ya nyuma kwa kila kipimo. Endeleza mtindo wa uundaji wa polepole. Operesheni za kufuta lazima iondoe matoleo yote ya kipimo. + +**Cassandra Objects:** Mikusanyiko ni sifa za mstari, sio muundo. Fuatilia taarifa za kiwango cha keyspace. + +**Vihifadhi vya grafu (Graph stores) (Neo4j, Memgraph, FalkorDB):** Tafuta nodi za `CollectionMetadata` wakati wa kuanza. Unda/futa nodi za metadata wakati wa kusawazisha. + +**Cassandra Triples:** Tumia API ya `KnowledgeGraph` kwa operesheni za mkusanyiko. + +**Mambo Muhimu ya Ubunifu:** + +**Ulinganifu wa muda (Eventual consistency):** Hakuna utaratibu wa ombi/jibu, utaratibu wa kusukuma usanidi hutangazwa +**Ulinganifu (Idempotency):** Operesheni zote za kuunda/kufuta lazima ziwe salama kufanywa tena +**Usimamizi wa makosa (Error handling):** Leta makosa lakini usizuie sasisho za usanidi +**Kujirejesha (Self-healing):** Operesheni ambazo zimefeli zitajaribu tena wakati wa sasisho la usanidi lijayo +**Muundo wa ufunguo wa mkusanyiko (Collection key format):** `"user:collection"` katika `config["collections"]` + +#### Mabadiliko ya 11: Sasisha Mpango wa Mkusaniko - Ondoa Alama za Muda (Timestamps) +**Faili:** `trustgraph-base/trustgraph/schema/services/collection.py` + +**Badilisha CollectionMetadata (Mistari 13-21):** +Ondoa sehemu za `created_at` na `updated_at`: +```python +class CollectionMetadata(Record): + user = String() + collection = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() +``` + +**Badilisha `CollectionManagementRequest` (Mistari 25-47):** +Ondoa sehemu za wakati: +```python +class CollectionManagementRequest(Record): + operation = String() + user = String() + collection = String() + timestamp = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() + tag_filter = Array(String()) + limit = Integer() +``` + +**Sababu:** +Wakati (Timestamps) havi faida kwa makusanyo. +Huduma ya usanidi (config) inadhibiti ufuatiliaji wake wa toleo. +Inarahisisha muundo na kupunguza uhifadhi. + +#### Faida za Uhamishaji wa Huduma ya Usanidi + +1. ✅ **Inaondoa masuala ya usimamizi wa uhifadhi yaliyopangwa awali** - Inatatua kizuizi cha wateja wengi. +2. ✅ **Uratibu rahisi zaidi** - Hakuna utaratibu ngumu wa kusubiri majibu kutoka kwa huduma 4+ za uhifadhi. +3. ✅ **Ulinganifu wa muda** - Huduma za uhifadhi husasishwa kwa kujitegemea kupitia utaratibu wa usanidi. +4. ✅ **Uaminifu bora zaidi** - Uratibu wa kudumu wa usanidi dhidi ya ombi/jibu lisilo la kudumu. +5. ✅ **Mfumo wa usanidi uliounganishwa** - Makusanyo yanatibiwa kama usanidi. +6. ✅ **Inapunguza utata** - Inondoa mistari ~300 ya nambari ya uratibu. +7. ✅ **Inafaa kwa wateja wengi** - Usanidi tayari una msaada wa kutenganisha wateja kupitia nafasi. +8. ✅ **Ufuatiliaji wa toleo** - Mfumo wa toleo wa huduma ya usanidi hutoa kumbukumbu ya uhakiki. + +## Maelezo ya Utendaji + +### Utangamano wa Nyuma + +**Mabadiliko ya Vigezo:** +Mabadiliko ya majina ya vigezo vya CLI ni mabadiliko ambayo yanaweza kusababisha matatizo lakini yanapokelewa (kipengele hapo kwa sasa hakifanyi kazi). +Huduma zinafanya kazi bila vigezo (tumia chaguo-msingi). +Nafasi chaguo-msingi zimehifadhiwa: "config", "knowledge", "librarian". +Kichefuchefu chaguo-msingi: `persistent://tg/config/config` + +**Usimamizi wa Makusanyo:** +**Mabadiliko ambayo yanaweza kusababisha matatizo:** Jedwali la makusanyo limeondolewa kutoka kwa nafasi ya "librarian". +**Hakuna uhamishaji wa data unaotolewa** - inakubalika kwa hatua hii. +API ya makusanyo ya nje haijabadilika (operesheni za kuorodhesha/kusasisha/kufuta). +Muundo wa metadata ya makusanyo umeboreshwa (wakati umeondolewa). + +### Mahitaji ya Majaribio + +**Majaribio ya Vigezo:** +1. Thibitisha kwamba kiparamu `--config-push-queue` hufanya kazi kwenye huduma ya "graph-embeddings". +2. Thibitisha kwamba kiparamu `--config-push-queue` hufanya kazi kwenye huduma ya "text-completion". +3. Thibitisha kwamba kiparamu `--config-push-queue` hufanya kazi kwenye huduma ya usanidi. +4. Thibitisha kwamba kiparamu `--cassandra-keyspace` hufanya kazi kwa huduma ya usanidi. +5. Thibitisha kwamba kiparamu `--cassandra-keyspace` hufanya kazi kwa huduma ya "cores". +6. Thibitisha kwamba kiparamu `--cassandra-keyspace` hufanya kazi kwa huduma ya "librarian". +7. Thibitisha kwamba huduma zinafanya kazi bila vigezo (zinatumia chaguo-msingi). +8. Thibitisha uwekaji wa wateja wengi na majina ya kichefuchefu na nafasi maalum. + +**Majaribio ya Usimamizi wa Makusanyo:** +9. Thibitisha operesheni `list-collections` kupitia huduma ya usanidi. +10. Thibitisha kwamba `update-collection` huunda/kusasisha kwenye jedwali la usanidi. +11. Thibitisha kwamba `delete-collection` huondoa kutoka kwenye jedwali la usanidi. +12. Thibitisha kwamba utaratibu wa "config push" huwashwa wakati wa sasisho za makusanyo. +13. Thibitisha kwamba utaratibu wa kuchujwa wa lebo hufanya kazi na uhifadhi unaotegemea usanidi. +14. Thibitisha kwamba operesheni za makusanyo hufanya kazi bila sehemu za wakati. + +### Mfano wa Uwekaji wa Wateja Wengi +```bash +# Tenant: tg-dev +graph-embeddings \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config + +config-service \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config \ + --cassandra-keyspace tg_dev_config +``` + +## Uchambuzi wa Athari + +### Huduma Zinazoathiriwa na Mabadiliko 1-2 (Kubadilisha Jina la Paramu ya CLI) +Huduma zote zinazorithi kutoka kwa AsyncProcessor au FlowProcessor: +config-service +cores-service +librarian-service +graph-embeddings +document-embeddings +text-completion-* (wote watoa huduma) +extract-* (wote waangamizi) +query-* (huduma zote za kuulizia) +retrieval-* (huduma zote za RAG) +storage-* (huduma zote za kuhifadhi) +Na huduma zingine 20+ + +### Huduma Zinazoathiriwa na Mabadiliko 3-6 (Nafasi ya Cassandra) +config-service +cores-service +librarian-service + +### Huduma Zinazoathiriwa na Mabadiliko 7-11 (Usimamizi wa Mkusanyiko) + +**Mabadiliko ya Mara Moja:** +librarian-service (collection_manager.py, service.py) +tables/library.py (ondoa meza ya mkusanyiko) +schema/services/collection.py (ondoa alama ya muda) + +**Mabadiliko Yaliyokamilika (Mabadiliko ya 10):** ✅ +Huduma zote za kuhifadhi (jumla ya 11) - zimehamishwa kwa utaratibu wa kusukuma usanidi kwa mkusanyiko kupitia `CollectionConfigHandler` +Mfumo wa usimamizi wa kuhifadhi umeondolewa kutoka `storage.py` + +## Mambo ya Kuzingatia ya Baadaye + +### Mfumo wa Nafasi ya Mtumiaji Kila Mmoja + +Huduma zingine hutumia **nafasi za mtumiaji kila mmoja** kwa njia ya moja kwa moja, ambapo kila mtumiaji hupata nafasi yake mwenyewe ya Cassandra: + +**Huduma zenye nafasi za mtumiaji kila mmoja:** +1. **Huduma ya Uulizia ya Triples** (`trustgraph-flow/trustgraph/query/triples/cassandra/service.py:65`) + Inatumia `keyspace=query.user` +2. **Huduma ya Uulizia ya Vitabu** (`trustgraph-flow/trustgraph/query/objects/cassandra/service.py:479`) + Inatumia `keyspace=self.sanitize_name(user)` +3. **Ufikiaji wa Moja kwa Moja wa KnowledgeGraph** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py:18`) + Paramu ya chaguo-msingi `keyspace="trustgraph"` + +**Hali:** Hizi **hazibadiliki** katika maelezo haya. + +**Hakikisha Upya wa Baadaye:** +Tathmini ikiwa mfumo wa nafasi ya mtumiaji kila mmoja huunda masuala ya kutenganisha wateja +Fikiria ikiwa usambazaji wa wateja mbalimbali unahitaji muundo wa mbele ya nafasi (k.m., `tenant_a_user1`) +Angalia uwezekano wa migongano ya kitambulisho cha mtumiaji kati ya wateja +Tathmini ikiwa nafasi moja iliyoshirikiwa kwa kila mteja na kutenganisha mstari kwa msingi wa mtumiaji ni bora + +**Kumbuka:** Hii haizuie utekelezaji wa sasa wa wateja mbalimbali lakini inapaswa kukaguliwa kabla ya utekelezaji wa wateja mbalimbali wa uzalishaji. + +## Awamu za Utendaji + +### Awamu ya 1: Marekebisho ya Paramu (Mabadiliko 1-6) +Marekebisho ya jina la paramu `--config-push-queue` +Ongeza msaada wa paramu `--cassandra-keyspace` +**Matokeo:** Mpangilio wa folyo na nafasi ya wateja mbalimbali umeanzishwa + +### Awamu ya 2: Uhamishaji wa Usimamizi wa Mkusanyiko (Mabadiliko 7-9, 11) +Hamisha uhifadhi wa mkusanyiko kwa huduma ya usanidi +Ondoa meza ya mkusanyiko kutoka kwa librarian +Sasisha mfumo wa mkusanyiko (ondoa alama za muda) +**Matokeo:** Huondoa mada zilizokota za usimamizi wa uhifadhi, hurahisisha librarian + +### Awamu ya 3: Masasisho ya Huduma ya Uhifadhi (Mabadiliko ya 10) ✅ IMEKAMILIKA +Zesasisha huduma zote za kuhifadhi ili zitumie utaratibu wa kusukuma usanidi kwa mkusanyiko kupitia `CollectionConfigHandler` +Ondoa miundombinu ya ombi/jibu la usimamizi wa uhifadhi +Ondoa ufafanuzi wa zamani wa mfumo +**Matokeo:** Usimamizi kamili wa mkusanyiko unaotegemea usanidi umefikiwa + +## Marejeleo +GitHub Issue: https://github.com/trustgraph-ai/trustgraph/issues/582 +Faili Zinazohusiana: + `trustgraph-base/trustgraph/base/async_processor.py` + `trustgraph-base/trustgraph/base/cassandra_config.py` + `trustgraph-base/trustgraph/schema/core/topic.py` + `trustgraph-base/trustgraph/schema/services/collection.py` + `trustgraph-flow/trustgraph/config/service/service.py` + `trustgraph-flow/trustgraph/cores/service.py` + `trustgraph-flow/trustgraph/librarian/service.py` + `trustgraph-flow/trustgraph/librarian/collection_manager.py` + `trustgraph-flow/trustgraph/tables/library.py` diff --git a/docs/tech-specs/multi-tenant-support.tr.md b/docs/tech-specs/multi-tenant-support.tr.md new file mode 100644 index 00000000..10d1fd8e --- /dev/null +++ b/docs/tech-specs/multi-tenant-support.tr.md @@ -0,0 +1,772 @@ +# Teknik Özellikler: Çok Kiracılı Destek + +## Genel Bakış + +Kuyumuzu özelleştirmeyi engelleyen parametre adı eşleşmezliklerini düzelterek ve Cassandra anahtar alanı parametrelemesini ekleyerek çok kiracılı dağıtımları etkinleştirin. + +## Mimari Bağlam + +### Akış Tabanlı Kuyruk Çözümlemesi + +TrustGraph sistemi, dinamik kuyruk çözümlemesi için **akış tabanlı bir mimari** kullanır ve bu, doğal olarak çok kiracılığı destekler: + +**Akış Tanımları**, Cassandra'da saklanır ve arayüz tanımları aracılığıyla kuyruk adlarını belirtir. +**Kuyruk adları**, akış örneği kimlikleriyle değiştirilen `{id}` değişkenlerine sahip **şablonlar** kullanır. +**Hizmetler**, istek zamanında akış yapılandırmalarını arayarak **kuyrukları dinamik olarak çözümler**. +**Her kiracı, farklı kuyruk adlarına sahip benzersiz akışlara sahip olabilir**, bu da izolasyon sağlar. + +Örnek akış arayüz tanımı: +```json +{ + "interfaces": { + "triples-store": "persistent://tg/flow/triples-store:{id}", + "graph-embeddings-store": "persistent://tg/flow/graph-embeddings-store:{id}" + } +} +``` + +Kiracı A, `tenant-a-prod` akışını başlatığında ve kiracı B, `tenant-b-prod` akışını başlattığında, otomatik olarak izole edilmiş kuyruklar elde ederler: +`persistent://tg/flow/triples-store:tenant-a-prod` +`persistent://tg/flow/triples-store:tenant-b-prod` + +**Çoklu kiracılığa doğru şekilde tasarlanmış hizmetler:** +✅ **Bilgi Yönetimi (çekirdekler)** - İsteğe eklenen akış yapılandırmasından kuyrukları dinamik olarak çözer. + +**Düzeltilmesi gereken hizmetler:** +🔴 **Yapılandırma Hizmeti** - Parametre adı eşleşmezliği, kuyruk özelleştirmesini engeller. +🔴 **Kütüphaneci Hizmeti** - Sabit kodlanmış depolama yönetimi konuları (aşağıda açıklanmıştır). +🔴 **Tüm Hizmetler** - Cassandra anahtar alanını özelleştiremezsiniz. + +## Sorun Tanımı + +### Sorun #1: AsyncProcessor'daki Parametre Adı Eşleşmezliği +**CLI tanımları:** `--config-queue` (belirsiz adlandırma) +**Argparse'ın dönüştürdüğü:** `config_queue` (params sözlüğünde) +**Kodun aradığı:** `config_push_queue` +**Sonuç:** Parametre göz ardı edilir ve varsayılan olarak `persistent://tg/config/config` olur. +**Etkisi:** AsyncProcessor'dan türeyen 32'den fazla hizmeti etkiler. +**Engeller:** Çoklu kiracılı dağıtımlar, kiracıya özel yapılandırma kuyruklarını kullanamaz. +**Çözüm:** CLI parametresinin adını `--config-push-queue` olarak değiştirerek netliği artırın (özellik şu anda bozuk olduğundan, bozucu değişiklik kabul edilebilir). + +### Sorun #2: Yapılandırma Hizmetindeki Parametre Adı Eşleşmezliği +**CLI tanımları:** `--push-queue` (belirsiz adlandırma) +**Argparse'ın dönüştürdüğü:** `push_queue` (params sözlüğünde) +**Kodun aradığı:** `config_push_queue` +**Sonuç:** Parametre göz ardı edilir. +**Etkisi:** Yapılandırma hizmeti, özel bir push kuyruğunu kullanamaz. +**Çözüm:** CLI parametresinin adını `--config-push-queue` olarak değiştirerek tutarlılığı ve netliği artırın (bozucu değişiklik kabul edilebilir). + +### Sorun #3: Sabit Kodlanmış Cassandra Anahtar Alanı +**Mevcut durum:** Anahtar alanı, çeşitli hizmetlerde `"config"`, `"knowledge"`, `"librarian"` olarak sabit kodlanmıştır. +**Sonuç:** Çoklu kiracılı dağıtımlar için anahtar alanı özelleştirilemez. +**Etkisi:** Yapılandırma, çekirdek ve kütüphaneci hizmetleri. +**Engeller:** Birden fazla kiracı, ayrı Cassandra anahtar alanlarını kullanamaz. + +### Sorun #4: Koleksiyon Yönetimi Mimarisi ✅ TAMAMLANDI +**Önceki durum:** Koleksiyonlar, ayrı koleksiyon tablosu aracılığıyla Cassandra kütüphaneci anahtar alanında depolanıyordu. +**Önceki durum:** Kütüphaneci, koleksiyon oluşturma/silme işlemini koordine etmek için 4 sabit kodlanmış depolama yönetimi konusunu kullanıyordu: + `vector_storage_management_topic` + `object_storage_management_topic` + `triples_storage_management_topic` + `storage_management_response_topic` +**Sorunlar (Çözüldü):** + Sabit kodlanmış konular, çoklu kiracılı dağıtımlar için özelleştirilemezdi. + Kütüphaneci ile 4+ depolama hizmeti arasında karmaşık asenkron koordinasyon. + Ayrı bir Cassandra tablosu ve yönetim altyapısı. + Kritik işlemler için kalıcı olmayan istek/yanıt kuyrukları. +**Uygulanan Çözüm:** Koleksiyonları yapılandırma hizmeti depolamasına taşıdık, dağıtım için yapılandırma push'u kullandık. +**Durum:** Tüm depolama arka uçları `CollectionConfigHandler` modeline taşınmıştır. + +## Çözüm + +Bu özellik, Sorunlar #1, #2, #3 ve #4'ü ele alır. + +### 1. Bölüm: Parametre Adı Eşleşmezliklerini Düzeltme + +#### Değişiklik 1: AsyncProcessor Temel Sınıfı - CLI Parametresinin Adını Değiştirme +**Dosya:** `trustgraph-base/trustgraph/base/async_processor.py` +**Satır:** 260-264 + +**Mevcut:** +```python +parser.add_argument( + '--config-queue', + default=default_config_queue, + help=f'Config push queue {default_config_queue}', +) +``` + +**Sabit:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_queue, + help=f'Config push queue (default: {default_config_queue})', +) +``` + +**Gerekçe:** +Daha açık, daha kesin bir adlandırma +İç değişken adıyla eşleşiyor: `config_push_queue` +Özellik şu anda çalışmadığı için, bu bir değişikliktir ve kabul edilebilir. +params.get() içinde herhangi bir kod değişikliğine gerek yok; zaten doğru adı arıyor. + +#### Değişiklik 2: Konfigürasyon Servisi - CLI Parametresinin Yeniden Adlandırılması +**Dosya:** `trustgraph-flow/trustgraph/config/service/service.py` +**Satır:** 276-279 + +**Mevcut:** +```python +parser.add_argument( + '--push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**Sabit:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**Gerekçe:** +Daha anlaşılır bir adlandırma - "config-push-queue", sadece "push-queue"den daha açık. +İç değişken adıyla eşleşiyor: `config_push_queue` +AsyncProcessor'ın `--config-push-queue` parametresiyle tutarlı. +Özellik şu anda çalışmadığı için değişiklik kabul edilebilir. +params.get() içinde herhangi bir kod değişikliğine gerek yok - zaten doğru adı arıyor. + +### 2. Bölüm: Cassandra Keyspace Parametrelendirmesi + +#### 3. Değişiklik: cassandra_config Modülüne Keyspace Parametresi Ekle +**Dosya:** `trustgraph-base/trustgraph/base/cassandra_config.py` + +**CLI argümanı ekle** (`add_cassandra_args()` fonksiyonunda): +```python +parser.add_argument( + '--cassandra-keyspace', + default=None, + help='Cassandra keyspace (default: service-specific)' +) +``` + +**Ortam değişkeni desteği ekleyin** (`resolve_cassandra_config()` fonksiyonunda): +```python +keyspace = params.get( + "cassandra_keyspace", + os.environ.get("CASSANDRA_KEYSPACE") +) +``` + +**`resolve_cassandra_config()`'nin dönüş değerini güncelleyin:** +Şu anda döndürüyor: `(hosts, username, password)` +Aşağıdaki değeri döndürmesi için değiştirin: `(hosts, username, password, keyspace)` + +**Gerekçe:** +Mevcut Cassandra yapılandırma kalıbıyla tutarlı +`add_cassandra_args()` aracılığıyla tüm hizmetlere erişilebilir +Hem CLI hem de ortam değişkeni yapılandırmasını destekler + +#### Değişiklik 4: Yapılandırma Hizmeti - Parametreli Keyspace Kullanımı +**Dosya:** `trustgraph-flow/trustgraph/config/service/service.py` + +**30. Satır** - Sabit kodlanmış keyspace'i kaldırın: +```python +# DELETE THIS LINE: +keyspace = "config" +``` + +**69-73 satırları** - Cassandra yapılandırma çözümlemesi güncellendi: + +**Mevcut:** +```python +cassandra_host, cassandra_username, cassandra_password = \ + resolve_cassandra_config(params) +``` + +**Sabit:** +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="config") +``` + +**Gerekçe:** +"config" varsayılan olarak kullanılarak geriye dönük uyumluluk sağlanır. +`--cassandra-keyspace` veya `CASSANDRA_KEYSPACE` ile geçersiz kılınabilir. + +#### Değişiklik 5: Cores/Bilgi Hizmeti - Parametreleştirilmiş Anahtar Alanı Kullanımı +**Dosya:** `trustgraph-flow/trustgraph/cores/service.py` + +**Satır 37** - Sabit kodlanmış anahtar alanını kaldırın: +```python +# DELETE THIS LINE: +keyspace = "knowledge" +``` + +**Cassandra yapılandırma çözümlemesi güncellendi** (yapılandırma hizmetiyle benzer konumda): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="knowledge") +``` + +#### Değişiklik 6: Kütüphaneci Hizmeti - Parametreleştirilmiş Anahtar Alanı Kullanımı +**Dosya:** `trustgraph-flow/trustgraph/librarian/service.py` + +**Satır 51** - Sabit kodlanmış anahtar alanını kaldır: +```python +# DELETE THIS LINE: +keyspace = "librarian" +``` + +**Cassandra yapılandırma çözümlemesi güncellendi** (yapılandırma hizmetiyle benzer konumda): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="librarian") +``` + +### 3. Bölüm: Koleksiyon Yönetimini Config Servisine Taşıma + +#### Genel Bakış +Koleksiyonları Cassandra librarian anahtar alanından config servisi depolama alanına taşıyın. Bu, sabit kodlanmış depolama yönetimi konularını ortadan kaldırır ve dağıtım için mevcut config push mekanizmasını kullanarak mimariyi basitleştirir. + +#### Mevcut Mimari +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Cassandra Collections Table (librarian keyspace) + ↓ + Broadcast to 4 Storage Management Topics (hardcoded) + ↓ + Wait for 4+ Storage Service Responses + ↓ + Response to Gateway +``` + +#### Yeni Mimari +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Config Service API (put/delete/getvalues) + ↓ + Cassandra Config Table (class='collections', key='user:collection') + ↓ + Config Push (to all subscribers on config-push-queue) + ↓ + All Storage Services receive config update independently +``` + +#### Değişiklik 7: Koleksiyon Yöneticisi - Config Hizmeti API'sini Kullanın +**Dosya:** `trustgraph-flow/trustgraph/librarian/collection_manager.py` + +**Kaldırılacaklar:** +`LibraryTableStore` kullanımı (33, 40-41 satırları) +Depolama yönetimi üreticilerinin başlatılması (86-140 satırları) +`on_storage_response` metodu (400-430 satırları) +`pending_deletions` takibi (57, 90-96 satırları ve tüm kullanım alanları) + +**Eklenecekler:** +API çağrıları için Config hizmeti istemcisi (istek/yanıt kalıbı) + +**Config İstemcisi Kurulumu:** +```python +# In __init__, add config request/response producers/consumers +from trustgraph.schema.services.config import ConfigRequest, ConfigResponse + +# Producer for config requests +self.config_request_producer = Producer( + client=pulsar_client, + topic=config_request_queue, + schema=ConfigRequest, +) + +# Consumer for config responses (with correlation ID) +self.config_response_consumer = Consumer( + taskgroup=taskgroup, + client=pulsar_client, + flow=None, + topic=config_response_queue, + subscriber=f"{id}-config", + schema=ConfigResponse, + handler=self.on_config_response, +) + +# Tracking for pending config requests +self.pending_config_requests = {} # request_id -> asyncio.Event +``` + +**`list_collections`'ı Değiştirin (145-180. satırlar):** +```python +async def list_collections(self, user, tag_filter=None, limit=None): + """List collections from config service""" + # Send getvalues request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='getvalues', + type='collections', + ) + + # Send request and wait for response + response = await self.send_config_request(request) + + # Parse collections from response + collections = [] + for key, value_json in response.values.items(): + if ":" in key: + coll_user, collection = key.split(":", 1) + if coll_user == user: + metadata = json.loads(value_json) + collections.append(CollectionMetadata(**metadata)) + + # Apply tag filtering in-memory (as before) + if tag_filter: + collections = [c for c in collections if any(tag in c.tags for tag in tag_filter)] + + # Apply limit + if limit: + collections = collections[:limit] + + return collections + +async def send_config_request(self, request): + """Send config request and wait for response""" + event = asyncio.Event() + self.pending_config_requests[request.id] = event + + await self.config_request_producer.send(request) + await event.wait() + + return self.pending_config_requests.pop(request.id + "_response") + +async def on_config_response(self, message, consumer, flow): + """Handle config response""" + response = message.value() + if response.id in self.pending_config_requests: + self.pending_config_requests[response.id + "_response"] = response + self.pending_config_requests[response.id].set() +``` + +**`update_collection`'yi değiştirin (182-312. satırlar):** +```python +async def update_collection(self, user, collection, name, description, tags): + """Update collection via config service""" + # Create metadata + metadata = CollectionMetadata( + user=user, + collection=collection, + name=name, + description=description, + tags=tags, + ) + + # Send put request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='put', + type='collections', + key=f'{user}:{collection}', + value=json.dumps(metadata.to_dict()), + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config update failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and create collections +``` + +**`delete_collection`'ı Değiştirin (314-398. satırlar):** +```python +async def delete_collection(self, user, collection): + """Delete collection via config service""" + # Send delete request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='delete', + type='collections', + key=f'{user}:{collection}', + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config delete failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and delete collections +``` + +**Koleksiyon Meta Veri Formatı:** +`config` tablosunda şu şekilde saklanır: `class='collections', key='user:collection'` +Değer, zaman damgası alanları olmadan JSON olarak seri hale getirilmiş `CollectionMetadata`'dır. +Alanlar: `user`, `collection`, `name`, `description`, `tags` +Örnek: `class='collections', key='alice:my-docs', value='{"user":"alice","collection":"my-docs","name":"My Documents","description":"...","tags":["work"]}'` + +#### 8. Değişiklik: Kütüphane Hizmeti - Depolama Yönetimi Altyapısını Kaldır +**Dosya:** `trustgraph-flow/trustgraph/librarian/service.py` + +**Kaldır:** +Depolama yönetimi üreticileri (173-190. satırlar): + `vector_storage_management_producer` + `object_storage_management_producer` + `triples_storage_management_producer` +Depolama yanıt tüketici (192-201. satırlar) +`on_storage_response` işleyici (467-473. satırlar) + +**Değiştir:** +`CollectionManager` başlatma (215-224. satırlar) - depolama üretici parametrelerini kaldır + +**Not:** Harici koleksiyon API'si değişmeden kalır: +`list-collections` +`update-collection` +`delete-collection` + +#### 9. Değişiklik: Koleksiyonlar Tablosunu `LibraryTableStore`'dan Kaldır +**Dosya:** `trustgraph-flow/trustgraph/tables/library.py` + +**Sil:** +Koleksiyonlar tablosu `CREATE` ifadesi (114-127. satırlar) +Koleksiyonlar için hazırlanmış ifadeler (205-240. satırlar) +Tüm koleksiyon metotları (578-717. satırlar): + `ensure_collection_exists` + `list_collections` + `update_collection` + `delete_collection` + `get_collection` + `create_collection` + +**Gerekçe:** +Koleksiyonlar artık `config` tablosunda saklanıyor +Uyumluluk bozan bir değişiklik kabul edilebilir - veri taşıma işlemine gerek yok +Kütüphane hizmetini önemli ölçüde basitleştirir + +#### 10. Değişiklik: Depolama Hizmetleri - Yapılandırmaya Dayalı Koleksiyon Yönetimi ✅ TAMAMLANDI + +**Durum:** 11 depolama arka ucunun tamamı, `CollectionConfigHandler`'ı kullanmak üzere güncellendi. + +**Etkilenen Hizmetler (toplam 11):** +Belge gömülüleri: milvus, pinecone, qdrant +Grafik gömülüleri: milvus, pinecone, qdrant +Nesne depolama: cassandra +Üçlü depolama: cassandra, falkordb, memgraph, neo4j + +**Dosyalar:** +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +`trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +`trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` + +**Uygulama Deseni (tüm hizmetler):** + +1. **Yapılandırma işleyiciyi `__init__` içinde kaydedin:** +```python +# Add after AsyncProcessor initialization +self.register_config_handler(self.on_collection_config) +self.known_collections = set() # Track (user, collection) tuples +``` + +2. **Yapılandırma yöneticisini uygulayın:** +```python +async def on_collection_config(self, config, version): + """Handle collection configuration updates""" + logger.info(f"Collection config version: {version}") + + if "collections" not in config: + return + + # Parse collections from config + # Key format: "user:collection" in config["collections"] + config_collections = set() + for key in config["collections"].keys(): + if ":" in key: + user, collection = key.split(":", 1) + config_collections.add((user, collection)) + + # Determine changes + to_create = config_collections - self.known_collections + to_delete = self.known_collections - config_collections + + # Create new collections (idempotent) + for user, collection in to_create: + try: + await self.create_collection_internal(user, collection) + self.known_collections.add((user, collection)) + logger.info(f"Created collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to create {user}/{collection}: {e}") + + # Delete removed collections (idempotent) + for user, collection in to_delete: + try: + await self.delete_collection_internal(user, collection) + self.known_collections.discard((user, collection)) + logger.info(f"Deleted collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to delete {user}/{collection}: {e}") +``` + +3. **Başlangıçta bilinen koleksiyonları başlatın:** +```python +async def start(self): + """Start the processor""" + await super().start() + await self.sync_known_collections() + +async def sync_known_collections(self): + """Query backend to populate known_collections set""" + # Backend-specific implementation: + # - Milvus/Pinecone/Qdrant: List collections/indexes matching naming pattern + # - Cassandra: Query keyspaces or collection metadata + # - Neo4j/Memgraph/FalkorDB: Query CollectionMetadata nodes + pass +``` + +4. **Mevcut işleyici metotları yeniden düzenleyin:** +```python +# Rename and remove response sending: +# handle_create_collection → create_collection_internal +# handle_delete_collection → delete_collection_internal + +async def create_collection_internal(self, user, collection): + """Create collection (idempotent)""" + # Same logic as current handle_create_collection + # But remove response producer calls + # Handle "already exists" gracefully + pass + +async def delete_collection_internal(self, user, collection): + """Delete collection (idempotent)""" + # Same logic as current handle_delete_collection + # But remove response producer calls + # Handle "not found" gracefully + pass +``` + +5. **Depolama yönetimi altyapısını kaldırın:** + `self.storage_request_consumer` kurulumunu ve başlatmayı kaldırın + `self.storage_response_producer` kurulumunu kaldırın + `on_storage_management` dağıtıcı yöntemini kaldırın + Depolama yönetimi için metrikleri kaldırın + Aşağıdaki import'ları kaldırın: `StorageManagementRequest`, `StorageManagementResponse` + +**Arka Uç Özel Hususlar:** + +**Vektör depoları (Milvus, Pinecone, Qdrant):** `known_collections` içinde mantıksal `(user, collection)`'ı takip edin, ancak her boyut için birden fazla arka uç koleksiyonu oluşturabilir. Tembel oluşturma modeline devam edin. Silme işlemleri, tüm boyut varyantlarını kaldırmalıdır. + +**Cassandra Nesneleri:** Koleksiyonlar, yapılar değil, satır özellikleridir. Veritabanı seviyesindeki bilgileri takip edin. + +**Grafik depoları (Neo4j, Memgraph, FalkorDB):** Başlangıçta `CollectionMetadata` düğümlerini sorgulayın. Senkronizasyon sırasında meta veri düğümlerini oluşturun/silin. + +**Cassandra Üçlüleri:** Koleksiyon işlemleri için `KnowledgeGraph` API'sini kullanın. + +**Temel Tasarım Noktaları:** + +**Son tutarlılık:** İstek/yanıt mekanizması yoktur, yapılandırma itmesi yayınlanır +**Tekrarlanabilirlik:** Tüm oluşturma/silme işlemleri, yeniden denenmek üzere güvenli olmalıdır +**Hata işleme:** Hataları günlüğe kaydedin, ancak yapılandırma güncellemelerini engellemeyin +**Kendini iyileştirme:** Başarısız işlemler, bir sonraki yapılandırma itmesinde yeniden denenecektir +**Koleksiyon anahtar biçimi:** `config["collections"]` içinde `"user:collection"` + +#### Değişiklik 11: Koleksiyon Şemasını Güncelle - Zaman Damgalarını Kaldır +**Dosya:** `trustgraph-base/trustgraph/schema/services/collection.py` + +**CollectionMetadata'ı değiştirin (Satırlar 13-21):** +Aşağıdaki alanları kaldırın: `created_at` ve `updated_at`: +```python +class CollectionMetadata(Record): + user = String() + collection = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() +``` + +**CollectionManagementRequest'i Değiştir (25-47. satırlar):** +Zaman damgası alanlarını kaldır: +```python +class CollectionManagementRequest(Record): + operation = String() + user = String() + collection = String() + timestamp = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() + tag_filter = Array(String()) + limit = Integer() +``` + +**Gerekçe:** +Zaman damgaları, koleksiyonlar için değer katmaz. +Yapılandırma hizmeti, kendi sürüm takibini yapar. +Şemayı basitleştirir ve depolama alanını azaltır. + +#### Yapılandırma Hizmeti Geçişinin Faydaları + +1. ✅ **Sabit kodlanmış depolama yönetimi konularını ortadan kaldırır** - Çok kiracılı sorunu çözer. +2. ✅ **Daha basit koordinasyon** - 4 veya daha fazla depolama yanıtı için karmaşık asenkron beklemeler olmaz. +3. ✅ **Sonunda tutarlılık** - Depolama hizmetleri, yapılandırma itme yoluyla bağımsız olarak güncellenir. +4. ✅ **Daha iyi güvenilirlik** - Kalıcı yapılandırma itme, kalıcı olmayan istek/yanıt yerine. +5. ✅ **Birleşik yapılandırma modeli** - Koleksiyonlar, yapılandırma olarak ele alınır. +6. ✅ **Karmaşıklığı azaltır** - Yaklaşık 300 satır koordinasyon kodunu kaldırır. +7. ✅ **Çok kiracılı için hazır** - Yapılandırma, anahtar alanı aracılığıyla zaten kiracı izolasyonunu destekler. +8. ✅ **Sürüm takibi** - Yapılandırma hizmeti sürüm mekanizması, denetim izi sağlar. + +## Uygulama Notları + +### Geriye Dönük Uyumluluk + +**Parametre Değişiklikleri:** +CLI parametrelerinin yeniden adlandırılması, bozucu değişikliklerdir ancak kabul edilebilir (özellik şu anda çalışmıyor). +Hizmetler parametreler olmadan çalışır (varsayılanları kullanır). +Varsayılan anahtar alanları korunur: "config", "knowledge", "librarian". +Varsayılan kuyruk: `persistent://tg/config/config` + +**Koleksiyon Yönetimi:** +**Bozucu değişiklik:** Koleksiyon tablosu, "librarian" anahtar alanından kaldırılmıştır. +**Veri geçişi sağlanmamıştır** - bu aşama için kabul edilebilir. +Harici koleksiyon API'si değişmemiştir (listeleme/güncelleme/silme işlemleri). +Koleksiyon meta veri biçimi basitleştirilmiştir (zaman damgaları kaldırılmıştır). + +### Test Gereksinimleri + +**Parametre Testi:** +1. `--config-push-queue` parametresinin "graph-embeddings" hizmetinde çalıştığını doğrulayın. +2. `--config-push-queue` parametresinin "text-completion" hizmetinde çalıştığını doğrulayın. +3. `--config-push-queue` parametresinin yapılandırma hizmetinde çalıştığını doğrulayın. +4. `--cassandra-keyspace` parametresinin yapılandırma hizmeti için çalıştığını doğrulayın. +5. `--cassandra-keyspace` parametresinin "cores" hizmeti için çalıştığını doğrulayın. +6. `--cassandra-keyspace` parametresinin "librarian" hizmeti için çalıştığını doğrulayın. +7. Hizmetlerin parametreler olmadan çalıştığını (varsayılanları kullandığını) doğrulayın. +8. Özel kuyruk adları ve anahtar alanı ile çok kiracılı dağıtımı doğrulayın. + +**Koleksiyon Yönetimi Testi:** +9. `list-collections` işlemini yapılandırma hizmeti aracılığıyla doğrulayın. +10. `update-collection`'ın yapılandırma tablosunda oluşturulduğunu/güncellendiğini doğrulayın. +11. `delete-collection`'ın yapılandırma tablosundan kaldırıldığını doğrulayın. +12. Koleksiyon güncellemelerinde yapılandırma itmesinin tetiklendiğini doğrulayın. +13. Etiket filtrelemenin yapılandırma tabanlı depolama ile çalıştığını doğrulayın. +14. Koleksiyon işlemlerinin zaman damgası alanları olmadan çalıştığını doğrulayın. + +### Çok Kiracılı Dağıtım Örneği +```bash +# Tenant: tg-dev +graph-embeddings \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config + +config-service \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config \ + --cassandra-keyspace tg_dev_config +``` + +## Etki Analizi + +### 1-2 Değişikliklerinden Etkilenen Hizmetler (CLI Parametre Adı Değişikliği) +AsyncProcessor veya FlowProcessor'dan türeyen tüm hizmetler: +config-service +cores-service +librarian-service +graph-embeddings +document-embeddings +text-completion-* (tüm sağlayıcılar) +extract-* (tüm çıkarıcılar) +query-* (tüm sorgu hizmetleri) +retrieval-* (tüm RAG hizmetleri) +storage-* (tüm depolama hizmetleri) +Ve 20'den fazla hizmet daha + +### 3-6 Değişikliklerinden Etkilenen Hizmetler (Cassandra Keyspace) +config-service +cores-service +librarian-service + +### 7-11 Değişikliklerinden Etkilenen Hizmetler (Koleksiyon Yönetimi) + +**Hızlı Uygulanacak Değişiklikler:** +librarian-service (collection_manager.py, service.py) +tables/library.py (collections tablosunun kaldırılması) +schema/services/collection.py (zaman damgası kaldırma) + +**Tamamlanan Değişiklikler (Değişiklik 10):** ✅ +Tüm depolama hizmetleri (toplam 11) - `CollectionConfigHandler` üzerinden koleksiyon güncellemeleri için yapılandırma itme işlemine geçirildi +Depolama yönetimi şeması `storage.py`'dan kaldırıldı + +## Gelecek Hususlar + +### Kullanıcı Başına Keyspace Modeli + +Bazı hizmetler, her kullanıcının kendi Cassandra keyspace'ine sahip olduğu **kullanıcı başına keyspace**'leri dinamik olarak kullanır: + +**Kullanıcı başına keyspace kullanan hizmetler:** +1. **Triples Sorgu Hizmeti** (`trustgraph-flow/trustgraph/query/triples/cassandra/service.py:65`) + `keyspace=query.user` kullanır +2. **Objects Sorgu Hizmeti** (`trustgraph-flow/trustgraph/query/objects/cassandra/service.py:479`) + `keyspace=self.sanitize_name(user)` kullanır +3. **KnowledgeGraph Doğrudan Erişim** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py:18`) + Varsayılan parametre `keyspace="trustgraph"` + +**Durum:** Bu, bu belirtimde **değiştirilmemiştir**. + +**Gelecekte İnceleme Gerekli:** +Kullanıcı başına keyspace modelinin kiracı izolasyonu sorunlarına neden olup olmadığını değerlendirin +Çok kiracılı dağıtımların keyspace önek kalıplarına (örneğin, `tenant_a_user1`) ihtiyaç duyup duymadığını düşünün +Kiracılar arasında potansiyel kullanıcı kimliği çakışmalarını gözden geçirin +Tek, paylaşılan keyspace'in, kullanıcı tabanlı satır izolasyonu ile birlikte daha mı tercih edilebilir olduğunu değerlendirin + +**Not:** Bu, mevcut çok kiracılı uygulamayı engellemez, ancak üretim çok kiracılı dağıtımlardan önce incelenmelidir. + +## Uygulama Aşamaları + +### Aşama 1: Parametre Düzeltmeleri (Değişiklikler 1-6) +`--config-push-queue` parametre adlandırmasını düzeltin +`--cassandra-keyspace` parametre desteğini ekleyin +**Sonuç:** Çok kiracılı kuyruk ve keyspace yapılandırması etkinleştirildi + +### Aşama 2: Koleksiyon Yönetimi Geçişi (Değişiklikler 7-9, 11) +Koleksiyon depolamasını yapılandırma hizmetine geçirin +librarian'dan koleksiyon tablosunu kaldırın +Koleksiyon şemasını güncelleyin (zaman damgalarını kaldırın) +**Sonuç:** Sabit kodlu depolama yönetimi konuları ortadan kaldırılır, librarian basitleştirilir + +### Aşama 3: Depolama Hizmeti Güncellemeleri (Değişiklik 10) ✅ TAMAMLANDI +Tüm depolama hizmetlerini koleksiyonlar için yapılandırma itme işlemine almak için güncelleyin `CollectionConfigHandler` +Depolama yönetimi istek/yanıt altyapısını kaldırın +Eski şema tanımlarını kaldırın +**Sonuç:** Tamamen yapılandırmaya dayalı koleksiyon yönetimi elde edildi + +## Referanslar +GitHub Sorunu: https://github.com/trustgraph-ai/trustgraph/issues/582 +İlgili Dosyalar: + `trustgraph-base/trustgraph/base/async_processor.py` + `trustgraph-base/trustgraph/base/cassandra_config.py` + `trustgraph-base/trustgraph/schema/core/topic.py` + `trustgraph-base/trustgraph/schema/services/collection.py` + `trustgraph-flow/trustgraph/config/service/service.py` + `trustgraph-flow/trustgraph/cores/service.py` + `trustgraph-flow/trustgraph/librarian/service.py` + `trustgraph-flow/trustgraph/librarian/collection_manager.py` + `trustgraph-flow/trustgraph/tables/library.py` diff --git a/docs/tech-specs/multi-tenant-support.zh-cn.md b/docs/tech-specs/multi-tenant-support.zh-cn.md new file mode 100644 index 00000000..786eafd8 --- /dev/null +++ b/docs/tech-specs/multi-tenant-support.zh-cn.md @@ -0,0 +1,772 @@ +# 技术规范:多租户支持 + +## 概述 + +通过修复参数名称不匹配的问题,从而解决阻止队列自定义的问题,并添加 Cassandra 键空间参数化,以实现多租户部署。 + +## 架构上下文 + +### 基于流的队列解析 + +TrustGraph 系统使用**基于流的架构**进行动态队列解析,该架构本质上支持多租户: + +**流定义**存储在 Cassandra 中,并通过接口定义指定队列名称。 +**队列名称使用模板**,其中包含 `{id}` 变量,这些变量会被替换为流实例 ID。 +**服务在请求时动态解析队列**,通过查找流配置。 +**每个租户可以拥有独特的流**,具有不同的队列名称,从而提供隔离。 + +示例流接口定义: +```json +{ + "interfaces": { + "triples-store": "persistent://tg/flow/triples-store:{id}", + "graph-embeddings-store": "persistent://tg/flow/graph-embeddings-store:{id}" + } +} +``` + +当租户 A 启动流程 `tenant-a-prod`,而租户 B 启动流程 `tenant-b-prod` 时,它们会自动获得隔离的队列: +`persistent://tg/flow/triples-store:tenant-a-prod` +`persistent://tg/flow/triples-store:tenant-b-prod` + +**为多租户设计的服务:** +✅ **知识管理 (核心)** - 动态解析从请求中传递的流程配置中的队列 + +**需要修复的服务:** +🔴 **配置服务** - 参数名称不匹配,无法自定义队列 +🔴 **图书管理员服务** - 预定义的存储管理主题(见下文) +🔴 **所有服务** - 无法自定义 Cassandra keyspace + +## 问题描述 + +### 问题 #1:AsyncProcessor 中的参数名称不匹配 +**CLI 定义:** `--config-queue` (命名不明确) +**Argparse 转换:** `config_queue` (在 params 字典中) +**代码查找:** `config_push_queue` +**结果:** 参数被忽略,默认为 `persistent://tg/config/config` +**影响:** 影响所有 32 多个从 AsyncProcessor 继承的服务 +**问题:** 多租户部署无法使用租户特定的配置队列 +**解决方案:** 将 CLI 参数重命名为 `--config-push-queue`,以提高清晰度(可以接受破坏性更改,因为该功能当前已损坏) + +### 问题 #2:配置服务中的参数名称不匹配 +**CLI 定义:** `--push-queue` (命名模糊) +**Argparse 转换:** `push_queue` (在 params 字典中) +**代码查找:** `config_push_queue` +**结果:** 参数被忽略 +**影响:** 配置服务无法使用自定义推送队列 +**解决方案:** 将 CLI 参数重命名为 `--config-push-queue`,以提高一致性和清晰度(可以接受破坏性更改) + +### 问题 #3:预定义的 Cassandra Keyspace +**当前:** Keyspace 在各种服务中硬编码为 `"config"`、`"knowledge"`、`"librarian"` +**结果:** 无法为多租户部署自定义 keyspace +**影响:** 配置、核心和图书管理员服务 +**问题:** 多个租户无法使用单独的 Cassandra keyspace + +### 问题 #4:集合管理架构 ✅ 已完成 +**之前:** 集合存储在图书管理员 keyspace 中的单独的集合表中 +**之前:** 图书管理员使用 4 个硬编码的存储管理主题来协调集合创建/删除: + `vector_storage_management_topic` + `object_storage_management_topic` + `triples_storage_management_topic` + `storage_management_response_topic` +**问题(已解决):** + 无法为多租户部署自定义硬编码主题 + 图书管理员和 4 个或更多存储服务之间的复杂异步协调 + 单独的 Cassandra 表和管理基础设施 + 关键操作的非持久性请求/响应队列 +**已实施的解决方案:** 将集合迁移到配置服务存储,使用配置推送进行分发 +**状态:** 所有存储后端已迁移到 `CollectionConfigHandler` 模式 + +## 解决方案 + +此规范解决了问题 #1、#2、#3 和 #4。 + +### 第一部分:修复参数名称不匹配 + +#### 更改 1:AsyncProcessor 基类 - 重命名 CLI 参数 +**文件:** `trustgraph-base/trustgraph/base/async_processor.py` +**行:** 260-264 + +**当前:** +```python +parser.add_argument( + '--config-queue', + default=default_config_queue, + help=f'Config push queue {default_config_queue}', +) +``` + +**已修复:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_queue, + help=f'Config push queue (default: {default_config_queue})', +) +``` + +**理由:** +命名更清晰、更明确 +与内部变量名 `config_push_queue` 匹配 +允许进行重大更改,因为该功能目前不可用 +params.get() 不需要任何代码更改,因为它已经查找正确的名称 + +#### 更改 2:配置服务 - 重命名 CLI 参数 +**文件:** `trustgraph-flow/trustgraph/config/service/service.py` +**行:** 276-279 + +**当前:** +```python +parser.add_argument( + '--push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**固定:** +```python +parser.add_argument( + '--config-push-queue', + default=default_config_push_queue, + help=f'Config push queue (default: {default_config_push_queue})' +) +``` + +**理由:** +更清晰的命名 - "config-push-queue" 比仅仅 "push-queue" 更明确。 +与内部变量名 `config_push_queue` 匹配。 +与 AsyncProcessor 的 `--config-push-queue` 参数一致。 +即使是重大更改,也是可以接受的,因为该功能目前不可用。 +params.get() 中不需要任何代码更改 - 它已经查找正确的名称。 + +### 第二部分:添加 Cassandra 键空间参数化 + +#### 更改 3:向 cassandra_config 模块添加键空间参数 +**文件:** `trustgraph-base/trustgraph/base/cassandra_config.py` + +**添加 CLI 参数**(在 `add_cassandra_args()` 函数中): +```python +parser.add_argument( + '--cassandra-keyspace', + default=None, + help='Cassandra keyspace (default: service-specific)' +) +``` + +**添加环境变量支持** (在 `resolve_cassandra_config()` 函数中): +```python +keyspace = params.get( + "cassandra_keyspace", + os.environ.get("CASSANDRA_KEYSPACE") +) +``` + +**更新 `resolve_cassandra_config()` 的返回值:** +当前返回:`(hosts, username, password)` +更改为返回:`(hosts, username, password, keyspace)` + +**理由:** +与现有的 Cassandra 配置模式一致 +通过 `add_cassandra_args()` 可供所有服务使用 +支持 CLI 和环境变量配置 + +#### 变更 4:配置服务 - 使用参数化 Keyspace +**文件:** `trustgraph-flow/trustgraph/config/service/service.py` + +**第 30 行** - 移除硬编码的 Keyspace: +```python +# DELETE THIS LINE: +keyspace = "config" +``` + +**第69-73行** - 更新 Cassandra 配置解析: + +**当前:** +```python +cassandra_host, cassandra_username, cassandra_password = \ + resolve_cassandra_config(params) +``` + +**已修复:** +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="config") +``` + +**原因:** +保持与默认值为 "config" 的配置向后兼容。 +允许通过 `--cassandra-keyspace` 或 `CASSANDRA_KEYSPACE` 进行覆盖。 + +#### 变更 5:核心/知识服务 - 使用参数化键空间 +**文件:** `trustgraph-flow/trustgraph/cores/service.py` + +**第 37 行** - 移除硬编码的键空间: +```python +# DELETE THIS LINE: +keyspace = "knowledge" +``` + +**更新 Cassandra 配置解析**(位置类似于配置服务): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="knowledge") +``` + +#### 变更 6:图书管理员服务 - 使用参数化键空间 +**文件:** `trustgraph-flow/trustgraph/librarian/service.py` + +**第 51 行** - 移除硬编码的键空间: +```python +# DELETE THIS LINE: +keyspace = "librarian" +``` + +**更新 Cassandra 配置解析**(位置与配置服务类似): +```python +cassandra_host, cassandra_username, cassandra_password, keyspace = \ + resolve_cassandra_config(params, default_keyspace="librarian") +``` + +### 第三部分:将集合管理迁移到配置服务 + +#### 概述 +将集合从 Cassandra librarian 键空间迁移到配置服务存储。这消除了硬编码的存储管理主题,并通过使用现有的配置推送机制进行分发,简化了架构。 + +#### 当前架构 +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Cassandra Collections Table (librarian keyspace) + ↓ + Broadcast to 4 Storage Management Topics (hardcoded) + ↓ + Wait for 4+ Storage Service Responses + ↓ + Response to Gateway +``` + +#### 新架构 +``` +API Request → Gateway → Librarian Service + ↓ + CollectionManager + ↓ + Config Service API (put/delete/getvalues) + ↓ + Cassandra Config Table (class='collections', key='user:collection') + ↓ + Config Push (to all subscribers on config-push-queue) + ↓ + All Storage Services receive config update independently +``` + +#### 变更 7:集合管理器 - 使用配置服务 API +**文件:** `trustgraph-flow/trustgraph/librarian/collection_manager.py` + +**移除:** +`LibraryTableStore` 的使用(第 33 行,第 40-41 行) +存储管理生产者初始化(第 86-140 行) +`on_storage_response` 方法(第 400-430 行) +`pending_deletions` 跟踪(第 57 行,第 90-96 行,以及整个使用过程) + +**添加:** +用于 API 调用的配置服务客户端(请求/响应模式) + +**配置客户端设置:** +```python +# In __init__, add config request/response producers/consumers +from trustgraph.schema.services.config import ConfigRequest, ConfigResponse + +# Producer for config requests +self.config_request_producer = Producer( + client=pulsar_client, + topic=config_request_queue, + schema=ConfigRequest, +) + +# Consumer for config responses (with correlation ID) +self.config_response_consumer = Consumer( + taskgroup=taskgroup, + client=pulsar_client, + flow=None, + topic=config_response_queue, + subscriber=f"{id}-config", + schema=ConfigResponse, + handler=self.on_config_response, +) + +# Tracking for pending config requests +self.pending_config_requests = {} # request_id -> asyncio.Event +``` + +**修改 `list_collections` (第145-180行):** +```python +async def list_collections(self, user, tag_filter=None, limit=None): + """List collections from config service""" + # Send getvalues request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='getvalues', + type='collections', + ) + + # Send request and wait for response + response = await self.send_config_request(request) + + # Parse collections from response + collections = [] + for key, value_json in response.values.items(): + if ":" in key: + coll_user, collection = key.split(":", 1) + if coll_user == user: + metadata = json.loads(value_json) + collections.append(CollectionMetadata(**metadata)) + + # Apply tag filtering in-memory (as before) + if tag_filter: + collections = [c for c in collections if any(tag in c.tags for tag in tag_filter)] + + # Apply limit + if limit: + collections = collections[:limit] + + return collections + +async def send_config_request(self, request): + """Send config request and wait for response""" + event = asyncio.Event() + self.pending_config_requests[request.id] = event + + await self.config_request_producer.send(request) + await event.wait() + + return self.pending_config_requests.pop(request.id + "_response") + +async def on_config_response(self, message, consumer, flow): + """Handle config response""" + response = message.value() + if response.id in self.pending_config_requests: + self.pending_config_requests[response.id + "_response"] = response + self.pending_config_requests[response.id].set() +``` + +**修改 `update_collection` (第182-312行):** +```python +async def update_collection(self, user, collection, name, description, tags): + """Update collection via config service""" + # Create metadata + metadata = CollectionMetadata( + user=user, + collection=collection, + name=name, + description=description, + tags=tags, + ) + + # Send put request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='put', + type='collections', + key=f'{user}:{collection}', + value=json.dumps(metadata.to_dict()), + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config update failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and create collections +``` + +**修改 `delete_collection` (第314-398行):** +```python +async def delete_collection(self, user, collection): + """Delete collection via config service""" + # Send delete request to config service + request = ConfigRequest( + id=str(uuid.uuid4()), + operation='delete', + type='collections', + key=f'{user}:{collection}', + ) + + response = await self.send_config_request(request) + + if response.error: + raise RuntimeError(f"Config delete failed: {response.error.message}") + + # Config service will trigger config push automatically + # Storage services will receive update and delete collections +``` + +**集合元数据格式:** +存储在配置表中,格式为:`class='collections', key='user:collection'` +值是 JSON 序列化的 CollectionMetadata (不包含时间戳字段) +字段:`user`, `collection`, `name`, `description`, `tags` +示例:`class='collections', key='alice:my-docs', value='{"user":"alice","collection":"my-docs","name":"My Documents","description":"...","tags":["work"]}'` + +#### 变更 8: Librarian Service - 移除存储管理基础设施 +**文件:** `trustgraph-flow/trustgraph/librarian/service.py` + +**移除:** +存储管理生产者 (173-190 行): + `vector_storage_management_producer` + `object_storage_management_producer` + `triples_storage_management_producer` +存储响应消费者 (192-201 行) +`on_storage_response` 处理程序 (467-473 行) + +**修改:** +CollectionManager 初始化 (215-224 行) - 移除存储生产者参数 + +**注意:** 外部集合 API 保持不变: +`list-collections` +`update-collection` +`delete-collection` + +#### 变更 9: 从 LibraryTableStore 中移除 Collections 表 +**文件:** `trustgraph-flow/trustgraph/tables/library.py` + +**删除:** +Collections 表的 CREATE 语句 (114-127 行) +Collections 预处理语句 (205-240 行) +所有集合方法 (578-717 行): + `ensure_collection_exists` + `list_collections` + `update_collection` + `delete_collection` + `get_collection` + `create_collection` + +**原因:** +集合现在存储在配置表中 +这是一个破坏性变更,但无需数据迁移 +显著简化了 librarian service + +#### 变更 10: 存储服务 - 基于配置的集合管理 ✅ 已完成 + +**状态:** 所有 11 个存储后端都已迁移到使用 `CollectionConfigHandler`。 + +**受影响的服务 (总共 11 个):** +文档嵌入: milvus, pinecone, qdrant +图嵌入: milvus, pinecone, qdrant +对象存储: cassandra +三元组存储: cassandra, falkordb, memgraph, neo4j + +**文件:** +`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py` +`trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py` +`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py` +`trustgraph-flow/trustgraph/storage/triples/falkordb/write.py` +`trustgraph-flow/trustgraph/storage/triples/memgraph/write.py` +`trustgraph-flow/trustgraph/storage/triples/neo4j/write.py` + +**实现模式 (所有服务):** + +1. **在 `__init__` 中注册配置处理程序:** +```python +# Add after AsyncProcessor initialization +self.register_config_handler(self.on_collection_config) +self.known_collections = set() # Track (user, collection) tuples +``` + +2. **实现配置处理器:** +```python +async def on_collection_config(self, config, version): + """Handle collection configuration updates""" + logger.info(f"Collection config version: {version}") + + if "collections" not in config: + return + + # Parse collections from config + # Key format: "user:collection" in config["collections"] + config_collections = set() + for key in config["collections"].keys(): + if ":" in key: + user, collection = key.split(":", 1) + config_collections.add((user, collection)) + + # Determine changes + to_create = config_collections - self.known_collections + to_delete = self.known_collections - config_collections + + # Create new collections (idempotent) + for user, collection in to_create: + try: + await self.create_collection_internal(user, collection) + self.known_collections.add((user, collection)) + logger.info(f"Created collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to create {user}/{collection}: {e}") + + # Delete removed collections (idempotent) + for user, collection in to_delete: + try: + await self.delete_collection_internal(user, collection) + self.known_collections.discard((user, collection)) + logger.info(f"Deleted collection: {user}/{collection}") + except Exception as e: + logger.error(f"Failed to delete {user}/{collection}: {e}") +``` + +3. **初始化启动时的已知集合:** +```python +async def start(self): + """Start the processor""" + await super().start() + await self.sync_known_collections() + +async def sync_known_collections(self): + """Query backend to populate known_collections set""" + # Backend-specific implementation: + # - Milvus/Pinecone/Qdrant: List collections/indexes matching naming pattern + # - Cassandra: Query keyspaces or collection metadata + # - Neo4j/Memgraph/FalkorDB: Query CollectionMetadata nodes + pass +``` + +4. **重构现有的处理方法:** +```python +# Rename and remove response sending: +# handle_create_collection → create_collection_internal +# handle_delete_collection → delete_collection_internal + +async def create_collection_internal(self, user, collection): + """Create collection (idempotent)""" + # Same logic as current handle_create_collection + # But remove response producer calls + # Handle "already exists" gracefully + pass + +async def delete_collection_internal(self, user, collection): + """Delete collection (idempotent)""" + # Same logic as current handle_delete_collection + # But remove response producer calls + # Handle "not found" gracefully + pass +``` + +5. **移除存储管理基础设施:** + 移除 `self.storage_request_consumer` 的配置和启动 + 移除 `self.storage_response_producer` 的配置 + 移除 `on_storage_management` 的调度器方法 + 移除存储管理的指标 + 移除导入:`StorageManagementRequest`, `StorageManagementResponse` + +**后端特定注意事项:** + +**向量存储 (Milvus, Pinecone, Qdrant):** 跟踪 `(user, collection)` 在 `known_collections` 中的逻辑,但可能会为每个维度创建多个后端集合。继续采用延迟创建模式。删除操作必须删除所有维度变体。 + +**Cassandra Objects:** 集合是行属性,而不是结构。跟踪键空间级别的信息。 + +**图数据库 (Neo4j, Memgraph, FalkorDB):** 启动时查询 `CollectionMetadata` 节点。在同步时创建/删除元数据节点。 + +**Cassandra 三元组:** 使用 `KnowledgeGraph` API 进行集合操作。 + +**关键设计要点:** + +**最终一致性:** 没有请求/响应机制,配置推送是广播的 +**幂等性:** 所有创建/删除操作都必须可以安全重试 +**错误处理:** 记录错误,但不要阻止配置更新 +**自愈:** 失败的操作将在下一次配置推送时重试 +**集合键格式:** `"user:collection"` 在 `config["collections"]` 中 + +#### 变更 11:更新集合模式 - 移除时间戳 +**文件:** `trustgraph-base/trustgraph/schema/services/collection.py` + +**修改 CollectionMetadata (第 13-21 行):** +移除 `created_at` 和 `updated_at` 字段: +```python +class CollectionMetadata(Record): + user = String() + collection = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() +``` + +**修改 CollectionManagementRequest (第 25-47 行):** +移除时间戳字段: +```python +class CollectionManagementRequest(Record): + operation = String() + user = String() + collection = String() + timestamp = String() + name = String() + description = String() + tags = Array(String()) + # Remove: created_at = String() + # Remove: updated_at = String() + tag_filter = Array(String()) + limit = Integer() +``` + +**Rationale:** +Timestamps don't add value for collections +Config service maintains its own version tracking +Simplifies schema and reduces storage + +#### Benefits of Config Service Migration + +1. ✅ **Eliminates hardcoded storage management topics** - Solves multi-tenant blocker +2. ✅ **Simpler coordination** - No complex async waiting for 4+ storage responses +3. ✅ **Eventual consistency** - Storage services update independently via config push +4. ✅ **Better reliability** - Persistent config push vs non-persistent request/response +5. ✅ **Unified configuration model** - Collections treated as configuration +6. ✅ **Reduces complexity** - Removes ~300 lines of coordination code +7. ✅ **Multi-tenant ready** - Config already supports tenant isolation via keyspace +8. ✅ **Version tracking** - Config service version mechanism provides audit trail + +## Implementation Notes + +### Backward Compatibility + +**Parameter Changes:** +CLI parameter renames are breaking changes but acceptable (feature currently non-functional) +Services work without parameters (use defaults) +Default keyspaces preserved: "config", "knowledge", "librarian" +Default queue: `persistent://tg/config/config` + +**Collection Management:** +**Breaking change:** Collections table removed from librarian keyspace +**No data migration provided** - acceptable for this phase +External collection API unchanged (list/update/delete operations) +Collection metadata format simplified (timestamps removed) + +### Testing Requirements + +**Parameter Testing:** +1. Verify `--config-push-queue` parameter works on graph-embeddings service +2. Verify `--config-push-queue` parameter works on text-completion service +3. Verify `--config-push-queue` parameter works on config service +4. Verify `--cassandra-keyspace` parameter works for config service +5. Verify `--cassandra-keyspace` parameter works for cores service +6. Verify `--cassandra-keyspace` parameter works for librarian service +7. Verify services work without parameters (uses defaults) +8. Verify multi-tenant deployment with custom queue names and keyspace + +**Collection Management Testing:** +9. Verify `list-collections` operation via config service +10. Verify `update-collection` creates/updates in config table +11. Verify `delete-collection` removes from config table +12. Verify config push is triggered on collection updates +13. Verify tag filtering works with config-based storage +14. Verify collection operations work without timestamp fields + +### Multi-Tenant Deployment Example +```bash +# Tenant: tg-dev +graph-embeddings \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config + +config-service \ + -p pulsar+ssl://broker:6651 \ + --pulsar-api-key \ + --config-push-queue persistent://tg-dev/config/config \ + --cassandra-keyspace tg_dev_config +``` + +## 影响分析 + +### 受变更 1-2 影响的服务 (CLI 参数重命名) +所有继承自 AsyncProcessor 或 FlowProcessor 的服务: +config-service +cores-service +librarian-service +graph-embeddings +document-embeddings +text-completion-* (所有提供者) +extract-* (所有提取器) +query-* (所有查询服务) +retrieval-* (所有 RAG 服务) +storage-* (所有存储服务) +还有 20 多个服务 + +### 受变更 3-6 影响的服务 (Cassandra Keyspace) +config-service +cores-service +librarian-service + +### 受变更 7-11 影响的服务 (集合管理) + +**即时变更:** +librarian-service (collection_manager.py, service.py) +tables/library.py (删除 collections 表) +schema/services/collection.py (删除时间戳) + +**已完成的变更 (变更 10):** ✅ +所有存储服务 (共 11 个) - 已迁移到配置推送,用于通过 `CollectionConfigHandler` 更新集合 +存储管理模式已从 `storage.py` 中移除 + +## 未来考虑 + +### 基于用户的 Keyspace 模式 + +一些服务使用 **基于用户的 Keyspace** 动态模式,其中每个用户都拥有自己的 Cassandra Keyspace: + +**使用基于用户的 Keyspace 的服务:** +1. **三元组查询服务** (`trustgraph-flow/trustgraph/query/triples/cassandra/service.py:65`) + 使用 `keyspace=query.user` +2. **对象查询服务** (`trustgraph-flow/trustgraph/query/objects/cassandra/service.py:479`) + 使用 `keyspace=self.sanitize_name(user)` +3. **知识图谱直接访问** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py:18`) + 默认参数 `keyspace="trustgraph"` + +**状态:** 这些 **未进行修改**,在本规范中。 + +**需要未来审查:** +评估基于用户的 Keyspace 模式是否会产生租户隔离问题 +考虑是否需要为多租户部署使用 Keyspace 前缀模式 (例如,`tenant_a_user1`) +审查是否存在用户 ID 在租户之间的冲突 +评估是否更倾向于使用单个共享 Keyspace,每个租户使用基于用户的行隔离 + +**注意:** 这不会阻止当前的 multi-tenant 实现,但在进行生产 multi-tenant 部署之前应进行审查。 + +## 实施阶段 + +### 第一阶段:参数修复 (变更 1-6) +修复 `--config-push-queue` 参数命名 +添加 `--cassandra-keyspace` 参数支持 +**结果:** 启用了 multi-tenant 队列和 Keyspace 配置 + +### 第二阶段:集合管理迁移 (变更 7-9, 11) +将集合存储迁移到配置服务 +从 librarian 中删除 collections 表 +更新集合模式 (删除时间戳) +**结果:** 消除硬编码的存储管理主题,简化 librarian + +### 第三阶段:存储服务更新 (变更 10) ✅ 已完成 +所有存储服务已更新为使用配置推送进行集合管理,通过 `CollectionConfigHandler` +移除了存储管理请求/响应基础设施 +移除了旧的模式定义 +**结果:** 实现了基于配置的集合管理 + +## 引用 +GitHub Issue: https://github.com/trustgraph-ai/trustgraph/issues/582 +相关文件: + `trustgraph-base/trustgraph/base/async_processor.py` + `trustgraph-base/trustgraph/base/cassandra_config.py` + `trustgraph-base/trustgraph/schema/core/topic.py` + `trustgraph-base/trustgraph/schema/services/collection.py` + `trustgraph-flow/trustgraph/config/service/service.py` + `trustgraph-flow/trustgraph/cores/service.py` + `trustgraph-flow/trustgraph/librarian/service.py` + `trustgraph-flow/trustgraph/librarian/collection_manager.py` + `trustgraph-flow/trustgraph/tables/library.py` diff --git a/docs/tech-specs/neo4j-user-collection-isolation.hi.md b/docs/tech-specs/neo4j-user-collection-isolation.hi.md index ba248c1a..d57519ba 100644 --- a/docs/tech-specs/neo4j-user-collection-isolation.hi.md +++ b/docs/tech-specs/neo4j-user-collection-isolation.hi.md @@ -1,29 +1,29 @@ -# Neo4j उपयोगकर्ता/संग्रह अलगाव समर्थन +# नियो4जे उपयोगकर्ता/संग्रह अलगाव समर्थन ## समस्या विवरण -Neo4j ट्रिपल भंडारण और क्वेरी कार्यान्वयन में वर्तमान में उपयोगकर्ता/संग्रह अलगाव का अभाव है, जिससे बहु-किरायेदारी सुरक्षा समस्या उत्पन्न होती है। सभी ट्रिपल एक ही ग्राफ स्पेस में संग्रहीत किए जाते हैं, बिना किसी तंत्र के जो उपयोगकर्ताओं को अन्य उपयोगकर्ताओं के डेटा तक पहुंचने या संग्रहों को मिलाने से रोके। +नियो4जे का त्रिगुट भंडारण और क्वेरी कार्यान्वयन वर्तमान में उपयोगकर्ता/संग्रह अलगाव की कमी रखता है, जो एक बहु-किरायेदारी सुरक्षा समस्या पैदा करता है। सभी त्रिगुट एक ही ग्राफ स्पेस में संग्रहीत होते हैं, बिना किसी ऐसी तंत्र के जो उपयोगकर्ताओं को अन्य उपयोगकर्ताओं के डेटा तक पहुंचने या संग्रहों को मिलाने से रोकता हो। -अन्य ट्रस्टग्राफ स्टोरेज बैकएंड के विपरीत: -- **कैसेंड्रा**: प्रत्येक उपयोगकर्ता के लिए अलग-अलग कीस्पेस और प्रत्येक संग्रह के लिए अलग-अलग टेबल का उपयोग करता है। -- **वेक्टर स्टोर** (मिलवस, क्यूड्रांट, पाइनकोन): संग्रह-विशिष्ट नेमस्पेस का उपयोग करते हैं। -- **Neo4j**: वर्तमान में सभी डेटा को एक ही ग्राफ में साझा करता है (सुरक्षा भेद्यता)। +ट्रस्टग्राफ में अन्य स्टोरेज बैकएंड के विपरीत: +**कैसेंड्रा**: प्रत्येक उपयोगकर्ता के लिए अलग-अलग कीस्पेस और प्रत्येक संग्रह के लिए टेबल का उपयोग करता है। +**वेक्टर स्टोर** (मिलवस, क्यूड्रांट, पाइनकोन): संग्रह-विशिष्ट नेमस्पेस का उपयोग करते हैं। +**नियो4जे**: वर्तमान में सभी डेटा को एक ही ग्राफ में साझा करता है (सुरक्षा भेद्यता)। ## वर्तमान आर्किटेक्चर ### डेटा मॉडल -- **नोड**: `:Node` लेबल जिसमें `uri` प्रॉपर्टी है, `:Literal` लेबल जिसमें `value` प्रॉपर्टी है। -- **रिलेशनशिप**: `:Rel` लेबल जिसमें `uri` प्रॉपर्टी है। -- **इंडेक्स**: `Node.uri`, `Literal.value`, `Rel.uri` +**नोड्स**: `:Node` लेबल के साथ `uri` प्रॉपर्टी, `:Literal` लेबल के साथ `value` प्रॉपर्टी। +**रिलेशनशिप्स**: `:Rel` लेबल के साथ `uri` प्रॉपर्टी। +**इंडेक्स**: `Node.uri`, `Literal.value`, `Rel.uri`। ### संदेश प्रवाह -- `Triples` संदेशों में `metadata.user` और `metadata.collection` फ़ील्ड होते हैं। -- स्टोरेज सेवा उपयोगकर्ता/संग्रह जानकारी प्राप्त करती है लेकिन उसे अनदेखा करती है। -- क्वेरी सेवा `TriplesQueryRequest` में `user` और `collection` की अपेक्षा करती है लेकिन उन्हें अनदेखा करती है। +`Triples` संदेशों में `metadata.user` और `metadata.collection` फ़ील्ड होते हैं। +स्टोरेज सेवा उपयोगकर्ता/संग्रह जानकारी प्राप्त करती है लेकिन इसे अनदेखा करती है। +क्वेरी सेवा `TriplesQueryRequest` में `user` और `collection` की अपेक्षा करती है लेकिन उन्हें अनदेखा करती है। ### वर्तमान सुरक्षा समस्या ```cypher -# कोई भी उपयोगकर्ता किसी भी डेटा को क्वेरी कर सकता है - कोई अलगाव नहीं +# Any user can query any data - no isolation MATCH (src:Node)-[rel:Rel]->(dest:Node) RETURN src.uri, rel.uri, dest.uri ``` @@ -31,30 +31,30 @@ RETURN src.uri, rel.uri, dest.uri ## प्रस्तावित समाधान: प्रॉपर्टी-आधारित फ़िल्टरिंग (अनुशंसित) ### अवलोकन -सभी नोड्स और रिलेशनशिप में `user` और `collection` प्रॉपर्टी जोड़ें, और फिर सभी ऑपरेशनों को इन प्रॉपर्टीज़ द्वारा फ़िल्टर करें। यह दृष्टिकोण मजबूत अलगाव प्रदान करता है, जबकि क्वेरी लचीलापन और पिछड़े अनुकूलता बनाए रखता है। +सभी नोड्स और संबंधों में `user` और `collection` प्रॉपर्टीज़ जोड़ें, और फिर सभी ऑपरेशन्स को इन प्रॉपर्टीज़ के आधार पर फ़िल्टर करें। यह दृष्टिकोण मजबूत अलगाव प्रदान करता है, जबकि क्वेरी लचीलापन और पिछड़े अनुकूलता को बनाए रखता है। ### डेटा मॉडल परिवर्तन #### उन्नत नोड संरचना ```cypher -// नोड एंटिटीज +// Node entities CREATE (n:Node { uri: "http://example.com/entity1", user: "john_doe", collection: "production_v1" }) -// लिटरल एंटिटीज +// Literal entities CREATE (n:Literal { - value: "लिटरल वैल्यू", + value: "literal value", user: "john_doe", collection: "production_v1" }) ``` -#### उन्नत रिलेशनशिप संरचना +#### उन्नत संबंध संरचना ```cypher -// उपयोगकर्ता/संग्रह प्रॉपर्टीज़ के साथ रिलेशनशिप +// Relationships with user/collection properties CREATE (src)-[:Rel { uri: "http://example.com/predicate1", user: "john_doe", @@ -62,73 +62,298 @@ CREATE (src)-[:Rel { }]->(dest) ``` -#### अद्यतित इंडेक्स +#### अद्यतित अनुक्रमणिकाएँ ```cypher -// कुशल फ़िल्टरिंग के लिए कंपाउंड इंडेक्स +// Compound indexes for efficient filtering CREATE INDEX node_user_collection_uri FOR (n:Node) ON (n.user, n.collection, n.uri); CREATE INDEX literal_user_collection_value FOR (n:Literal) ON (n.user, n.collection, n.value); CREATE INDEX rel_user_collection_uri FOR ()-[r:Rel]-() ON (r.user, r.collection, r.uri); -// पिछड़े अनुकूलता के लिए मौजूदा इंडेक्स बनाए रखें (वैकल्पिक) +// Maintain existing indexes for backwards compatibility (optional) CREATE INDEX Node_uri FOR (n:Node) ON (n.uri); CREATE INDEX Literal_value FOR (n:Literal) ON (n.value); CREATE INDEX Rel_uri FOR ()-[r:Rel]-() ON (r.uri); ``` -### कार्यान्वयन परिवर्तन +### कार्यान्वयन में परिवर्तन -#### स्टोरेज सेवा (`write.py`) +#### स्टोरेज सर्विस (`write.py`) **वर्तमान कोड:** ```python -# (कोड यहां) +def create_node(self, uri): + summary = self.io.execute_query( + "MERGE (n:Node {uri: $uri})", + uri=uri, database_=self.db, + ).summary ``` **अद्यतित कोड:** ```python -# (अद्यतित कोड यहां) +def create_node(self, uri, user, collection): + summary = self.io.execute_query( + "MERGE (n:Node {uri: $uri, user: $user, collection: $collection})", + uri=uri, user=user, collection=collection, database_=self.db, + ).summary ``` -#### क्वेरी सेवा (उदाहरण) +**बेहतर `store_triples` विधि:** +```python +async def store_triples(self, message): + user = message.metadata.user + collection = message.metadata.collection + + for t in message.triples: + self.create_node(t.s.value, user, collection) + + if t.o.is_uri: + self.create_node(t.o.value, user, collection) + self.relate_node(t.s.value, t.p.value, t.o.value, user, collection) + else: + self.create_literal(t.o.value, user, collection) + self.relate_literal(t.s.value, t.p.value, t.o.value, user, collection) +``` + +#### क्वेरी सर्विस (`service.py`) + +**वर्तमान कोड:** +```python +records, summary, keys = self.io.execute_query( + "MATCH (src:Node {uri: $src})-[rel:Rel {uri: $rel}]->(dest:Node) " + "RETURN dest.uri as dest", + src=query.s.value, rel=query.p.value, database_=self.db, +) +``` + +**अद्यतित कोड:** +```python +records, summary, keys = self.io.execute_query( + "MATCH (src:Node {uri: $src, user: $user, collection: $collection})-" + "[rel:Rel {uri: $rel, user: $user, collection: $collection}]->" + "(dest:Node {user: $user, collection: $collection}) " + "RETURN dest.uri as dest", + src=query.s.value, rel=query.p.value, + user=query.user, collection=query.collection, + database_=self.db, +) +``` + +### माइग्रेशन रणनीति + +#### चरण 1: नए डेटा में गुण जोड़ें +1. स्टोरेज सर्विस को अपडेट करें ताकि नए त्रिगुणों में उपयोगकर्ता/संग्रह गुण जोड़े जा सकें। +2. पिछली अनुकूलता बनाए रखें, क्योंकि प्रश्नों में गुणों की आवश्यकता नहीं होगी। +3. मौजूदा डेटा सुलभ रहेगा, लेकिन अलग नहीं होगा। + +#### चरण 2: मौजूदा डेटा का माइग्रेशन ```cypher -# मौजूदा क्वेरी: -MATCH (n:Node) WHERE n.name = 'example' +// Migrate existing nodes (requires default user/collection assignment) +MATCH (n:Node) WHERE n.user IS NULL +SET n.user = 'legacy_user', n.collection = 'default_collection'; -# अद्यतित क्वेरी: -MATCH (n:Node) WHERE n.name = 'example' AND n.user = $user AND n.collection = $collection +MATCH (n:Literal) WHERE n.user IS NULL +SET n.user = 'legacy_user', n.collection = 'default_collection'; + +MATCH ()-[r:Rel]->() WHERE r.user IS NULL +SET r.user = 'legacy_user', r.collection = 'default_collection'; ``` -### परफॉर्मेंस पर विचार +#### चरण 3: अलगाव को लागू करना +1. क्वेरी सेवा को अपडेट करें ताकि उपयोगकर्ता/संग्रह फ़िल्टरिंग की आवश्यकता हो +2. उचित उपयोगकर्ता/संग्रह संदर्भ के बिना क्वेरी को अस्वीकार करने के लिए सत्यापन जोड़ें +3. पुराने डेटा एक्सेस पथ को हटा दें -- कंपाउंड इंडेक्स का उपयोग करें। -- क्वेरी कैशिंग पर विचार करें। -- डेटा आकार और कनेक्शन पूल उपयोग की निगरानी करें। +### सुरक्षा संबंधी विचार -### सुरक्षा और अनुपालन +#### क्वेरी सत्यापन +```python +async def query_triples(self, query): + # Validate user/collection parameters + if not query.user or not query.collection: + raise ValueError("User and collection must be specified") + + # All queries must include user/collection filters + # ... rest of implementation +``` -- डेटा अलगाव गारंटी -- ऑडिट आवश्यकताएं -- अनुपालन विचार +#### पैरामीटर इंजेक्शन को रोकना +केवल पैरामीटराइज़्ड क्वेरी का उपयोग करें। +उपयोगकर्ता/संग्रह मूल्यों को स्वीकृत पैटर्न के विरुद्ध मान्य करें। +Neo4j प्रॉपर्टी नाम आवश्यकताओं के लिए सैनिटाइजेशन पर विचार करें। -### जोखिम और निवारण +#### ऑडिट ट्रेल +```python +logger.info(f"Query executed - User: {query.user}, Collection: {query.collection}, " + f"Pattern: {query.s}/{query.p}/{query.o}") +``` + +## वैकल्पिक दृष्टिकोणों पर विचार + +### विकल्प 2: लेबल-आधारित अलगाव + +**दृष्टिकोण**: गतिशील लेबल का उपयोग करें जैसे `User_john_Collection_prod` + +**लाभ:** +लेबल फ़िल्टरिंग के माध्यम से मजबूत अलगाव +लेबल इंडेक्स के साथ कुशल क्वेरी प्रदर्शन +स्पष्ट डेटा पृथक्करण + +**नुकसान:** +Neo4j में लेबल की संख्या पर व्यावहारिक सीमाएं हैं (~1000) +जटिल लेबल नाम पीढ़ी और सैनिटाइजेशन +जब आवश्यक हो तो संग्रहों में क्वेरी करना मुश्किल होता है + +**कार्यान्वयन उदाहरण:** +```cypher +CREATE (n:Node:User_john_Collection_prod {uri: "http://example.com/entity"}) +MATCH (n:User_john_Collection_prod) WHERE n:Node RETURN n +``` + +### विकल्प 3: प्रति-उपयोगकर्ता डेटाबेस + +**दृष्टिकोण**: प्रत्येक उपयोगकर्ता या उपयोगकर्ता/संग्रह संयोजन के लिए अलग-अलग Neo4j डेटाबेस बनाएं। + +**लाभ:** +पूर्ण डेटा अलगाव +क्रॉस-संदूषण का कोई जोखिम नहीं +प्रति-उपयोगकर्ता स्वतंत्र स्केलिंग + +**नुकसान:** +संसाधन ओवरहेड (प्रत्येक डेटाबेस मेमोरी का उपयोग करता है) +जटिल डेटाबेस जीवनचक्र प्रबंधन +Neo4j कम्युनिटी एडिशन डेटाबेस सीमाएं +उपयोगकर्ताओं के बीच विश्लेषण करना मुश्किल + +### विकल्प 4: समग्र कुंजी रणनीति + +**दृष्टिकोण**: सभी URIs और मानों को उपयोगकर्ता/संग्रह जानकारी के साथ उपसर्ग करें। + +**लाभ:** +मौजूदा प्रश्नों के साथ संगत +सरल कार्यान्वयन +कोई स्कीमा परिवर्तन आवश्यक नहीं + +**नुकसान:** +URI प्रदूषण डेटा अर्थशास्त्र को प्रभावित करता है +कम कुशल प्रश्न (स्ट्रिंग उपसर्ग मिलान) +RDF/सिमेंटिक वेब मानकों का उल्लंघन + +**कार्यान्वयन उदाहरण:** +```python +def make_composite_uri(uri, user, collection): + return f"usr:{user}:col:{collection}:uri:{uri}" +``` + +## कार्यान्वयन योजना + +### चरण 1: आधार (सप्ताह 1) +1. [ ] स्टोरेज सेवा को उपयोगकर्ता/संग्रह गुणों को स्वीकार करने और संग्रहीत करने के लिए अपडेट करें। +2. [ ] कुशल क्वेरी के लिए कंपाउंड इंडेक्स जोड़ें। +3. [ ] पिछड़े अनुकूलता परत लागू करें। +4. [ ] नई कार्यक्षमता के लिए यूनिट परीक्षण बनाएं। + +### चरण 2: क्वेरी अपडेट (सप्ताह 2) +1. [ ] सभी क्वेरी पैटर्न को उपयोगकर्ता/संग्रह फ़िल्टर शामिल करने के लिए अपडेट करें। +2. [ ] क्वेरी सत्यापन और सुरक्षा जांच जोड़ें। +3. [ ] एकीकरण परीक्षण अपडेट करें। +4. [ ] फ़िल्टर किए गए प्रश्नों के साथ प्रदर्शन परीक्षण। + +### चरण 3: माइग्रेशन और परिनियोजन (सप्ताह 3) +1. [ ] मौजूदा Neo4j उदाहरणों के लिए डेटा माइग्रेशन स्क्रिप्ट बनाएं। +2. [ ] परिनियोजन दस्तावेज़ और रनबुक। +3. [ ] अलगाव उल्लंघनों के लिए निगरानी और अलर्ट। +4. [ ] कई उपयोगकर्ताओं/संग्रहों के साथ एंड-टू-एंड परीक्षण। + +### चरण 4: मजबूती (सप्ताह 4) +1. [ ] विरासत अनुकूलता मोड हटाएं। +2. [ ] व्यापक ऑडिट लॉगिंग जोड़ें। +3. [ ] सुरक्षा समीक्षा और प्रवेश परीक्षण। +4. [ ] प्रदर्शन अनुकूलन। + +## परीक्षण रणनीति + +### यूनिट परीक्षण +```python +def test_user_collection_isolation(): + # Store triples for user1/collection1 + processor.store_triples(triples_user1_coll1) + + # Store triples for user2/collection2 + processor.store_triples(triples_user2_coll2) + + # Query as user1 should only return user1's data + results = processor.query_triples(query_user1_coll1) + assert all_results_belong_to_user1_coll1(results) + + # Query as user2 should only return user2's data + results = processor.query_triples(query_user2_coll2) + assert all_results_belong_to_user2_coll2(results) +``` + +### एकीकरण परीक्षण (एकीकरण परीक्षण) +मल्टी-यूजर परिदृश्य जिसमें ओवरलैपिंग डेटा शामिल है +क्रॉस-कलेक्शन क्वेरी (विफल होनी चाहिए) +मौजूदा डेटा के साथ माइग्रेशन परीक्षण +बड़े डेटासेट के साथ प्रदर्शन बेंचमार्क + +### सुरक्षा परीक्षण (सुरक्षा परीक्षण) +अन्य उपयोगकर्ताओं के डेटा को क्वेरी करने का प्रयास +उपयोगकर्ता/कलेक्शन पैरामीटर पर SQL इंजेक्शन-शैली के हमले +विभिन्न क्वेरी पैटर्न के तहत पूर्ण अलगाव को सत्यापित करें + +## प्रदर्शन संबंधी विचार (प्रदर्शन संबंधी विचार) + +### इंडेक्स रणनीति (इंडेक्स रणनीति) +इष्टतम फ़िल्टरिंग के लिए `(user, collection, uri)` पर कंपाउंड इंडेक्स +यदि कुछ संग्रह बहुत बड़े हैं तो आंशिक इंडेक्स पर विचार करें +इंडेक्स उपयोग और क्वेरी प्रदर्शन की निगरानी करें + +### क्वेरी अनुकूलन (क्वेरी अनुकूलन) +फ़िल्टर किए गए क्वेरी में इंडेक्स उपयोग को सत्यापित करने के लिए EXPLAIN का उपयोग करें +बार-बार एक्सेस किए जाने वाले डेटा के लिए क्वेरी परिणाम कैशिंग पर विचार करें +बड़ी संख्या में उपयोगकर्ताओं/संग्रहों के साथ मेमोरी उपयोग को प्रोफाइल करें + +### मापनीयता (मापनीयता) +प्रत्येक उपयोगकर्ता/संग्रह संयोजन अलग-अलग डेटा द्वीप बनाता है +डेटाबेस आकार और कनेक्शन पूल उपयोग की निगरानी करें +यदि आवश्यक हो तो क्षैतिज स्केलिंग रणनीतियों पर विचार करें + +## सुरक्षा और अनुपालन (सुरक्षा और अनुपालन) + +### डेटा अलगाव गारंटी (डेटा अलगाव गारंटी) +**भौतिक**: सभी उपयोगकर्ता डेटा स्पष्ट उपयोगकर्ता/संग्रह गुणों के साथ संग्रहीत होते हैं +**तार्किक**: सभी क्वेरी उपयोगकर्ता/संग्रह संदर्भ द्वारा फ़िल्टर की जाती हैं +**पहुंच नियंत्रण**: सेवा-स्तरीय सत्यापन अनधिकृत पहुंच को रोकता है + +### ऑडिट आवश्यकताएँ (ऑडिट आवश्यकताएँ) +उपयोगकर्ता/संग्रह संदर्भ के साथ सभी डेटा एक्सेस को लॉग करें +माइग्रेशन गतिविधियों और डेटा मूवमेंट को ट्रैक करें +अलगाव उल्लंघन के प्रयासों की निगरानी करें + +### अनुपालन संबंधी विचार (अनुपालन संबंधी विचार) +जीडीपीआर: उपयोगकर्ता-विशिष्ट डेटा को खोजने और हटाने की बेहतर क्षमता +एसओसी2: स्पष्ट डेटा अलगाव और पहुंच नियंत्रण +एचआईपीएए: स्वास्थ्य सेवा डेटा के लिए मजबूत किरायेदार अलगाव + +## जोखिम और निवारण (जोखिम और निवारण) | जोखिम | प्रभाव | संभावना | निवारण | |------|--------|------------|------------| -| क्वेरी में उपयोगकर्ता/संग्रह फ़िल्टर गायब | उच्च | मध्यम | अनिवार्य सत्यापन, व्यापक परीक्षण | -| परफॉर्मेंस में गिरावट | मध्यम | निम्न | इंडेक्स अनुकूलन, क्वेरी प्रोफाइलिंग | -| माइग्रेशन डेटा भ्रष्टाचार | उच्च | निम्न | बैकअप रणनीति, रोलबैक प्रक्रियाएं | -| जटिल मल्टी-संग्रह क्वेरी | मध्यम | मध्यम | क्वेरी पैटर्न का दस्तावेजीकरण, उदाहरण प्रदान करें | +| क्वेरी में उपयोगकर्ता/संग्रह फ़िल्टर गुम है | उच्च | मध्यम | अनिवार्य सत्यापन, व्यापक परीक्षण +| प्रदर्शन में गिरावट | मध्यम | कम | इंडेक्स अनुकूलन, क्वेरी प्रोफाइलिंग +| माइग्रेशन डेटा भ्रष्टाचार | उच्च | कम | बैकअप रणनीति, रोलबैक प्रक्रियाएं +| जटिल मल्टी-कलेक्शन क्वेरी | मध्यम | मध्यम | क्वेरी पैटर्न को दस्तावेज़ करें, उदाहरण प्रदान करें -### सफलता मानदंड +## सफलता मानदंड (सफलता मानदंड) -1. सुरक्षा: उत्पादन में शून्य क्रॉस-उपयोगकर्ता डेटा एक्सेस -2. परफॉर्मेंस: अनफ़िल्टर किए गए क्वेरी की तुलना में <10% क्वेरी परफॉर्मेंस प्रभाव -3. माइग्रेशन: 100% मौजूदा डेटा बिना किसी नुकसान के सफलतापूर्वक माइग्रेट किया गया -4. उपयोगिता: सभी मौजूदा क्वेरी पैटर्न उपयोगकर्ता/संग्रह संदर्भ के साथ काम करते हैं -5. अनुपालन: उपयोगकर्ता/संग्रह डेटा एक्सेस का पूर्ण ऑडिट ट्रेल +1. **सुरक्षा**: उत्पादन में क्रॉस-यूजर डेटा एक्सेस शून्य +2. **प्रदर्शन**: अनफ़िल्टर किए गए क्वेरी की तुलना में <10% क्वेरी प्रदर्शन प्रभाव +3. **माइग्रेशन**: 100% मौजूदा डेटा बिना किसी नुकसान के सफलतापूर्वक माइग्रेट किया गया +4. **उपयोगिता**: सभी मौजूदा क्वेरी पैटर्न उपयोगकर्ता/संग्रह संदर्भ के साथ काम करते हैं +5. **अनुपालन**: उपयोगकर्ता/संग्रह डेटा एक्सेस का पूर्ण ऑडिट ट्रेल -## निष्कर्ष +## निष्कर्ष (निष्कर्ष) -प्रॉपर्टी-आधारित फ़िल्टरिंग दृष्टिकोण Neo4j में उपयोगकर्ता/संग्रह अलगाव जोड़ने के लिए सुरक्षा, परफॉर्मेंस और रखरखाव का सबसे अच्छा संतुलन प्रदान करता है। यह ट्रस्टग्राफ के मौजूदा बहु-किरायेदारी पैटर्न के साथ संरेखित होता है, जबकि ग्राफ क्वेरी और इंडेक्सिंग में Neo4j की ताकत का लाभ उठाता है। +संपत्ति-आधारित फ़िल्टरिंग दृष्टिकोण उपयोगकर्ता/संग्रह अलगाव को Neo4j में जोड़ने के लिए सुरक्षा, प्रदर्शन और रखरखाव के बीच सबसे अच्छा संतुलन प्रदान करता है। यह Neo4j की ग्राफ क्वेरी और इंडेक्सिंग में ताकत का लाभ उठाते हुए TrustGraph के मौजूदा मल्टी-टेनेंसी पैटर्न के साथ संरेखित है। -यह समाधान यह सुनिश्चित करता है कि ट्रस्टग्राफ का Neo4j बैकएंड अन्य स्टोरेज बैकएंड के समान सुरक्षा मानकों को पूरा करे, डेटा अलगाव भेद्यताओं को रोकते हुए ग्राफ क्वेरी की लचीलापन और शक्ति को बनाए रखता है। \ No newline at end of file +यह समाधान सुनिश्चित करता है कि TrustGraph का Neo4j बैकएंड अन्य स्टोरेज बैकएंड के समान सुरक्षा मानकों को पूरा करता है, जिससे डेटा अलगाव कमजोरियों को रोका जा सकता है, जबकि ग्राफ क्वेरी की लचीलापन और शक्ति को बनाए रखा जा सकता है। \ No newline at end of file diff --git a/docs/tech-specs/neo4j-user-collection-isolation.pt.md b/docs/tech-specs/neo4j-user-collection-isolation.pt.md new file mode 100644 index 00000000..7acad813 --- /dev/null +++ b/docs/tech-specs/neo4j-user-collection-isolation.pt.md @@ -0,0 +1,359 @@ +# Suporte para Isolamento de Usuário/Coleção no Neo4j + +## Declaração do Problema + +A implementação atual de armazenamento e consulta de triplas do Neo4j carece de isolamento de usuário/coleção, o que cria um problema de segurança de multi-inquilinato. Todas as triplas são armazenadas no mesmo espaço de grafo sem nenhum mecanismo para impedir que os usuários acessem os dados de outros usuários ou misturem coleções. + +Ao contrário de outros backends de armazenamento no TrustGraph: +**Cassandra**: Usa key spaces separados por usuário e tabelas por coleção. +**Armazenamentos vetoriais** (Milvus, Qdrant, Pinecone): Usam namespaces específicos para cada coleção. +**Neo4j**: Atualmente compartilha todos os dados em um único grafo (vulnerabilidade de segurança). + +## Arquitetura Atual + +### Modelo de Dados +**Nós**: Rótulo `:Node` com propriedade `uri`, rótulo `:Literal` com propriedade `value`. +**Relacionamentos**: Rótulo `:Rel` com propriedade `uri`. +**Índices**: `Node.uri`, `Literal.value`, `Rel.uri`. + +### Fluxo de Mensagens +Mensagens `Triples` contêm campos `metadata.user` e `metadata.collection`. +O serviço de armazenamento recebe informações de usuário/coleção, mas as ignora. +O serviço de consulta espera `user` e `collection` em `TriplesQueryRequest`, mas os ignora. + +### Problema de Segurança Atual +```cypher +# Any user can query any data - no isolation +MATCH (src:Node)-[rel:Rel]->(dest:Node) +RETURN src.uri, rel.uri, dest.uri +``` + +## Solução Proposta: Filtragem Baseada em Propriedades (Recomendada) + +### Visão Geral +Adicione as propriedades `user` e `collection` a todos os nós e relacionamentos, e então filtre todas as operações por essas propriedades. Essa abordagem fornece um forte isolamento, mantendo a flexibilidade da consulta e a compatibilidade com versões anteriores. + +### Alterações no Modelo de Dados + +#### Estrutura de Nó Aprimorada +```cypher +// Node entities +CREATE (n:Node { + uri: "http://example.com/entity1", + user: "john_doe", + collection: "production_v1" +}) + +// Literal entities +CREATE (n:Literal { + value: "literal value", + user: "john_doe", + collection: "production_v1" +}) +``` + +#### Estrutura de Relacionamento Aprimorada +```cypher +// Relationships with user/collection properties +CREATE (src)-[:Rel { + uri: "http://example.com/predicate1", + user: "john_doe", + collection: "production_v1" +}]->(dest) +``` + +#### Índices Atualizados +```cypher +// Compound indexes for efficient filtering +CREATE INDEX node_user_collection_uri FOR (n:Node) ON (n.user, n.collection, n.uri); +CREATE INDEX literal_user_collection_value FOR (n:Literal) ON (n.user, n.collection, n.value); +CREATE INDEX rel_user_collection_uri FOR ()-[r:Rel]-() ON (r.user, r.collection, r.uri); + +// Maintain existing indexes for backwards compatibility (optional) +CREATE INDEX Node_uri FOR (n:Node) ON (n.uri); +CREATE INDEX Literal_value FOR (n:Literal) ON (n.value); +CREATE INDEX Rel_uri FOR ()-[r:Rel]-() ON (r.uri); +``` + +### Alterações na Implementação + +#### Serviço de Armazenamento (`write.py`) + +**Código Atual:** +```python +def create_node(self, uri): + summary = self.io.execute_query( + "MERGE (n:Node {uri: $uri})", + uri=uri, database_=self.db, + ).summary +``` + +**Código Atualizado:** +```python +def create_node(self, uri, user, collection): + summary = self.io.execute_query( + "MERGE (n:Node {uri: $uri, user: $user, collection: $collection})", + uri=uri, user=user, collection=collection, database_=self.db, + ).summary +``` + +**Método `store_triples` aprimorado:** +```python +async def store_triples(self, message): + user = message.metadata.user + collection = message.metadata.collection + + for t in message.triples: + self.create_node(t.s.value, user, collection) + + if t.o.is_uri: + self.create_node(t.o.value, user, collection) + self.relate_node(t.s.value, t.p.value, t.o.value, user, collection) + else: + self.create_literal(t.o.value, user, collection) + self.relate_literal(t.s.value, t.p.value, t.o.value, user, collection) +``` + +#### Serviço de Consulta (`service.py`) + +**Código Atual:** +```python +records, summary, keys = self.io.execute_query( + "MATCH (src:Node {uri: $src})-[rel:Rel {uri: $rel}]->(dest:Node) " + "RETURN dest.uri as dest", + src=query.s.value, rel=query.p.value, database_=self.db, +) +``` + +**Código Atualizado:** +```python +records, summary, keys = self.io.execute_query( + "MATCH (src:Node {uri: $src, user: $user, collection: $collection})-" + "[rel:Rel {uri: $rel, user: $user, collection: $collection}]->" + "(dest:Node {user: $user, collection: $collection}) " + "RETURN dest.uri as dest", + src=query.s.value, rel=query.p.value, + user=query.user, collection=query.collection, + database_=self.db, +) +``` + +### Estratégia de Migração + +#### Fase 1: Adicionar Propriedades a Novos Dados +1. Atualizar o serviço de armazenamento para adicionar propriedades de usuário/coleção a novas triplas. +2. Manter a compatibilidade com versões anteriores, não exigindo propriedades nas consultas. +3. Os dados existentes permanecem acessíveis, mas não isolados. + +#### Fase 2: Migrar Dados Existentes +```cypher +// Migrate existing nodes (requires default user/collection assignment) +MATCH (n:Node) WHERE n.user IS NULL +SET n.user = 'legacy_user', n.collection = 'default_collection'; + +MATCH (n:Literal) WHERE n.user IS NULL +SET n.user = 'legacy_user', n.collection = 'default_collection'; + +MATCH ()-[r:Rel]->() WHERE r.user IS NULL +SET r.user = 'legacy_user', r.collection = 'default_collection'; +``` + +#### Fase 3: Impor Isolamento +1. Atualizar o serviço de consulta para exigir filtragem por usuário/coleção. +2. Adicionar validação para rejeitar consultas sem o contexto adequado de usuário/coleção. +3. Remover caminhos de acesso a dados legados. + +### Considerações de Segurança + +#### Validação de Consulta +```python +async def query_triples(self, query): + # Validate user/collection parameters + if not query.user or not query.collection: + raise ValueError("User and collection must be specified") + + # All queries must include user/collection filters + # ... rest of implementation +``` + +#### Prevenção de Injeção de Parâmetros +Use exclusivamente consultas parametrizadas +Valide os valores do usuário/coleção em relação a padrões permitidos +Considere a sanitização para os requisitos de nomes de propriedades do Neo4j + +#### Rastreamento de Auditoria +```python +logger.info(f"Query executed - User: {query.user}, Collection: {query.collection}, " + f"Pattern: {query.s}/{query.p}/{query.o}") +``` + +## Abordagens Alternativas Consideradas + +### Opção 2: Isolamento Baseado em Rótulos + +**Abordagem**: Utilize rótulos dinâmicos como `User_john_Collection_prod` + +**Vantagens:** +Forte isolamento através da filtragem de rótulos +Desempenho de consulta eficiente com índices de rótulos +Separação clara de dados + +**Desvantagens:** +O Neo4j possui limites práticos no número de rótulos (aproximadamente 1000) +Geração e sanitização complexas de nomes de rótulos +Difícil consultar entre coleções quando necessário + +**Exemplo de Implementação:** +```cypher +CREATE (n:Node:User_john_Collection_prod {uri: "http://example.com/entity"}) +MATCH (n:User_john_Collection_prod) WHERE n:Node RETURN n +``` + +### Opção 3: Banco de Dados por Usuário + +**Abordagem**: Criar bancos de dados Neo4j separados para cada usuário ou combinação de usuário/coleção. + +**Vantagens:** +Isolamento completo de dados +Sem risco de contaminação cruzada +Escalonamento independente por usuário + +**Desvantagens:** +Sobrecarga de recursos (cada banco de dados consome memória) +Gerenciamento complexo do ciclo de vida do banco de dados +Limites do banco de dados da Edição Community do Neo4j +Análise entre usuários difícil + +### Opção 4: Estratégia de Chave Composta + +**Abordagem**: Prefixar todos os URIs e valores com informações do usuário/coleção. + +**Vantagens:** +Compatível com consultas existentes +Implementação simples +Não requer alterações no esquema + +**Desvantagens:** +A poluição de URIs afeta a semântica dos dados +Consultas menos eficientes (correspondência de prefixo de string) +Viola padrões RDF/web semântico + +**Exemplo de Implementação:** +```python +def make_composite_uri(uri, user, collection): + return f"usr:{user}:col:{collection}:uri:{uri}" +``` + +## Plano de Implementação + +### Fase 1: Fundação (Semana 1) +1. [ ] Atualizar o serviço de armazenamento para aceitar e armazenar propriedades de usuário/coleção +2. [ ] Adicionar índices compostos para consultas eficientes +3. [ ] Implementar uma camada de compatibilidade retroativa +4. [ ] Criar testes unitários para novas funcionalidades + +### Fase 2: Atualizações de Consulta (Semana 2) +1. [ ] Atualizar todos os padrões de consulta para incluir filtros de usuário/coleção +2. [ ] Adicionar validação de consulta e verificações de segurança +3. [ ] Atualizar testes de integração +4. [ ] Testes de desempenho com consultas filtradas + +### Fase 3: Migração e Implantação (Semana 3) +1. [ ] Criar scripts de migração de dados para instâncias Neo4j existentes +2. [ ] Documentação de implantação e manuais de operação +3. [ ] Monitoramento e alertas para violações de isolamento +4. [ ] Testes de ponta a ponta com vários usuários/coleções + +### Fase 4: Reforço (Semana 4) +1. [ ] Remover o modo de compatibilidade legado +2. [ ] Adicionar registro de auditoria abrangente +3. [ ] Revisão de segurança e testes de penetração +4. [ ] Otimização de desempenho + +## Estratégia de Testes + +### Testes Unitários +```python +def test_user_collection_isolation(): + # Store triples for user1/collection1 + processor.store_triples(triples_user1_coll1) + + # Store triples for user2/collection2 + processor.store_triples(triples_user2_coll2) + + # Query as user1 should only return user1's data + results = processor.query_triples(query_user1_coll1) + assert all_results_belong_to_user1_coll1(results) + + # Query as user2 should only return user2's data + results = processor.query_triples(query_user2_coll2) + assert all_results_belong_to_user2_coll2(results) +``` + +### Testes de Integração +Cenários multiusuário com dados sobrepostos +Consultas entre coleções (devem falhar) +Testes de migração com dados existentes +Testes de desempenho com grandes conjuntos de dados + +### Testes de Segurança +Tentativa de consultar dados de outros usuários +Ataques de injeção de SQL em parâmetros de usuário/coleção +Verificar o isolamento completo sob vários padrões de consulta + +## Considerações de Desempenho + +### Estratégia de Indexação +Índices compostos em `(user, collection, uri)` para filtragem otimizada +Considere índices parciais se algumas coleções forem muito maiores +Monitore o uso de índices e o desempenho das consultas + +### Otimização de Consultas +Use EXPLAIN para verificar o uso de índices em consultas filtradas +Considere o cache de resultados de consulta para dados acessados com frequência +Monitore o uso de memória com um grande número de usuários/coleções + +### Escalabilidade +Cada combinação de usuário/coleção cria ilhas de dados separadas +Monitore o tamanho do banco de dados e o uso do pool de conexões +Considere estratégias de escalabilidade horizontal, se necessário + +## Segurança e Conformidade + +### Garantias de Isolamento de Dados +**Físico**: Todos os dados do usuário armazenados com propriedades explícitas de usuário/coleção +**Lógico**: Todas as consultas filtradas pelo contexto de usuário/coleção +**Controle de Acesso**: A validação no nível do serviço impede o acesso não autorizado + +### Requisitos de Auditoria +Registre todo o acesso a dados com o contexto de usuário/coleção +Rastreie atividades de migração e movimentação de dados +Monitore tentativas de violação de isolamento + +### Considerações de Conformidade +GDPR: Capacidade aprimorada de localizar e excluir dados específicos do usuário +SOC2: Isolamento claro de dados e controles de acesso +HIPAA: Forte isolamento de locatários para dados de saúde + +## Riscos e Mitigações + +| Risco | Impacto | Probabilidade | Mitigação | +|------|--------|------------|------------| +| Consulta sem o filtro de usuário/coleção | Alto | Médio | Validação obrigatória, testes abrangentes | +| Degradação de desempenho | Médio | Baixo | Otimização de índice, análise de desempenho | +| Corrupção de dados durante a migração | Alto | Baixo | Estratégia de backup, procedimentos de reversão | +| Consultas complexas entre várias coleções | Médio | Médio | Documente padrões de consulta, forneça exemplos | + +## Critérios de Sucesso + +1. **Segurança**: Zero acesso a dados de outros usuários em produção +2. **Desempenho**: Impacto de <10% no desempenho da consulta em comparação com consultas não filtradas +3. **Migração**: 100% dos dados existentes migrados com sucesso e sem perda +4. **Usabilidade**: Todos os padrões de consulta existentes funcionam com o contexto de usuário/coleção +5. **Conformidade**: Rastreamento completo de acesso a dados de usuário/coleção + +## Conclusão + +A abordagem de filtragem baseada em propriedades oferece o melhor equilíbrio entre segurança, desempenho e manutenção para adicionar o isolamento de usuário/coleção ao Neo4j. Ela se alinha aos padrões de multilocação existentes do TrustGraph, aproveitando os pontos fortes do Neo4j em consultas de grafos e indexação. + +Esta solução garante que o backend do Neo4j do TrustGraph atenda aos mesmos padrões de segurança de outros backends de armazenamento, prevenindo vulnerabilidades de isolamento de dados, mantendo a flexibilidade e o poder das consultas de grafos. \ No newline at end of file diff --git a/docs/tech-specs/neo4j-user-collection-isolation.tr.md b/docs/tech-specs/neo4j-user-collection-isolation.tr.md new file mode 100644 index 00000000..1b0d2c2f --- /dev/null +++ b/docs/tech-specs/neo4j-user-collection-isolation.tr.md @@ -0,0 +1,359 @@ +# Neo4j Kullanıcı/Koleksiyon İzolasyonu Desteği + +## Problem Tanımı + +Mevcut Neo4j üçlü depolama ve sorgu uygulaması, kullanıcı/koleksiyon izolasyonu eksikliği nedeniyle çoklu kiracılık güvenliği sorunlarına yol açmaktadır. Tüm üçlüler, kullanıcıların diğer kullanıcıların verilerine erişmesini veya koleksiyonları karıştırmasını engelleyen herhangi bir mekanizma olmadan aynı grafik alanında saklanmaktadır. + +TrustGraph'taki diğer depolama arka uçlarından farklı olarak: +**Cassandra**: Her kullanıcı için ayrı anahtarlar ve her koleksiyon için tablolar kullanır. +**Vektör depoları** (Milvus, Qdrant, Pinecone): Koleksiyona özgü ad alanlarını kullanır. +**Neo4j**: Şu anda tüm verileri tek bir grafik alanında paylaşır (güvenlik açığı). + +## Mevcut Mimari + +### Veri Modeli +**Düğümler**: `:Node` etiketi ile `uri` özelliği, `:Literal` etiketi ile `value` özelliği. +**İlişkiler**: `:Rel` etiketi ile `uri` özelliği. +**Dizinler**: `Node.uri`, `Literal.value`, `Rel.uri`. + +### Mesaj Akışı +`Triples` mesajları `metadata.user` ve `metadata.collection` alanlarını içerir. +Depolama hizmeti kullanıcı/koleksiyon bilgilerini alır, ancak bunları yoksayar. +Sorgu hizmeti `TriplesQueryRequest` içinde `user` ve `collection`'i bekler, ancak bunları yoksayar. + +### Mevcut Güvenlik Sorunu +```cypher +# Any user can query any data - no isolation +MATCH (src:Node)-[rel:Rel]->(dest:Node) +RETURN src.uri, rel.uri, dest.uri +``` + +## Önerilen Çözüm: Özellik Tabanlı Filtreleme (Önerilen) + +### Genel Bakış +Tüm düğümlere ve ilişkilerlere `user` ve `collection` özelliklerini ekleyin, ardından tüm işlemleri bu özelliklere göre filtreleyin. Bu yaklaşım, güçlü bir izolasyon sağlarken sorgu esnekliğini ve geriye dönük uyumluluğu korur. + +### Veri Modeli Değişiklikleri + +#### Gelişmiş Düğüm Yapısı +```cypher +// Node entities +CREATE (n:Node { + uri: "http://example.com/entity1", + user: "john_doe", + collection: "production_v1" +}) + +// Literal entities +CREATE (n:Literal { + value: "literal value", + user: "john_doe", + collection: "production_v1" +}) +``` + +#### Gelişmiş İlişki Yapısı +```cypher +// Relationships with user/collection properties +CREATE (src)-[:Rel { + uri: "http://example.com/predicate1", + user: "john_doe", + collection: "production_v1" +}]->(dest) +``` + +#### Güncellenmiş İndeksler +```cypher +// Compound indexes for efficient filtering +CREATE INDEX node_user_collection_uri FOR (n:Node) ON (n.user, n.collection, n.uri); +CREATE INDEX literal_user_collection_value FOR (n:Literal) ON (n.user, n.collection, n.value); +CREATE INDEX rel_user_collection_uri FOR ()-[r:Rel]-() ON (r.user, r.collection, r.uri); + +// Maintain existing indexes for backwards compatibility (optional) +CREATE INDEX Node_uri FOR (n:Node) ON (n.uri); +CREATE INDEX Literal_value FOR (n:Literal) ON (n.value); +CREATE INDEX Rel_uri FOR ()-[r:Rel]-() ON (r.uri); +``` + +### Uygulama Değişiklikleri + +#### Depolama Hizmeti (`write.py`) + +**Mevcut Kod:** +```python +def create_node(self, uri): + summary = self.io.execute_query( + "MERGE (n:Node {uri: $uri})", + uri=uri, database_=self.db, + ).summary +``` + +**Güncellenmiş Kod:** +```python +def create_node(self, uri, user, collection): + summary = self.io.execute_query( + "MERGE (n:Node {uri: $uri, user: $user, collection: $collection})", + uri=uri, user=user, collection=collection, database_=self.db, + ).summary +``` + +**Geliştirilmiş `store_triples` Metodu:** +```python +async def store_triples(self, message): + user = message.metadata.user + collection = message.metadata.collection + + for t in message.triples: + self.create_node(t.s.value, user, collection) + + if t.o.is_uri: + self.create_node(t.o.value, user, collection) + self.relate_node(t.s.value, t.p.value, t.o.value, user, collection) + else: + self.create_literal(t.o.value, user, collection) + self.relate_literal(t.s.value, t.p.value, t.o.value, user, collection) +``` + +#### Sorgu Hizmeti (`service.py`) + +**Mevcut Kod:** +```python +records, summary, keys = self.io.execute_query( + "MATCH (src:Node {uri: $src})-[rel:Rel {uri: $rel}]->(dest:Node) " + "RETURN dest.uri as dest", + src=query.s.value, rel=query.p.value, database_=self.db, +) +``` + +**Güncellenmiş Kod:** +```python +records, summary, keys = self.io.execute_query( + "MATCH (src:Node {uri: $src, user: $user, collection: $collection})-" + "[rel:Rel {uri: $rel, user: $user, collection: $collection}]->" + "(dest:Node {user: $user, collection: $collection}) " + "RETURN dest.uri as dest", + src=query.s.value, rel=query.p.value, + user=query.user, collection=query.collection, + database_=self.db, +) +``` + +### Göç Stratejisi + +#### 1. Aşama: Yeni Verilere Özellikler Ekleme +1. Kullanıcı/koleksiyon özelliklerini yeni üçlülere eklemek için depolama hizmetini güncelleyin. +2. Geriye dönük uyumluluğu korumak için sorgularda özelliklerin gerekli olmaması. +3. Mevcut veriler erişilebilir durumda kalır, ancak izole edilmez. + +#### 2. Aşama: Mevcut Verilerin Taşınması +```cypher +// Migrate existing nodes (requires default user/collection assignment) +MATCH (n:Node) WHERE n.user IS NULL +SET n.user = 'legacy_user', n.collection = 'default_collection'; + +MATCH (n:Literal) WHERE n.user IS NULL +SET n.user = 'legacy_user', n.collection = 'default_collection'; + +MATCH ()-[r:Rel]->() WHERE r.user IS NULL +SET r.user = 'legacy_user', r.collection = 'default_collection'; +``` + +#### 3. Aşama: İzolasyonu Sağlama +1. Sorgu hizmetini, kullanıcı/koleksiyon filtrelemesini gerektirecek şekilde güncelleyin. +2. Doğru kullanıcı/koleksiyon bağlamı olmadan yapılan sorguları reddedecek doğrulama ekleyin. +3. Eski veri erişim yollarını kaldırın. + +### Güvenlik Hususları + +#### Sorgu Doğrulama +```python +async def query_triples(self, query): + # Validate user/collection parameters + if not query.user or not query.collection: + raise ValueError("User and collection must be specified") + + # All queries must include user/collection filters + # ... rest of implementation +``` + +#### Parametre Enjeksiyonunu Önleme +Yalnızca parametreli sorguları kullanın +Kullanıcı/toplam değerlerini izin verilen kalıplara karşı doğrulayın +Neo4j özellik adı gereksinimleri için sanitizasyonu göz önünde bulundurun + +#### Denetim Kaydı +```python +logger.info(f"Query executed - User: {query.user}, Collection: {query.collection}, " + f"Pattern: {query.s}/{query.p}/{query.o}") +``` + +## Alternatif Yaklaşımlar + +### Seçenek 2: Etiket Tabanlı İzolasyon + +**Yaklaşım**: Dinamik etiketler kullanın, örneğin `User_john_Collection_prod` + +**Avantajları:** +Etiket filtreleme yoluyla güçlü izolasyon +Etiket indeksleriyle verimli sorgu performansı +Açık veri ayrımı + +**Dezavantajları:** +Neo4j'nin etiket sayısı konusunda pratik sınırlamaları vardır (~1000'ler) +Karmaşık etiket adı oluşturma ve temizleme +Gerekli olduğunda koleksiyonlar arasında sorgu yapmak zordur + +**Uygulama Örneği:** +```cypher +CREATE (n:Node:User_john_Collection_prod {uri: "http://example.com/entity"}) +MATCH (n:User_john_Collection_prod) WHERE n:Node RETURN n +``` + +### Seçenek 3: Kullanıcı Başına Veritabanı + +**Yaklaşım:** Her kullanıcı veya kullanıcı/koleksiyon kombinasyonu için ayrı Neo4j veritabanları oluşturun. + +**Avantajları:** +Tam veri izolasyonu +Çapraz bulaşma riski yok +Kullanıcı başına bağımsız ölçeklendirme + +**Dezavantajları:** +Kaynak yükü (her veritabanı bellek tüketir) +Karmaşık veritabanı yaşam döngüsü yönetimi +Neo4j Community Edition veritabanı limitleri +Kullanıcılar arası analizler yapmak zordur. + +### Seçenek 4: Bileşik Anahtar Stratejisi + +**Yaklaşım:** Tüm URI'ları ve değerleri kullanıcı/koleksiyon bilgileriyle ön ekleyin. + +**Avantajları:** +Mevcut sorgularla geriye dönük uyumluluk +Basit uygulama +Şema değişiklikleri gerektirmez + +**Dezavantajları:** +URI kirliliği, veri anlamını etkiler +Daha az verimli sorgular (dize ön eki eşleştirme) +RDF/semantik web standartlarını ihlal eder + +**Uygulama Örneği:** +```python +def make_composite_uri(uri, user, collection): + return f"usr:{user}:col:{collection}:uri:{uri}" +``` + +## Uygulama Planı + +### Aşama 1: Temel (1. Hafta) +1. [ ] Depolama hizmetini, kullanıcı/koleksiyon özelliklerini kabul edecek ve saklayacak şekilde güncelleyin. +2. [ ] Verimli sorgulama için bileşik indeksler ekleyin. +3. [ ] Geriye dönük uyumluluk katmanı uygulayın. +4. [ ] Yeni işlevler için birim testleri oluşturun. + +### Aşama 2: Sorgu Güncellemeleri (2. Hafta) +1. [ ] Tüm sorgu kalıplarını, kullanıcı/koleksiyon filtrelerini içerecek şekilde güncelleyin. +2. [ ] Sorgu doğrulaması ve güvenlik kontrolleri ekleyin. +3. [ ] Entegrasyon testlerini güncelleyin. +4. [ ] Filtrelenmiş sorgularla performans testi yapın. + +### Aşama 3: Göç ve Dağıtım (3. Hafta) +1. [ ] Mevcut Neo4j örnekleri için veri geçiş betikleri oluşturun. +2. [ ] Dağıtım belgeleri ve çalıştırma kılavuzları. +3. [ ] İzolasyon ihlalleri için izleme ve uyarı. +4. [ ] Çok sayıda kullanıcı/koleksiyonla uçtan uca testler yapın. + +### Aşama 4: Güçlendirme (4. Hafta) +1. [ ] Eski uyumluluk modunu kaldırın. +2. [ ] Kapsamlı denetim kaydı ekleyin. +3. [ ] Güvenlik incelemesi ve sızma testi. +4. [ ] Performans optimizasyonu. + +## Test Stratejisi + +### Birim Testleri +```python +def test_user_collection_isolation(): + # Store triples for user1/collection1 + processor.store_triples(triples_user1_coll1) + + # Store triples for user2/collection2 + processor.store_triples(triples_user2_coll2) + + # Query as user1 should only return user1's data + results = processor.query_triples(query_user1_coll1) + assert all_results_belong_to_user1_coll1(results) + + # Query as user2 should only return user2's data + results = processor.query_triples(query_user2_coll2) + assert all_results_belong_to_user2_coll2(results) +``` + +### Entegrasyon Testleri +Eş zamanlı veri içeren çok kullanıcılı senaryolar +Koleksiyonlar arası sorgular (başarısız olmalıdır) +Mevcut verilerle yapılan geçiş testleri +Büyük veri kümeleriyle yapılan performans ölçümleri + +### Güvenlik Testleri +Diğer kullanıcıların verilerine erişme girişimleri +Kullanıcı/koleksiyon parametrelerine yönelik SQL enjeksiyonu tarzı saldırılar +Çeşitli sorgu kalıpları altında tam izolasyonu doğrulayın + +## Performans Hususları + +### İndeks Stratejisi +Optimum filtreleme için `(user, collection, uri)` üzerinde birleşik indeksler +Bazı koleksiyonların çok daha büyük olması durumunda, kısmi indeksleri göz önünde bulundurun +İndeks kullanımını ve sorgu performansını izleyin + +### Sorgu Optimizasyonu +Filtrelenmiş sorgularda indeks kullanımını doğrulamak için EXPLAIN'i kullanın +Sık erişilen veriler için sorgu sonucu önbelleklemesini göz önünde bulundurun +Çok sayıda kullanıcı/koleksiyonla bellek kullanımını analiz edin + +### Ölçeklenebilirlik +Her kullanıcı/koleksiyon kombinasyonu, ayrı veri adacıkları oluşturur +Veritabanı boyutunu ve bağlantı havuzu kullanımını izleyin +Gerekirse, yatay ölçeklendirme stratejilerini göz önünde bulundurun + +## Güvenlik ve Uyumluluk + +### Veri İzolasyon Garantileri +**Fiziksel**: Tüm kullanıcı verileri, açık kullanıcı/koleksiyon özellikleri ile saklanır +**Mantıksal**: Tüm sorgular, kullanıcı/koleksiyon bağlamıyla filtrelenir +**Erişim Kontrolü**: Hizmet seviyesindeki doğrulama, yetkisiz erişimi engeller + +### Denetim Gereksinimleri +Tüm veri erişimlerini kullanıcı/koleksiyon bağlamıyla kaydedin +Geçiş etkinliklerini ve veri hareketlerini izleyin +İzolasyon ihlali girişimlerini izleyin + +### Uyumluluk Hususları +GDPR: Kullanıcıya özel verileri bulma ve silme yeteneğinin geliştirilmesi +SOC2: Açık veri izolasyonu ve erişim kontrolleri +HIPAA: Sağlık verileri için güçlü kiracı izolasyonu + +## Riskler ve Önlemler + +| Risk | Etki | Olasılık | Önlem | +|------|--------|------------|------------| +| Sorguda eksik kullanıcı/koleksiyon filtresi | Yüksek | Orta | Zorunlu doğrulama, kapsamlı testler | +| Performans düşüşü | Orta | Düşük | İndeks optimizasyonu, sorgu analizi | +| Geçiş sırasında veri bozulması | Yüksek | Düşük | Yedekleme stratejisi, geri alma prosedürleri | +| Karmaşık, koleksiyonlar arası sorgular | Orta | Orta | Sorgu kalıplarını belgeleyin, örnekler sağlayın | + +## Başarı Kriterleri + +1. **Güvenlik**: Üretimde, kullanıcılar arası veri erişiminin sıfır olması +2. **Performans**: Filtrelenmemiş sorgulara kıyasla %10'dan düşük sorgu performans etkisi +3. **Geçiş**: Mevcut verilerin %100'ü, kayıp olmadan başarıyla geçirilmiştir +4. **Kullanılabilirlik**: Tüm mevcut sorgu kalıpları, kullanıcı/koleksiyon bağlamıyla çalışır +5. **Uyumluluk**: Kullanıcı/koleksiyon verilerine yapılan tüm erişimlerin tam denetim kaydı + +## Sonuç + +Özellik tabanlı filtreleme yaklaşımı, Neo4j'ye kullanıcı/koleksiyon izolasyonu eklemek için güvenlik, performans ve bakım açısından en iyi dengeyi sağlar. TrustGraph'ın mevcut çok kiracılık kalıplarıyla uyumludur ve aynı zamanda Neo4j'nin grafik sorgulama ve indeksleme konusundaki güçlü yönlerinden yararlanır. + +Bu çözüm, TrustGraph'ın Neo4j arka ucunun, diğer depolama arka uçları ile aynı güvenlik standartlarını karşılamasını sağlar ve veri izolasyonu güvenlik açıklarını önlerken, grafik sorgularının esnekliğini ve gücünü korur. \ No newline at end of file diff --git a/docs/tech-specs/ontology-extract-phase-2.ar.md b/docs/tech-specs/ontology-extract-phase-2.ar.md new file mode 100644 index 00000000..24cf63bb --- /dev/null +++ b/docs/tech-specs/ontology-extract-phase-2.ar.md @@ -0,0 +1,761 @@ +# استخراج المعرفة من علم الوجود - المرحلة الثانية، إعادة هيكلة + +**الحالة**: مسودة +**المؤلف**: جلسة التحليل بتاريخ 2025-12-03 +**مرتبط بـ**: `ontology.md`، `ontorag.md` + +## نظرة عامة + +يحدد هذا المستند التناقضات الموجودة في نظام استخراج المعرفة الحالي القائم على علم الوجود ويقترح إعادة هيكلة لتحسين أداء نماذج اللغة الكبيرة وتقليل فقدان المعلومات. + +## التنفيذ الحالي + +### كيف يعمل الآن + +1. **تحميل علم الوجود** (`ontology_loader.py`) + يقوم بتحميل ملف JSON الخاص بعلم الوجود باستخدام مفاتيح مثل `"fo/Recipe"`، `"fo/Food"`، `"fo/produces"` + تتضمن معرفات الفئات بادئة مساحة الاسم في المفتاح نفسه. + مثال من `food.ontology`: + ```json + "classes": { + "fo/Recipe": { + "uri": "http://purl.org/ontology/fo/Recipe", + "rdfs:comment": "A Recipe is a combination..." + } + } + ``` + +2. **بناء المطالبة** (`extract.py:299-307`، `ontology-prompt.md`) + يتلقى النموذج `classes`، `object_properties`، `datatype_properties` (قواميس). + يتكرر النموذج: `{% for class_id, class_def in classes.items() %}` + يرى نموذج اللغة الكبيرة (LLM): `**fo/Recipe**: A Recipe is a combination...` + يوضح تنسيق الإخراج النموذجي: + ```json + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} + {"subject": "recipe:cornish-pasty", "predicate": "has_ingredient", "object": "ingredient:flour"} + ``` + +3. **تحليل الاستجابة** (`extract.py:382-428`) + يتوقع مصفوفة JSON: `[{"subject": "...", "predicate": "...", "object": "..."}]` + يتحقق من الصحة مقابل مجموعة فرعية من علم الوجود. + يوسع الـ URIs عبر `expand_uri()` (extract.py:473-521) + +4. **توسيع الـ URI** (`extract.py:473-521`) + يتحقق مما إذا كانت القيمة موجودة في قاموس `ontology_subset.classes`. + إذا تم العثور عليها، يتم استخراج الـ URI من تعريف الفئة. + إذا لم يتم العثور عليها، يتم إنشاء الـ URI: `f"https://trustgraph.ai/ontology/{ontology_id}#{value}"` + +### مثال تدفق البيانات + +**JSON لعلم الوجود → المحمل → المطالبة:** +``` +"fo/Recipe" → classes["fo/Recipe"] → LLM sees "**fo/Recipe**" +``` + +**نموذج اللغة الكبير → المحلل → الإخراج:** +``` +"Recipe" → not in classes["fo/Recipe"] → constructs URI → LOSES original URI +"fo/Recipe" → found in classes → uses original URI → PRESERVES URI +``` + +## المشكلات التي تم تحديدها + +### 1. **أمثلة غير متسقة في التعليمات** + +**المشكلة**: قالب التعليمات يعرض معرفات الفئات مع بادئات (`fo/Recipe`) ولكن الإخراج النموذجي يستخدم أسماء فئات بدون بادئات (`Recipe`). + +**الموقع**: `ontology-prompt.md:5-52` + +```markdown +## Ontology Classes: +- **fo/Recipe**: A Recipe is... + +## Example Output: +{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} +``` + +**التأثير:** يتلقى نموذج اللغة الكبير إشارات متضاربة حول التنسيق الذي يجب استخدامه. + +### 2. **فقدان المعلومات في توسيع عنوان URL** + +**المشكلة:** عندما يقوم نموذج اللغة الكبير بإرجاع أسماء الفئات غير المسبوقة بعد المثال، لا يمكن لـ `expand_uri()` العثور عليها في قاموس الأونطولوجيا ويقوم بإنشاء عناوين URI احتياطية، مما يؤدي إلى فقدان عناوين URI الأصلية الصحيحة. + +**الموقع:** `extract.py:494-500` + +```python +if value in ontology_subset.classes: # Looks for "Recipe" + class_def = ontology_subset.classes[value] # But key is "fo/Recipe" + if isinstance(class_def, dict) and 'uri' in class_def: + return class_def['uri'] # Never reached! +return f"https://trustgraph.ai/ontology/{ontology_id}#{value}" # Fallback +``` + +**التأثير:** +عنوان URI الأصلي: `http://purl.org/ontology/fo/Recipe` +عنوان URI المُنشأ: `https://trustgraph.ai/ontology/food#Recipe` +فقدان المعنى الدلالي، مما يعيق التوافقية. + +### 3. **تنسيق مثيل الكيان الغامض** + +**المشكلة:** لا توجد إرشادات واضحة حول تنسيق عنوان URI لمثيل الكيان. + +**أمثلة في التعليمات:** +`"recipe:cornish-pasty"` (بادئة تشبه مساحة الاسم) +`"ingredient:flour"` (بادئة مختلفة) + +**السلوك الفعلي** (extract.py:517-520): +```python +# Treat as entity instance - construct unique URI +normalized = value.replace(" ", "-").lower() +return f"https://trustgraph.ai/{ontology_id}/{normalized}" +``` + +**التأثير**: يجب على نموذج اللغة الكبير تخمين اتفاقية البادئات بدون أي سياق دلالي. + +### 4. **لا توجد إرشادات حول بادئات النطاقات**. + +**المشكلة**: يحتوي ملف JSON الخاص بالدلالة على تعريفات النطاقات (السطر 10-25 في food.ontology): +```json +"namespaces": { + "fo": "http://purl.org/ontology/fo/", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + ... +} +``` + +ولكن هذه العناصر لا يتم إرسالها أبدًا إلى نموذج اللغة الكبير (LLM). نموذج اللغة الكبير لا يعرف: +ما الذي تعنيه كلمة "fo" +ما هو البادئة التي يجب استخدامها للكائنات +أي مساحة اسم تنطبق على أي عناصر + +### 5. **التسميات غير المستخدمة في المطالبة** + +**المشكلة:** كل فئة لديها `rdfs:label` حقول (مثل `{"value": "Recipe", "lang": "en-gb"}`)، ولكن قالب المطالبة لا يستخدمها. + +**الحالي:** يعرض فقط `class_id` و `comment` +```jinja +- **{{class_id}}**{% if class_def.comment %}: {{class_def.comment}}{% endif %} +``` + +**متاح ولكنه غير مستخدم:** +```python +"rdfs:label": [{"value": "Recipe", "lang": "en-gb"}] +``` + +**التأثير**: يمكن أن يوفر أسماءً قابلة للقراءة من قبل الإنسان جنبًا إلى جنب مع المعرفات التقنية. + +## الحلول المقترحة + +### الخيار أ: التوحيد إلى معرفات غير مُسبقة + +**النهج**: إزالة البادئات من معرفات الفئات قبل عرضها لنظام LLM. + +**التغييرات**: +1. تعديل `build_extraction_variables()` لتحويل المفاتيح: + ```python + classes_for_prompt = { + k.split('/')[-1]: v # "fo/Recipe" → "Recipe" + for k, v in ontology_subset.classes.items() + } + ``` + +2. تحديث مثال المطالبة ليتطابق (يستخدم بالفعل أسماء غير مسبوقة). + +3. تعديل `expand_uri()` للتعامل مع كلا التنسيقين: + ```python + # Try exact match first + if value in ontology_subset.classes: + return ontology_subset.classes[value]['uri'] + + # Try with prefix + for prefix in ['fo/', 'rdf:', 'rdfs:']: + prefixed = f"{prefix}{value}" + if prefixed in ontology_subset.classes: + return ontology_subset.classes[prefixed]['uri'] + ``` + +**المزايا:** +أنظف وأكثر قابلية للقراءة من قبل البشر. +تتوافق مع أمثلة المطالبات الحالية. +تعمل نماذج اللغات الكبيرة بشكل أفضل مع الرموز الأبسط. + +**العيوب:** +تعارض أسماء الفئات إذا كانت هناك العديد من الأنطولوجيات لها نفس اسم الفئة. +تفقد معلومات مساحة الاسم. +تتطلب منطقًا احتياطيًا للبحث. + +### الخيار ب: استخدام المعرفات الكاملة المسبوقة باستمرار + +**الطريقة:** تحديث الأمثلة لاستخدام المعرفات المسبوقة التي تتطابق مع ما هو موضح في قائمة الفئات. + +**التغييرات:** +1. تحديث مثال المطالبة (ontology-prompt.md:46-52): + ```json + [ + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "fo/Recipe"}, + {"subject": "recipe:cornish-pasty", "predicate": "rdfs:label", "object": "Cornish Pasty"}, + {"subject": "recipe:cornish-pasty", "predicate": "fo/produces", "object": "food:cornish-pasty"}, + {"subject": "food:cornish-pasty", "predicate": "rdf:type", "object": "fo/Food"} + ] + ``` + +2. أضف شرحًا لمساحة الاسم إلى التعليمات: + ```markdown + ## Namespace Prefixes: + - **fo/**: Food Ontology (http://purl.org/ontology/fo/) + - **rdf:**: RDF Schema + - **rdfs:**: RDF Schema + + Use these prefixes exactly as shown when referencing classes and properties. + ``` + +3. احتفظ بـ `expand_uri()` كما هو (يعمل بشكل صحيح عند العثور على تطابقات). + +**المزايا:** +اتساق الإدخال والإخراج. +عدم وجود فقدان للمعلومات. +يحافظ على دلالات مساحة الاسم. +يعمل مع العديد من الأنطولوجيات. + +**العيوب:** +رموز أكثر تفصيلاً لنظام LLM. +يتطلب من نظام LLM تتبع البادئات. + +### الخيار ج: هجين - عرض كل من التسمية والمعرف + +**النهج:** قم بتحسين المطالبة لعرض كل من التسميات المقروءة من قبل الإنسان والمعرفات التقنية. + +**التغييرات:** +1. تحديث قالب المطالبة: + ```jinja + {% for class_id, class_def in classes.items() %} + - **{{class_id}}** (label: "{{class_def.labels[0].value if class_def.labels else class_id}}"){% if class_def.comment %}: {{class_def.comment}}{% endif %} + {% endfor %} + ``` + + الناتج النموذجي: + ```markdown + - **fo/Recipe** (label: "Recipe"): A Recipe is a combination... + ``` + +2. تعليمات التحديث: + ```markdown + When referencing classes: + - Use the full prefixed ID (e.g., "fo/Recipe") in JSON output + - The label (e.g., "Recipe") is for human understanding only + ``` + +**المزايا:** +الأوضح لنماذج اللغة الكبيرة (LLM) +يحافظ على جميع المعلومات +يوضح بشكل صريح ما يجب استخدامه + +**العيوب:** +طلب أطول +قالب أكثر تعقيدًا + +## النهج المطبق + +**تنسيق مبسط للعلاقة بين الكيانات والخصائص** - يحل محل التنسيق القديم القائم على الثلاثيات تمامًا. + +تم اختيار النهج الجديد لأنه: + +1. **لا يوجد فقدان للمعلومات**: يتم الحفاظ على عناوين URI الأصلية بشكل صحيح. +2. **منطق أبسط**: لا توجد حاجة إلى أي تحويل، تعمل عمليات البحث المباشرة في القواميس. +3. **أمان مساحة الاسم**: يتعامل مع العديد من الأنطولوجيات دون حدوث تعارضات. +4. **الصحة الدلالية**: يحافظ على الدلالات الخاصة بـ RDF/OWL. + +## التنفيذ مكتمل + +### ما تم بناؤه: + +1. **قالب طلب جديد** (`prompts/ontology-extract-v2.txt`) + ✅ أقسام واضحة: أنواع الكيانات، العلاقات، الخصائص. + ✅ مثال باستخدام معرفات النوع الكاملة (`fo/Recipe`، `fo/has_ingredient`). + ✅ تعليمات لاستخدام المعرفات الدقيقة من المخطط. + ✅ تنسيق JSON جديد مع مصفوفات الكيانات/العلاقات/الخصائص. + +2. **تسوية الكيانات** (`entity_normalizer.py`) + ✅ `normalize_entity_name()` - يحول الأسماء إلى تنسيق آمن لـ URI. + ✅ `normalize_type_identifier()` - يتعامل مع الشرطات المائلة في الأنواع (`fo/Recipe` → `fo-recipe`). + ✅ `build_entity_uri()` - ينشئ عناوين URI فريدة باستخدام زوج (الاسم، النوع). + ✅ `EntityRegistry` - يتتبع الكيانات لتجنب التكرار. + +3. **محلل JSON** (`simplified_parser.py`) + ✅ يحلل التنسيق الجديد: `{entities: [...], relationships: [...], attributes: [...]}`. + ✅ يدعم أسماء الحقول بتنسيق kebab-case و snake_case. + ✅ يُرجع فئات بيانات منظمة. + ✅ معالجة أخطاء سلسة مع التسجيل. + +4. **محول الثلاثيات** (`triple_converter.py`) + ✅ `convert_entity()` - ينشئ ثلاثيات النوع + التسمية تلقائيًا. + ✅ `convert_relationship()` - يربط عناوين URI للكيانات عبر الخصائص. + ✅ `convert_attribute()` - يضيف القيم الحرفية. + ✅ يبحث عن عناوين URI الكاملة من تعريفات الأنطولوجيا. + +5. **المعالج الرئيسي المحدث** (`extract.py`) + ✅ تمت إزالة كود الاستخراج القديم القائم على الثلاثيات. + ✅ تمت إضافة `extract_with_simplified_format()`. + ✅ يستخدم الآن التنسيق المبسط الجديد فقط. + ✅ يستدعي الطلب بمعرف `extract-with-ontologies-v2`. + +## حالات الاختبار + +### الاختبار 1: الحفاظ على عنوان URI +```python +# Given ontology class +classes = {"fo/Recipe": {"uri": "http://purl.org/ontology/fo/Recipe", ...}} + +# When LLM returns +llm_output = {"subject": "x", "predicate": "rdf:type", "object": "fo/Recipe"} + +# Then expanded URI should be +assert expanded == "http://purl.org/ontology/fo/Recipe" +# Not: "https://trustgraph.ai/ontology/food#Recipe" +``` + +### الاختبار 2: التصادم متعدد الأنطولوجيا +```python +# Given two ontologies +ont1 = {"fo/Recipe": {...}} +ont2 = {"cooking/Recipe": {...}} + +# LLM should use full prefix to disambiguate +llm_output = {"object": "fo/Recipe"} # Not just "Recipe" +``` + +### الاختبار رقم 3: تنسيق مثيل الكيان +```python +# Given prompt with food ontology +# LLM should create instances like +{"subject": "recipe:cornish-pasty"} # Namespace-style +{"subject": "food:beef"} # Consistent prefix +``` + +## أسئلة مفتوحة + +1. **هل يجب أن تستخدم حالات الكيانات بادئات النطاق؟** + الحالي: `"recipe:cornish-pasty"` (عشوائي) + بديل: استخدام بادئة الأونطولوجيا `"fo:cornish-pasty"`؟ + بديل: بدون بادئة، التوسع في URI `"cornish-pasty"` → URI كامل؟ + +2. **كيفية التعامل مع النطاق/المدى في المطالبة؟** + يعرض حاليًا: `(Recipe → Food)` + هل يجب أن يكون: `(fo/Recipe → fo/Food)`؟ + +3. **هل يجب علينا التحقق من صحة قيود النطاق/المدى؟** + ملاحظة TODO في extract.py:470 + سيكتشف المزيد من الأخطاء ولكنه أكثر تعقيدًا + +4. **ماذا عن الخصائص العكسية والتكافؤات؟** + تحتوي الأونطولوجيا على `owl:inverseOf`، `owl:equivalentClass` + لا يتم استخدامه حاليًا في الاستخراج + هل يجب أن يتم استخدامه؟ + +## مقاييس النجاح + +✅ عدم وجود فقدان لمعلومات URI (100٪ للحفاظ على URIs الأصلية) +✅ تنسيق إخراج LLM يطابق تنسيق الإدخال +✅ لا توجد أمثلة غامضة في المطالبة +✅ اجتياز الاختبارات مع العديد من الأونطولوجيات +✅ تحسين جودة الاستخراج (يتم قياسه بالنسبة المئوية للثلاثيات الصالحة) + +## نهج بديل: تنسيق استخراج مبسط + +### الفلسفة + +بدلاً من مطالبة LLM بفهم دلالات RDF/OWL، اطلب منه فعل ما هو جيد فيه: **العثور على الكيانات والعلاقات في النص**. + +دع الكود يتعامل مع بناء URI، وتحويل RDF، والشؤون الرسمية للويب الدلالي. + +### مثال: تصنيف الكيانات + +**النص المدخل:** +``` +Cornish pasty is a traditional British pastry filled with meat and vegetables. +``` + +**مخطط علم الوجود (يُعرض على نموذج اللغة الكبير):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food +``` + +**ماذا يُرجع نموذج اللغة الكبير (JSON بسيط):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + } + ] +} +``` + +**ما الذي ينتجه الكود (ثلاثيات RDF):** +```python +# 1. Normalize entity name + type to ID (type prevents collisions) +entity_id = "recipe-cornish-pasty" # normalize("Cornish pasty", "Recipe") +entity_uri = "https://trustgraph.ai/food/recipe-cornish-pasty" + +# Note: Same name, different type = different URI +# "Cornish pasty" (Recipe) → recipe-cornish-pasty +# "Cornish pasty" (Food) → food-cornish-pasty + +# 2. Generate triples +triples = [ + # Type triple + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/1999/02/22-rdf-syntax-ns#type", is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + # Label triple (automatic) + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/2000/01/rdf-schema#label", is_uri=True), + o=Value(value="Cornish pasty", is_uri=False) + ) +] +``` + +### المزايا + +1. **نموذج اللغة الكبير (LLM) لا يحتاج إلى:** + فهم بناء جمل URI + اختراع بادئات المعرفات (`recipe:`، `ingredient:`) + معرفة عن `rdf:type` أو `rdfs:label` + إنشاء معرفات الويب الدلالي + +2. **نموذج اللغة الكبير (LLM) يحتاج فقط إلى:** + العثور على الكيانات في النص + ربطها بفئات علم الوجود + استخراج العلاقات والسمات + +3. **الكود يتعامل مع:** + تطبيع وبناء URI + توليد ثلاثيات RDF + تعيين تسميات تلقائيًا + إدارة مساحات الأسماء + +### لماذا هذا أفضل + +**موجه أبسط** = تقليل الارتباك = تقليل الأخطاء +**معرفات متسقة** = الكود يتحكم في قواعد التطبيع +**تسميات مُولدة تلقائيًا** = لا توجد ثلاثيات rdfs:label مفقودة +**يركز نموذج اللغة الكبير على الاستخراج** = وهو ما يتقنه بالفعل + +### مثال: علاقات الكيانات + +**النص المدخل:** +``` +Cornish pasty is a traditional British pastry filled with beef and potatoes. +``` + +**مخطط علم الوجود (معروض للنموذج اللغوي الكبير):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food + +## Relationships: +- has_ingredient: Relates a recipe to an ingredient it uses (Recipe → Ingredient) +- food: Relates an ingredient to the food that is required (Ingredient → Food) +``` + +**ماذا يُرجع نموذج اللغة الكبير (JSON بسيط):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ] +} +``` + +**ما الذي ينتجه الكود (ثلاثيات RDF):** +```python +# Normalize entity names to URIs +cornish_pasty_uri = "https://trustgraph.ai/food/cornish-pasty" +beef_uri = "https://trustgraph.ai/food/beef" +potatoes_uri = "https://trustgraph.ai/food/potatoes" + +# Look up relation URI from ontology +has_ingredient_uri = "http://purl.org/ontology/fo/ingredients" # from fo/has_ingredient + +triples = [ + # Entity type triples (as before) + Triple(s=cornish_pasty_uri, p=rdf_type, o="http://purl.org/ontology/fo/Recipe"), + Triple(s=cornish_pasty_uri, p=rdfs_label, o="Cornish pasty"), + + Triple(s=beef_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=beef_uri, p=rdfs_label, o="beef"), + + Triple(s=potatoes_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=potatoes_uri, p=rdfs_label, o="potatoes"), + + # Relationship triples + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=beef_uri, is_uri=True) + ), + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=potatoes_uri, is_uri=True) + ) +] +``` + +**النقاط الرئيسية:** +تقوم نماذج اللغة الكبيرة بإرجاع أسماء الكيانات باللغة الطبيعية: `"Cornish pasty"`، `"beef"`، `"potatoes"` +تتضمن نماذج اللغة الكبيرة أنواعًا لتوضيح المعنى: `subject-type`، `object-type` +تستخدم نماذج اللغة الكبيرة اسم العلاقة من المخطط: `"has_ingredient"` +تستخدم الشيفرة معرّفات متسقة باستخدام (الاسم، النوع): `("Cornish pasty", "Recipe")` → `recipe-cornish-pasty` +تبحث الشيفرة عن عنوان URI للعلاقة من علم الوجود: `fo/has_ingredient` → عنوان URI الكامل +دائمًا ما تحصل المجموعة نفسها (الاسم، النوع) على نفس عنوان URI (إزالة التكرار) + +### مثال: التمييز بين أسماء الكيانات + +**المشكلة:** يمكن أن يشير نفس الاسم إلى أنواع مختلفة من الكيانات. + +**حالة واقعية:** +``` +"Cornish pasty" can be: +- A Recipe (instructions for making it) +- A Food (the dish itself) +``` + +**كيف يتم التعامل معها:** + +يقوم نموذج اللغة الكبير بإرجاع كليهما ككيانات منفصلة: +```json +{ + "entities": [ + {"entity": "Cornish pasty", "type": "Recipe"}, + {"entity": "Cornish pasty", "type": "Food"} + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "produces", + "object": "Cornish pasty", + "object-type": "Food" + } + ] +} +``` + +**حل التعليمات البرمجية:** +```python +# Different types → different URIs +recipe_uri = normalize("Cornish pasty", "Recipe") +# → "https://trustgraph.ai/food/recipe-cornish-pasty" + +food_uri = normalize("Cornish pasty", "Food") +# → "https://trustgraph.ai/food/food-cornish-pasty" + +# Relationship connects them correctly +triple = Triple( + s=recipe_uri, # The Recipe + p="http://purl.org/ontology/fo/produces", + o=food_uri # The Food +) +``` + +**لماذا هذا يعمل:** +يتم تضمين النوع في جميع المراجع (الكيانات، والعلاقات، والسمات). +يستخدم الكود `(name, type)` كـ "مجموعة" (tuple) كمفتاح للبحث. +لا يوجد غموض، ولا توجد تعارضات. + +### مثال: سمات الكيان + +**النص المدخل:** +``` +This Cornish pasty recipe serves 4-6 people and takes 45 minutes to prepare. +``` + +**مخطط علم الوجود (يُعرض على نموذج اللغة الكبير):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method + +## Attributes: +- serves: Indicates what the recipe is intended to serve (Recipe → text) +- preparation_time: Time needed to prepare the recipe (Recipe → text) +``` + +**ماذا يُرجع نموذج اللغة الكبير (JSON بسيط):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty recipe", + "type": "Recipe" + } + ], + "attributes": [ + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4-6 people" + }, + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "preparation_time", + "value": "45 minutes" + } + ] +} +``` + +**ما الذي ينتجه الكود (ثلاثيات RDF):** +```python +# Normalize entity name to URI +recipe_uri = "https://trustgraph.ai/food/cornish-pasty-recipe" + +# Look up attribute URIs from ontology +serves_uri = "http://purl.org/ontology/fo/serves" # from fo/serves +prep_time_uri = "http://purl.org/ontology/fo/preparation_time" # from fo/preparation_time + +triples = [ + # Entity type triple + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdf_type, is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + + # Label triple (automatic) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdfs_label, is_uri=True), + o=Value(value="Cornish pasty recipe", is_uri=False) + ), + + # Attribute triples (objects are literals, not URIs) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=serves_uri, is_uri=True), + o=Value(value="4-6 people", is_uri=False) # Literal value! + ), + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=prep_time_uri, is_uri=True), + o=Value(value="45 minutes", is_uri=False) # Literal value! + ) +] +``` + +**النقاط الرئيسية:** +يستخرج نموذج اللغة الكبير القيم الحرفية: `"4-6 people"`، `"45 minutes"` +يتضمن نموذج اللغة الكبير نوع الكيان لتوضيح المعنى: `entity-type` +يستخدم نموذج اللغة الكبير اسم الخاصية من المخطط: `"serves"`، `"preparation_time"` +يبحث الكود عن عنوان URI للخاصية من خصائص نوع البيانات في علم الوجود. +**الكائن هو قيمة حرفية** (`is_uri=False`)، وليس مرجع URI. +تظل القيم كنص طبيعي، ولا تحتاج إلى تطبيع. + +**الفرق عن العلاقات:** +العلاقات: كل من الموضوع والمفعول به هما كيانات (URIs). +الخصائص: الموضوع هو كيان (URI)، والمفعول به هو قيمة حرفية (نص/رقم). + +### مثال كامل: الكيانات + العلاقات + الخصائص + +**النص المدخل:** +``` +Cornish pasty is a savory pastry filled with beef and potatoes. +This recipe serves 4 people. +``` + +**ماذا يُرجع نموذج اللغة الكبير:** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ], + "attributes": [ + { + "entity": "Cornish pasty", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4 people" + } + ] +} +``` + +**النتيجة:** تم توليد 11 ثلاثية RDF: +3 ثلاثيات لنوع الكيان (rdf:type) +3 ثلاثيات لملصق الكيان (rdfs:label) - تلقائي +2 ثلاثية للعلاقة (has_ingredient) +1 ثلاثية للخاصية (serves) + +كل ذلك من خلال استخلاص بسيط وسهل من اللغة الطبيعية بواسطة نموذج اللغة الكبير! + +## المراجع + +التنفيذ الحالي: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` +قالب التعليمات: `ontology-prompt.md` +حالات الاختبار: `tests/unit/test_extract/test_ontology/` +مثال على علم الوجود: `e2e/test-data/food.ontology` diff --git a/docs/tech-specs/ontology-extract-phase-2.es.md b/docs/tech-specs/ontology-extract-phase-2.es.md new file mode 100644 index 00000000..5fcd9e65 --- /dev/null +++ b/docs/tech-specs/ontology-extract-phase-2.es.md @@ -0,0 +1,761 @@ +# Extracción de Conocimiento Ontológico - Fase 2, Refactorización + +**Estado**: Borrador +**Autor**: Sesión de Análisis 2025-12-03 +**Relacionado**: `ontology.md`, `ontorag.md` + +## Resumen + +Este documento identifica inconsistencias en el sistema actual de extracción de conocimiento basado en ontologías y propone una refactorización para mejorar el rendimiento de los LLM y reducir la pérdida de información. + +## Implementación Actual + +### Cómo Funciona Actualmente + +1. **Carga de la Ontología** (`ontology_loader.py`) + Carga el archivo JSON de la ontología con claves como `"fo/Recipe"`, `"fo/Food"`, `"fo/produces"` + Los ID de las clases incluyen el prefijo del espacio de nombres en la clave. + Ejemplo de `food.ontology`: + ```json + "classes": { + "fo/Recipe": { + "uri": "http://purl.org/ontology/fo/Recipe", + "rdfs:comment": "A Recipe is a combination..." + } + } + ``` + +2. **Construcción del prompt** (`extract.py:299-307`, `ontology-prompt.md`) + La plantilla recibe diccionarios `classes`, `object_properties`, `datatype_properties` + La plantilla itera: `{% for class_id, class_def in classes.items() %}` + El LLM ve: `**fo/Recipe**: A Recipe is a combination...` + El formato de salida de ejemplo muestra: + ```json + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} + {"subject": "recipe:cornish-pasty", "predicate": "has_ingredient", "object": "ingredient:flour"} + ``` + +3. **Análisis de la respuesta** (`extract.py:382-428`) + Espera un array JSON: `[{"subject": "...", "predicate": "...", "object": "..."}]` + Valida contra un subconjunto de la ontología + Expande los URIs mediante `expand_uri()` (extract.py:473-521) + +4. **Expansión de URIs** (`extract.py:473-521`) + Comprueba si el valor está en el diccionario `ontology_subset.classes` + Si se encuentra, extrae el URI de la definición de la clase + Si no se encuentra, construye el URI: `f"https://trustgraph.ai/ontology/{ontology_id}#{value}"` + +### Ejemplo de flujo de datos + +**JSON de la ontología → Loader → Prompt:** +``` +"fo/Recipe" → classes["fo/Recipe"] → LLM sees "**fo/Recipe**" +``` + +**LLM → Analizador → Salida:** +``` +"Recipe" → not in classes["fo/Recipe"] → constructs URI → LOSES original URI +"fo/Recipe" → found in classes → uses original URI → PRESERVES URI +``` + +## Problemas Identificados + +### 1. **Ejemplos Inconsistentes en la Instrucción** + +**Problema**: La plantilla de la instrucción muestra ID de clase con prefijos (`fo/Recipe`) pero la salida de ejemplo utiliza nombres de clase sin prefijos (`Recipe`). + +**Ubicación**: `ontology-prompt.md:5-52` + +```markdown +## Ontology Classes: +- **fo/Recipe**: A Recipe is... + +## Example Output: +{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} +``` + +**Impacto**: El modelo de lenguaje (LLM) recibe señales contradictorias sobre qué formato utilizar. + +### 2. **Pérdida de información en la expansión de URI** + +**Problema**: Cuando el LLM devuelve nombres de clase sin prefijo, siguiendo el ejemplo, `expand_uri()` no puede encontrarlos en el diccionario de ontología y construye URI de respaldo, perdiendo los URI originales correctos. + +**Ubicación**: `extract.py:494-500` + +```python +if value in ontology_subset.classes: # Looks for "Recipe" + class_def = ontology_subset.classes[value] # But key is "fo/Recipe" + if isinstance(class_def, dict) and 'uri' in class_def: + return class_def['uri'] # Never reached! +return f"https://trustgraph.ai/ontology/{ontology_id}#{value}" # Fallback +``` + +**Impacto:** +URI original: `http://purl.org/ontology/fo/Recipe` +URI construido: `https://trustgraph.ai/ontology/food#Recipe` +Significado semántico perdido, interrumpe la interoperabilidad. + +### 3. **Formato ambiguo de instancia de entidad** + +**Problema:** No hay una guía clara sobre el formato de la URI de la instancia de entidad. + +**Ejemplos en la solicitud:** +`"recipe:cornish-pasty"` (prefijo similar a un espacio de nombres) +`"ingredient:flour"` (prefijo diferente) + +**Comportamiento real** (extract.py:517-520): +```python +# Treat as entity instance - construct unique URI +normalized = value.replace(" ", "-").lower() +return f"https://trustgraph.ai/{ontology_id}/{normalized}" +``` + +**Impacto**: El modelo de lenguaje debe adivinar la convención de prefijos sin contexto ontológico. + +### 4. **Sin Guía de Prefijos de Espacio de Nombres** + +**Problema**: El archivo JSON de la ontología contiene definiciones de espacios de nombres (líneas 10-25 en food.ontology): +```json +"namespaces": { + "fo": "http://purl.org/ontology/fo/", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + ... +} +``` + +Pero estas líneas nunca se muestran al LLM. El LLM no sabe: +Qué significa "fo" +Qué prefijo usar para las entidades +A qué espacio de nombres se aplica a qué elementos + +### 5. **Etiquetas No Utilizadas en el Prompt** + +**Problema**: Cada clase tiene campos `rdfs:label` (por ejemplo, `{"value": "Recipe", "lang": "en-gb"}`), pero la plantilla del prompt no los utiliza. + +**Actual**: Muestra solo `class_id` y `comment` +```jinja +- **{{class_id}}**{% if class_def.comment %}: {{class_def.comment}}{% endif %} +``` + +**Disponible pero no utilizado**: +```python +"rdfs:label": [{"value": "Recipe", "lang": "en-gb"}] +``` + +**Impacto**: Podría proporcionar nombres legibles por humanos junto con identificadores técnicos. + +## Soluciones propuestas + +### Opción A: Normalizar a identificadores sin prefijos + +**Enfoque**: Eliminar los prefijos de los identificadores de clase antes de mostrarlos al LLM. + +**Cambios**: +1. Modificar `build_extraction_variables()` para transformar las claves: + ```python + classes_for_prompt = { + k.split('/')[-1]: v # "fo/Recipe" → "Recipe" + for k, v in ontology_subset.classes.items() + } + ``` + +2. Actualizar el ejemplo de la instrucción para que coincida (ya utiliza nombres sin prefijos). + +3. Modificar `expand_uri()` para que gestione ambos formatos: + ```python + # Try exact match first + if value in ontology_subset.classes: + return ontology_subset.classes[value]['uri'] + + # Try with prefix + for prefix in ['fo/', 'rdf:', 'rdfs:']: + prefixed = f"{prefix}{value}" + if prefixed in ontology_subset.classes: + return ontology_subset.classes[prefixed]['uri'] + ``` + +**Ventajas:** +Más limpio, más legible para los humanos. +Coincide con ejemplos de prompts existentes. +Los LLM funcionan mejor con tokens más simples. + +**Desventajas:** +Colisiones de nombres de clase si múltiples ontologías tienen el mismo nombre de clase. +Pierde la información del espacio de nombres. +Requiere lógica de respaldo para las búsquedas. + +### Opción B: Utilizar IDs con Prefijos Completos de Forma Consistente + +**Enfoque:** Actualizar los ejemplos para utilizar IDs con prefijos que coincidan con lo que se muestra en la lista de clases. + +**Cambios:** +1. Actualizar el ejemplo del prompt (ontology-prompt.md:46-52): + ```json + [ + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "fo/Recipe"}, + {"subject": "recipe:cornish-pasty", "predicate": "rdfs:label", "object": "Cornish Pasty"}, + {"subject": "recipe:cornish-pasty", "predicate": "fo/produces", "object": "food:cornish-pasty"}, + {"subject": "food:cornish-pasty", "predicate": "rdf:type", "object": "fo/Food"} + ] + ``` + +2. Agregar una explicación del espacio de nombres a la instrucción: + ```markdown + ## Namespace Prefixes: + - **fo/**: Food Ontology (http://purl.org/ontology/fo/) + - **rdf:**: RDF Schema + - **rdfs:**: RDF Schema + + Use these prefixes exactly as shown when referencing classes and properties. + ``` + +3. Mantener `expand_uri()` tal cual (funciona correctamente cuando se encuentran coincidencias). + +**Ventajas**: +Consistencia entre entrada y salida. +Sin pérdida de información. +Preserva la semántica del espacio de nombres. +Funciona con múltiples ontologías. + +**Desventajas**: +Tokens más verbosos para el LLM. +Requiere que el LLM rastree los prefijos. + +### Opción C: Híbrida: Mostrar tanto la etiqueta como el ID. + +**Enfoque**: Mejorar el prompt para mostrar tanto las etiquetas legibles por humanos como los ID técnicos. + +**Cambios**: +1. Actualizar la plantilla del prompt: + ```jinja + {% for class_id, class_def in classes.items() %} + - **{{class_id}}** (label: "{{class_def.labels[0].value if class_def.labels else class_id}}"){% if class_def.comment %}: {{class_def.comment}}{% endif %} + {% endfor %} + ``` + + Ejemplo de salida: + ```markdown + - **fo/Recipe** (label: "Recipe"): A Recipe is a combination... + ``` + +2. Instrucciones de actualización: + ```markdown + When referencing classes: + - Use the full prefixed ID (e.g., "fo/Recipe") in JSON output + - The label (e.g., "Recipe") is for human understanding only + ``` + +**Ventajas**: +Más claro para los modelos de lenguaje (LLM). +Preserva toda la información. +Explícito sobre qué usar. + +**Desventajas**: +Requiere un prompt más largo. +Plantilla más compleja. + +## Enfoque Implementado + +**Formato Simplificado de Entidad-Relación-Atributo** - reemplaza completamente el formato basado en triples anterior. + +El nuevo enfoque se eligió porque: + +1. **Sin Pérdida de Información**: Los URI originales se conservan correctamente. +2. **Lógica Más Simple**: No se necesita transformación, las búsquedas directas en diccionarios funcionan. +3. **Seguridad de Espacios de Nombres**: Maneja múltiples ontologías sin colisiones. +4. **Corrección Semántica**: Mantiene la semántica RDF/OWL. + +## Implementación Completada + +### Lo que se Construyó: + +1. **Nueva Plantilla de Prompt** (`prompts/ontology-extract-v2.txt`) + ✅ Secciones claras: Tipos de Entidad, Relaciones, Atributos. + ✅ Ejemplo utilizando identificadores de tipo completos (`fo/Recipe`, `fo/has_ingredient`). + ✅ Instrucciones para usar los identificadores exactos del esquema. + ✅ Nuevo formato JSON con matrices de entidades/relaciones/atributos. + +2. **Normalización de Entidades** (`entity_normalizer.py`) + ✅ `normalize_entity_name()` - Convierte los nombres a un formato seguro para URI. + ✅ `normalize_type_identifier()` - Maneja las barras diagonales en los tipos (`fo/Recipe` → `fo-recipe`). + ✅ `build_entity_uri()` - Crea URI únicos utilizando la tupla (nombre, tipo). + ✅ `EntityRegistry` - Realiza un seguimiento de las entidades para la eliminación de duplicados. + +3. **Analizador JSON** (`simplified_parser.py`) + ✅ Analiza el nuevo formato: `{entities: [...], relationships: [...], attributes: [...]}` + ✅ Admite nombres de campo en formato kebab-case y snake_case. + ✅ Devuelve clases de datos estructuradas. + ✅ Manejo de errores con registro. + +4. **Convertidor de Triples** (`triple_converter.py`) + ✅ `convert_entity()` - Genera automáticamente triples de tipo + etiqueta. + ✅ `convert_relationship()` - Conecta los URI de las entidades a través de propiedades. + ✅ `convert_attribute()` - Agrega valores literales. + ✅ Busca URI completos a partir de las definiciones de la ontología. + +5. **Procesador Principal Actualizado** (`extract.py`) + ✅ Se eliminó el código antiguo de extracción basado en triples. + ✅ Se agregó el método `extract_with_simplified_format()`. + ✅ Ahora utiliza exclusivamente el nuevo formato simplificado. + ✅ Llama al indicador con el ID `extract-with-ontologies-v2`. + +## Casos de Prueba + +### Prueba 1: Preservación de URI +```python +# Given ontology class +classes = {"fo/Recipe": {"uri": "http://purl.org/ontology/fo/Recipe", ...}} + +# When LLM returns +llm_output = {"subject": "x", "predicate": "rdf:type", "object": "fo/Recipe"} + +# Then expanded URI should be +assert expanded == "http://purl.org/ontology/fo/Recipe" +# Not: "https://trustgraph.ai/ontology/food#Recipe" +``` + +### Prueba 2: Colisión Multi-Ontología +```python +# Given two ontologies +ont1 = {"fo/Recipe": {...}} +ont2 = {"cooking/Recipe": {...}} + +# LLM should use full prefix to disambiguate +llm_output = {"object": "fo/Recipe"} # Not just "Recipe" +``` + +### Prueba 3: Formato de Instancia de Entidad +```python +# Given prompt with food ontology +# LLM should create instances like +{"subject": "recipe:cornish-pasty"} # Namespace-style +{"subject": "food:beef"} # Consistent prefix +``` + +## Preguntas Abiertas + +1. **¿Deben las instancias de entidades usar prefijos de espacio de nombres?** + Actual: `"recipe:cornish-pasty"` (arbitrario) + Alternativa: ¿Usar prefijo de ontología `"fo:cornish-pasty"`? + Alternativa: Sin prefijo, expandir en URI `"cornish-pasty"` → URI completa? + +2. **¿Cómo manejar el dominio/rango en el prompt?** + Actualmente muestra: `(Recipe → Food)` + ¿Debería ser: `(fo/Recipe → fo/Food)`? + +3. **¿Debemos validar las restricciones de dominio/rango?** + TODO comentario en extract.py:470 + Detectaría más errores pero sería más complejo + +4. **¿Qué tal las propiedades inversas y las equivalencias?** + La ontología tiene `owl:inverseOf`, `owl:equivalentClass` + Actualmente no se utilizan en la extracción + ¿Deberían usarse? + +## Métricas de Éxito + +✅ Pérdida de información de URI cero (100% de preservación de los URI originales) +✅ El formato de salida del LLM coincide con el formato de entrada +✅ No hay ejemplos ambiguos en el prompt +✅ Las pruebas pasan con múltiples ontologías +✅ Calidad de extracción mejorada (medida por el porcentaje de triples válidos) + +## Enfoque Alternativo: Formato de Extracción Simplificado + +### Filosofía + +En lugar de pedirle al LLM que comprenda la semántica de RDF/OWL, pídele que haga lo que hace bien: **encontrar entidades y relaciones en el texto**. + +Deje que el código se encargue de la construcción de URI, la conversión de RDF y las formalidades de la web semántica. + +### Ejemplo: Clasificación de Entidades + +**Texto de entrada:** +``` +Cornish pasty is a traditional British pastry filled with meat and vegetables. +``` + +**Esquema de Ontología (mostrado al LLM):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food +``` + +**Lo que el LLM devuelve (JSON simple):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + } + ] +} +``` + +**¿Qué código produce (triples RDF):** +```python +# 1. Normalize entity name + type to ID (type prevents collisions) +entity_id = "recipe-cornish-pasty" # normalize("Cornish pasty", "Recipe") +entity_uri = "https://trustgraph.ai/food/recipe-cornish-pasty" + +# Note: Same name, different type = different URI +# "Cornish pasty" (Recipe) → recipe-cornish-pasty +# "Cornish pasty" (Food) → food-cornish-pasty + +# 2. Generate triples +triples = [ + # Type triple + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/1999/02/22-rdf-syntax-ns#type", is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + # Label triple (automatic) + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/2000/01/rdf-schema#label", is_uri=True), + o=Value(value="Cornish pasty", is_uri=False) + ) +] +``` + +### Beneficios + +1. **El LLM no necesita:** + Entender la sintaxis de URI + Inventar prefijos de identificadores (`recipe:`, `ingredient:`) + Conocer `rdf:type` o `rdfs:label` + Construir identificadores de la web semántica + +2. **El LLM solo necesita:** + Encontrar entidades en el texto + Mapearlas a clases de ontología + Extraer relaciones y atributos + +3. **El código se encarga de:** + Normalización y construcción de URI + Generación de triples RDF + Asignación automática de etiquetas + Gestión de espacios de nombres + +### ¿Por qué esto funciona mejor? + +**Indicación más simple** = menos confusión = menos errores +**IDs consistentes** = el código controla las reglas de normalización +**Etiquetas generadas automáticamente** = no faltan triples rdfs:label +**El LLM se centra en la extracción** = en lo que realmente es bueno + +### Ejemplo: Relaciones de Entidades + +**Texto de entrada:** +``` +Cornish pasty is a traditional British pastry filled with beef and potatoes. +``` + +**Esquema de Ontología (mostrado al LLM):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food + +## Relationships: +- has_ingredient: Relates a recipe to an ingredient it uses (Recipe → Ingredient) +- food: Relates an ingredient to the food that is required (Ingredient → Food) +``` + +**Lo que el LLM devuelve (JSON simple):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ] +} +``` + +**¿Qué código produce (triples RDF):** +```python +# Normalize entity names to URIs +cornish_pasty_uri = "https://trustgraph.ai/food/cornish-pasty" +beef_uri = "https://trustgraph.ai/food/beef" +potatoes_uri = "https://trustgraph.ai/food/potatoes" + +# Look up relation URI from ontology +has_ingredient_uri = "http://purl.org/ontology/fo/ingredients" # from fo/has_ingredient + +triples = [ + # Entity type triples (as before) + Triple(s=cornish_pasty_uri, p=rdf_type, o="http://purl.org/ontology/fo/Recipe"), + Triple(s=cornish_pasty_uri, p=rdfs_label, o="Cornish pasty"), + + Triple(s=beef_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=beef_uri, p=rdfs_label, o="beef"), + + Triple(s=potatoes_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=potatoes_uri, p=rdfs_label, o="potatoes"), + + # Relationship triples + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=beef_uri, is_uri=True) + ), + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=potatoes_uri, is_uri=True) + ) +] +``` + +**Puntos clave:** +El modelo de lenguaje (LLM) devuelve nombres de entidades en lenguaje natural: `"Cornish pasty"`, `"beef"`, `"potatoes"` +El LLM incluye tipos para disambiguar: `subject-type`, `object-type` +El LLM utiliza el nombre de la relación del esquema: `"has_ingredient"` +El código deriva IDs consistentes utilizando (nombre, tipo): `("Cornish pasty", "Recipe")` → `recipe-cornish-pasty` +El código busca el URI de la relación en la ontología: `fo/has_ingredient` → URI completo +La misma tupla (nombre, tipo) siempre obtiene el mismo URI (desduplicación) + +### Ejemplo: Disambiguación del nombre de la entidad + +**Problema:** El mismo nombre puede referirse a diferentes tipos de entidad. + +**Caso real:** +``` +"Cornish pasty" can be: +- A Recipe (instructions for making it) +- A Food (the dish itself) +``` + +**Cómo se gestiona:** + +El modelo de lenguaje grande (LLM) devuelve ambos como entidades separadas: +```json +{ + "entities": [ + {"entity": "Cornish pasty", "type": "Recipe"}, + {"entity": "Cornish pasty", "type": "Food"} + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "produces", + "object": "Cornish pasty", + "object-type": "Food" + } + ] +} +``` + +**Resolución de código:** +```python +# Different types → different URIs +recipe_uri = normalize("Cornish pasty", "Recipe") +# → "https://trustgraph.ai/food/recipe-cornish-pasty" + +food_uri = normalize("Cornish pasty", "Food") +# → "https://trustgraph.ai/food/food-cornish-pasty" + +# Relationship connects them correctly +triple = Triple( + s=recipe_uri, # The Recipe + p="http://purl.org/ontology/fo/produces", + o=food_uri # The Food +) +``` + +**¿Por qué funciona esto?:** +El tipo se incluye en TODAS las referencias (entidades, relaciones, atributos). +El código utiliza la tupla `(name, type)` como clave de búsqueda. +No hay ambigüedad, no hay colisiones. + +### Ejemplo: Atributos de Entidad + +**Texto de entrada:** +``` +This Cornish pasty recipe serves 4-6 people and takes 45 minutes to prepare. +``` + +**Esquema de Ontología (mostrado al LLM):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method + +## Attributes: +- serves: Indicates what the recipe is intended to serve (Recipe → text) +- preparation_time: Time needed to prepare the recipe (Recipe → text) +``` + +**Lo que el LLM devuelve (JSON simple):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty recipe", + "type": "Recipe" + } + ], + "attributes": [ + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4-6 people" + }, + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "preparation_time", + "value": "45 minutes" + } + ] +} +``` + +**¿Qué código produce (triples RDF):** +```python +# Normalize entity name to URI +recipe_uri = "https://trustgraph.ai/food/cornish-pasty-recipe" + +# Look up attribute URIs from ontology +serves_uri = "http://purl.org/ontology/fo/serves" # from fo/serves +prep_time_uri = "http://purl.org/ontology/fo/preparation_time" # from fo/preparation_time + +triples = [ + # Entity type triple + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdf_type, is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + + # Label triple (automatic) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdfs_label, is_uri=True), + o=Value(value="Cornish pasty recipe", is_uri=False) + ), + + # Attribute triples (objects are literals, not URIs) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=serves_uri, is_uri=True), + o=Value(value="4-6 people", is_uri=False) # Literal value! + ), + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=prep_time_uri, is_uri=True), + o=Value(value="45 minutes", is_uri=False) # Literal value! + ) +] +``` + +**Puntos Clave:** +El LLM extrae valores literales: `"4-6 people"`, `"45 minutes"` +El LLM incluye el tipo de entidad para la desambiguación: `entity-type` +El LLM utiliza el nombre del atributo del esquema: `"serves"`, `"preparation_time"` +El código busca el URI del atributo de las propiedades del tipo de datos de la ontología +**El objeto es literal** (`is_uri=False`), no una referencia de URI +Los valores permanecen como texto natural, no se necesita normalización + +**Diferencia con las Relaciones:** +Relaciones: tanto el sujeto como el objeto son entidades (URIs) +Atributos: el sujeto es una entidad (URI), el objeto es un valor literal (cadena/número) + +### Ejemplo Completo: Entidades + Relaciones + Atributos + +**Texto de Entrada:** +``` +Cornish pasty is a savory pastry filled with beef and potatoes. +This recipe serves 4 people. +``` + +**Lo que el LLM devuelve:** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ], + "attributes": [ + { + "entity": "Cornish pasty", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4 people" + } + ] +} +``` + +**Resultado:** Se generaron 11 triples RDF: +3 triples de tipo de entidad (rdf:type) +3 triples de etiqueta de entidad (rdfs:label) - automático +2 triples de relación (has_ingredient) +1 triple de atributo (serves) + +¡Todo proviene de extracciones simples y en lenguaje natural realizadas por el LLM! + +## Referencias + +Implementación actual: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` +Plantilla de prompt: `ontology-prompt.md` +Casos de prueba: `tests/unit/test_extract/test_ontology/` +Ontología de ejemplo: `e2e/test-data/food.ontology` diff --git a/docs/tech-specs/ontology-extract-phase-2.he.md b/docs/tech-specs/ontology-extract-phase-2.he.md new file mode 100644 index 00000000..a407b5be --- /dev/null +++ b/docs/tech-specs/ontology-extract-phase-2.he.md @@ -0,0 +1,761 @@ +# חילוץ ידע מתוך אונטולוגיות - שלב 2, שיפור מחדש + +**סטטוס**: טיוטה +**מחבר**: מפגש ניתוח 2025-12-03 +**קשור**: `ontology.md`, `ontorag.md` + +## סקירה כללית + +מסמך זה מזהה אי-התאמות במערכת הנוכחית לחילוץ ידע המבוססת על אונטולוגיות, ומציע שיפור מחדש כדי לשפר את הביצועים של מודלי שפה גדולים (LLM) ולהפחית אובדן מידע. + +## יישום נוכחי + +### איך זה עובד כרגע + +1. **טעינת אונטולוגיה** (`ontology_loader.py`) + טוען קובץ JSON של אונטולוגיה עם מפתחות כמו `"fo/Recipe"`, `"fo/Food"`, `"fo/produces"` + מזהי מחלקות כוללים את הקידומת של מרחב השמות במפתח עצמו + דוגמה מ-`food.ontology`: + ```json + "classes": { + "fo/Recipe": { + "uri": "http://purl.org/ontology/fo/Recipe", + "rdfs:comment": "A Recipe is a combination..." + } + } + ``` + +2. **בניית הנחיה** (`extract.py:299-307`, `ontology-prompt.md`) + התבנית מקבלת מילונים `classes`, `object_properties`, `datatype_properties` + התבנית חוזרת: `{% for class_id, class_def in classes.items() %}` + מודל השפה (LLM) רואה: `**fo/Recipe**: A Recipe is a combination...` + פורמט פלט לדוגמה מציג: + ```json + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} + {"subject": "recipe:cornish-pasty", "predicate": "has_ingredient", "object": "ingredient:flour"} + ``` + +3. **ניתוח תגובה** (`extract.py:382-428`) + מצפה למערך JSON: `[{"subject": "...", "predicate": "...", "object": "..."}]` + מאמת מול תת-אונטולוגיה + מרחיב URI באמצעות `expand_uri()` (extract.py:473-521) + +4. **הרחבת URI** (`extract.py:473-521`) + בודק אם הערך נמצא במילון `ontology_subset.classes` + אם נמצא, מחלץ את ה-URI מההגדרה של המחלקה + אם לא נמצא, בונה את ה-URI: `f"https://trustgraph.ai/ontology/{ontology_id}#{value}"` + +### דוגמה לזרימת נתונים + +**JSON של אונטולוגיה → Loader → Prompt:** +``` +"fo/Recipe" → classes["fo/Recipe"] → LLM sees "**fo/Recipe**" +``` + +**מודל שפה גדול → מנתח → פלט:** +``` +"Recipe" → not in classes["fo/Recipe"] → constructs URI → LOSES original URI +"fo/Recipe" → found in classes → uses original URI → PRESERVES URI +``` + +## בעיות שזוהו + +### 1. **דוגמאות לא עקביות בהנחיה** + +**בעיה**: תבנית ההנחיה מציגה מזהי מחלקות עם קידומות (`fo/Recipe`) אך הפלט לדוגמה משתמש בשמות מחלקות ללא קידומות (`Recipe`). + +**מיקום**: `ontology-prompt.md:5-52` + +```markdown +## Ontology Classes: +- **fo/Recipe**: A Recipe is... + +## Example Output: +{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} +``` + +**השפעה**: מודל השפה הגדול (LLM) מקבל אותות סותרים לגבי הפורמט שיש להשתמש בו. + +### 2. **אובדן מידע בהרחבת כתובות URL** + +**בעיה**: כאשר מודל השפה הגדול (LLM) מחזיר שמות מחלקות ללא קידומת, בהתאם לדוגמה, `expand_uri()` לא יכול למצוא אותם במילון האונטולוגיה ויוצר כתובות URL חלופיות, ובכך מאבד את כתובות ה-URL המקוריות הנכונות. + +**מיקום**: `extract.py:494-500` + +```python +if value in ontology_subset.classes: # Looks for "Recipe" + class_def = ontology_subset.classes[value] # But key is "fo/Recipe" + if isinstance(class_def, dict) and 'uri' in class_def: + return class_def['uri'] # Never reached! +return f"https://trustgraph.ai/ontology/{ontology_id}#{value}" # Fallback +``` + +**השפעה:** +URI מקורי: `http://purl.org/ontology/fo/Recipe` +URI שנוצר: `https://trustgraph.ai/ontology/food#Recipe` +אובדן משמעות סמנטית, פוגע בתאימות. + +### 3. **פורמט לא ברור של מופעי ישויות** + +**בעיה:** אין הנחיות ברורות לגבי פורמט ה-URI של מופעי ישויות. + +**דוגמאות בהנחיה:** +`"recipe:cornish-pasty"` (קידומת הדומה לשם מרחב) +`"ingredient:flour"` (קידומת שונה) + +**התנהגות בפועל** (extract.py:517-520): +```python +# Treat as entity instance - construct unique URI +normalized = value.replace(" ", "-").lower() +return f"https://trustgraph.ai/{ontology_id}/{normalized}" +``` + +**השפעה**: מודל שפה גדול (LLM) חייב לנחש את מוסכמות הקידומת ללא הקשר אונטולוגי. + +### 4. **הנחיות לגבי קידומות מרחבי שמות חסרות** + +**בעיה**: קובץ ה-JSON של האונטולוגיה מכיל הגדרות מרחבי שמות (שורות 10-25 בקובץ food.ontology): +```json +"namespaces": { + "fo": "http://purl.org/ontology/fo/", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + ... +} +``` + +אבל השורות האלה לעולם אינן מוצגות למודל השפה הגדול (LLM). מודל השפה הגדול אינו יודע: +מה המשמעות של "fo" +איזה קידומת להשתמש עבור ישויות +לאיזה מרחב שם מתייחס כל אלמנט + +### 5. **תוויות שאינן משמשות בפרומפט** + +**בעיה**: לכל מחלקה יש שדות `rdfs:label` (לדוגמה, `{"value": "Recipe", "lang": "en-gb"}`), אבל תבנית הפרומפט אינה משתמשת בהם. + +**מצב נוכחי**: מציג רק `class_id` ו-`comment` +```jinja +- **{{class_id}}**{% if class_def.comment %}: {{class_def.comment}}{% endif %} +``` + +**זמין אך לא בשימוש:** +```python +"rdfs:label": [{"value": "Recipe", "lang": "en-gb"}] +``` + +**השפעה:** יכול לספק שמות קריאים לבני אדם לצד מזהים טכניים. + +## פתרונות מוצעים + +### אפשרות א': נרמול למזהים ללא קידומת + +**גישה:** הסרת קידומות ממזהי מחלקות לפני הצגתם למודל LLM. + +**שינויים:** +1. שנה את `build_extraction_variables()` כדי לשנות מפתחות: + ```python + classes_for_prompt = { + k.split('/')[-1]: v # "fo/Recipe" → "Recipe" + for k, v in ontology_subset.classes.items() + } + ``` + +2. עדכון דוגמת ההנחיה כך שתתאים (כבר משתמשת בשמות ללא קידומת). + +3. שינוי `expand_uri()` כדי לטפל בשני הפורמטים: + ```python + # Try exact match first + if value in ontology_subset.classes: + return ontology_subset.classes[value]['uri'] + + # Try with prefix + for prefix in ['fo/', 'rdf:', 'rdfs:']: + prefixed = f"{prefix}{value}" + if prefixed in ontology_subset.classes: + return ontology_subset.classes[prefixed]['uri'] + ``` + +**יתרונות:** +נקי יותר, קריא יותר לבני אדם +תואם לדוגמאות קיימות של הנחיות +מודלי שפה גדולים (LLMs) עובדים טוב יותר עם טוקנים פשוטים יותר + +**חסרונות:** +התנגשויות בשמות מחלקות אם למספר אונטולוגיות יש אותו שם מחלקה +מאבד מידע על מרחב השמות +דורש לוגיקה חלופית עבור חיפושים + +### אפשרות ב': שימוש עקבי במזהים עם קידומת מלאה + +**גישה:** עדכון הדוגמאות לשימוש במזהים עם קידומת התואמים למה שמוצג ברשימת המחלקות. + +**שינויים:** +1. עדכון דוגמת הנחיה (ontology-prompt.md:46-52): + ```json + [ + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "fo/Recipe"}, + {"subject": "recipe:cornish-pasty", "predicate": "rdfs:label", "object": "Cornish Pasty"}, + {"subject": "recipe:cornish-pasty", "predicate": "fo/produces", "object": "food:cornish-pasty"}, + {"subject": "food:cornish-pasty", "predicate": "rdf:type", "object": "fo/Food"} + ] + ``` + +2. הוספת הסבר על מרחב הnamespaces להנחיה: + ```markdown + ## Namespace Prefixes: + - **fo/**: Food Ontology (http://purl.org/ontology/fo/) + - **rdf:**: RDF Schema + - **rdfs:**: RDF Schema + + Use these prefixes exactly as shown when referencing classes and properties. + ``` + +3. שמרו על `expand_uri()` כפי שהוא (עובד כראוי כאשר נמצאו התאמות). + +**יתרונות:** +עקביות בין קלט לפלט. +ללא אובדן מידע. +שומר על סמנטיקת מרחבי השמות. +עובד עם מרובות אונטולוגיות. + +**חסרונות:** +טוקנים מילוליים יותר עבור מודל שפה גדול (LLM). +דורש ממודל השפה הגדול (LLM) לעקוב אחר קידומות. + +### אפשרות ג': היברידית - הצגת תווית ומזהה כאחד. + +**גישה:** שיפור ההנחיה להצגת תוויות קריאות אנוש ומזהים טכניים. + +**שינויים:** +1. עדכון תבנית ההנחיה: + ```jinja + {% for class_id, class_def in classes.items() %} + - **{{class_id}}** (label: "{{class_def.labels[0].value if class_def.labels else class_id}}"){% if class_def.comment %}: {{class_def.comment}}{% endif %} + {% endfor %} + ``` + + פלט לדוגמה: + ```markdown + - **fo/Recipe** (label: "Recipe"): A Recipe is a combination... + ``` + +2. הוראות עדכון: + ```markdown + When referencing classes: + - Use the full prefixed ID (e.g., "fo/Recipe") in JSON output + - The label (e.g., "Recipe") is for human understanding only + ``` + +**יתרונות:** +הבהרה עבור מודלי שפה גדולים (LLM) +שומר על כל המידע +מפרט במפורש מה להשתמש + +**חסרונות:** +הנחיה ארוכה יותר +תבנית מורכבת יותר + +## גישה מיושמת + +**פורמט פשוט של ישות-קשר-תכונה** - מחליף לחלוטין את הפורמט המבוסס על שלישיות הישן. + +הגישה החדשה נבחרה מכיוון: + +1. **ללא אובדן מידע:** כתובות URI מקוריות נשמרות כהלכה +2. **לוגיקה פשוטה יותר:** אין צורך בטרנספורמציה, חיפושים ישירים במילון עובדים +3. **בטיחות מרחבי שמות:** מטפל במספר אונטולוגיות ללא התנגשויות +4. **נכונות סמנטית:** שומר על סמנטיקה של RDF/OWL + +## יישום הושלם + +### מה נבנה: + +1. **תבנית הנחיה חדשה** (`prompts/ontology-extract-v2.txt`) + ✅ חלקים ברורים: סוגי ישויות, קשרים, תכונות + ✅ דוגמה תוך שימוש במזהים מלאים של סוגים (`fo/Recipe`, `fo/has_ingredient`) + ✅ הוראות לשימוש במזהים מדויקים מהסכימה + ✅ פורמט JSON חדש עם מערכים של ישויות/קשרים/תכונות + +2. **נרמול ישויות** (`entity_normalizer.py`) + ✅ `normalize_entity_name()` - ממיר שמות לפורמט בטוח ל-URI + ✅ `normalize_type_identifier()` - מטפל בסלאשים בסוגים (`fo/Recipe` → `fo-recipe`) + ✅ `build_entity_uri()` - יוצר כתובות URI ייחודיות באמצעות טאפל (שם, סוג) + ✅ `EntityRegistry` - עוקב אחר ישויות לצורך הסרה כפולה + +3. **מנתח JSON** (`simplified_parser.py`) + ✅ מנתח את הפורמט החדש: `{entities: [...], relationships: [...], attributes: [...]}` + ✅ תומך בשמות שדות בפורמט kebab-case ו-snake_case + ✅ מחזיר מחלקות נתונים מובנות + ✅ טיפול בשגיאות בצורה חלקה עם רישום + +4. **ממיר שלישיות** (`triple_converter.py`) + ✅ `convert_entity()` - מייצר באופן אוטומטי שלישיות של סוג + תווית + ✅ `convert_relationship()` - מחבר כתובות URI של ישויות באמצעות מאפיינים + ✅ `convert_attribute()` - מוסיף ערכים מילוליים + ✅ מחפש כתובות URI מלאות מהגדרות האונטולוגיה + +5. **מעבד ראשי מעודכן** (`extract.py`) + ✅ הסר קוד חילוץ ישן מבוסס על שלישיות + ✅ הוסף שיטה `extract_with_simplified_format()` + ✅ משתמש כעת אך ורק בפורמט הפשוט החדש + ✅ קורא להנחיה עם מזהה `extract-with-ontologies-v2` + +## מקרי בדיקה + +### בדיקה 1: שימור כתובות URI +```python +# Given ontology class +classes = {"fo/Recipe": {"uri": "http://purl.org/ontology/fo/Recipe", ...}} + +# When LLM returns +llm_output = {"subject": "x", "predicate": "rdf:type", "object": "fo/Recipe"} + +# Then expanded URI should be +assert expanded == "http://purl.org/ontology/fo/Recipe" +# Not: "https://trustgraph.ai/ontology/food#Recipe" +``` + +### מבחן 2: התנגשות בין מרובי אונטולוגיות +```python +# Given two ontologies +ont1 = {"fo/Recipe": {...}} +ont2 = {"cooking/Recipe": {...}} + +# LLM should use full prefix to disambiguate +llm_output = {"object": "fo/Recipe"} # Not just "Recipe" +``` + +### מבחן 3: פורמט של מופע ישות +```python +# Given prompt with food ontology +# LLM should create instances like +{"subject": "recipe:cornish-pasty"} # Namespace-style +{"subject": "food:beef"} # Consistent prefix +``` + +## שאלות פתוחות + +1. **האם יש להשתמש בתוספות מרחב שם עבור מופעי ישויות?** + נוכחי: `"recipe:cornish-pasty"` (שרירותי) + חלופה: להשתמש בתוסף אוֹנוֹטוֹלוֹגיה `"fo:cornish-pasty"`? + חלופה: ללא תוסף, להרחיב ב-URI `"cornish-pasty"` → URI מלא? + +2. **כיצד לטפל בתחום/טווח בפרומפט?** + מוצג כעת: `(Recipe → Food)` + האם זה צריך להיות: `(fo/Recipe → fo/Food)`? + +3. **האם עלינו לאמת אילוצי תחום/טווח?** + הערה TODO ב-extract.py:470 + יתפוס יותר שגיאות אך מורכב יותר + +4. **מה לגבי תכונות הפוכות ושקילות?** + לאוֹנוֹטוֹלוֹגיה יש `owl:inverseOf`, `owl:equivalentClass` + לא בשימוש כרגע בחילוץ + האם הם צריכים להיות בשימוש? + +## מדדי הצלחה + +✅ אפס אובדן מידע URI (שימור של 100% מה-URIs המקוריים) +✅ פורמט הפלט של ה-LLM תואם לפורמט הקלט +✅ אין דוגמאות מעורפלות בפרומפט +✅ הבדיקות עוברות עם אוֹנוֹטוֹלוֹגיות מרובות +✅ שיפור באיכות החילוץ (נמדד על ידי אחוז משולשות חוקיות) + +## גישה חלופית: פורמט חילוץ מפושט + +### פילוסופיה + +במקום לבקש מה-LLM להבין סמנטיקה של RDF/OWL, לבקש ממנו לעשות את מה שהוא טוב בו: **למצוא ישויות ויחסים בטקסט**. + +תן לקוד לטפל בבניית URI, המרת RDF ופורמליות של רשת סמנטית. + +### דוגמה: סיווג ישויות + +**טקסט קלט:** +``` +Cornish pasty is a traditional British pastry filled with meat and vegetables. +``` + +**סכימת אונטולוגיה (מוצגת למודל שפה גדול):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food +``` + +**מה שהמודל השפה הגדול מחזיר (JSON פשוט):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + } + ] +} +``` + +**מה הקוד מייצר (משולשי RDF):** +```python +# 1. Normalize entity name + type to ID (type prevents collisions) +entity_id = "recipe-cornish-pasty" # normalize("Cornish pasty", "Recipe") +entity_uri = "https://trustgraph.ai/food/recipe-cornish-pasty" + +# Note: Same name, different type = different URI +# "Cornish pasty" (Recipe) → recipe-cornish-pasty +# "Cornish pasty" (Food) → food-cornish-pasty + +# 2. Generate triples +triples = [ + # Type triple + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/1999/02/22-rdf-syntax-ns#type", is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + # Label triple (automatic) + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/2000/01/rdf-schema#label", is_uri=True), + o=Value(value="Cornish pasty", is_uri=False) + ) +] +``` + +### יתרונות + +1. **מודל שפה גדול (LLM) לא צריך:** + להבין תחביר URI + להמציא קידומות מזהות (`recipe:`, `ingredient:`) + לדעת על `rdf:type` או `rdfs:label` + לבנות מזהי רשת סמנטית + +2. **מודל שפה גדול (LLM) צריך רק:** + למצוא ישויות בטקסט + למפות אותן למחלקות אונטולוגיה + לחלץ קשרים ומאפיינים + +3. **הקוד מטפל ב:** + נרמול ובניית URI + יצירת משולשות RDF + הקצאת תוויות אוטומטית + ניהול מרחבי שמות + +### למה זה עובד טוב יותר + +**שאילתה פשוטה יותר** = פחות בלבול = פחות שגיאות +**מזהים עקביים** = הקוד שולט בכללי הנרמול +**תוויות שנוצרו אוטומטית** = אין משולשות rdfs:label חסרות +**מודל שפה גדול מתמקד בחילוץ** = במה שהוא באמת טוב + +### דוגמה: קשרי ישויות + +**טקסט קלט:** +``` +Cornish pasty is a traditional British pastry filled with beef and potatoes. +``` + +**סכימת אונטולוגיה (מוצגת למודל שפה גדול):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food + +## Relationships: +- has_ingredient: Relates a recipe to an ingredient it uses (Recipe → Ingredient) +- food: Relates an ingredient to the food that is required (Ingredient → Food) +``` + +**מה שהמודל השפה הגדול מחזיר (JSON פשוט):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ] +} +``` + +**מה הקוד מייצר (משולשי RDF):** +```python +# Normalize entity names to URIs +cornish_pasty_uri = "https://trustgraph.ai/food/cornish-pasty" +beef_uri = "https://trustgraph.ai/food/beef" +potatoes_uri = "https://trustgraph.ai/food/potatoes" + +# Look up relation URI from ontology +has_ingredient_uri = "http://purl.org/ontology/fo/ingredients" # from fo/has_ingredient + +triples = [ + # Entity type triples (as before) + Triple(s=cornish_pasty_uri, p=rdf_type, o="http://purl.org/ontology/fo/Recipe"), + Triple(s=cornish_pasty_uri, p=rdfs_label, o="Cornish pasty"), + + Triple(s=beef_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=beef_uri, p=rdfs_label, o="beef"), + + Triple(s=potatoes_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=potatoes_uri, p=rdfs_label, o="potatoes"), + + # Relationship triples + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=beef_uri, is_uri=True) + ), + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=potatoes_uri, is_uri=True) + ) +] +``` + +**נקודות עיקריות:** +מודל שפה גדול (LLM) מחזיר שמות של ישויות בשפה טבעית: `"Cornish pasty"`, `"beef"`, `"potatoes"` +מודל שפה גדול (LLM) כולל סוגים כדי להבהיר: `subject-type`, `object-type` +מודל שפה גדול (LLM) משתמש בשם היחס מהסכימה: `"has_ingredient"` +הקוד מייצר מזהים עקביים באמצעות (שם, סוג): `("Cornish pasty", "Recipe")` → `recipe-cornish-pasty` +הקוד מחפש את ה-URI של היחס מהאונטולוגיה: `fo/has_ingredient` → URI מלא +אותה טופל (שם, סוג) תמיד מקבל את אותו ה-URI (הסרה כפילות) + +### דוגמה: הבחנה בין שמות של ישויות + +**בעיה:** אותו שם יכול להתייחס לסוגי ישויות שונים. + +**מקרה אמיתי:** +``` +"Cornish pasty" can be: +- A Recipe (instructions for making it) +- A Food (the dish itself) +``` + +**כיצד זה מטופל:** + +מודל שפה גדול (LLM) מחזיר את שניהם כיחידות נפרדות: +```json +{ + "entities": [ + {"entity": "Cornish pasty", "type": "Recipe"}, + {"entity": "Cornish pasty", "type": "Food"} + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "produces", + "object": "Cornish pasty", + "object-type": "Food" + } + ] +} +``` + +**פתרון קוד:** +```python +# Different types → different URIs +recipe_uri = normalize("Cornish pasty", "Recipe") +# → "https://trustgraph.ai/food/recipe-cornish-pasty" + +food_uri = normalize("Cornish pasty", "Food") +# → "https://trustgraph.ai/food/food-cornish-pasty" + +# Relationship connects them correctly +triple = Triple( + s=recipe_uri, # The Recipe + p="http://purl.org/ontology/fo/produces", + o=food_uri # The Food +) +``` + +**מדוע זה עובד:** +הסוג כלול בכל ההפניות (ישויות, קשרים, תכונות) +הקוד משתמש בטופל `(name, type)` כמפתח חיפוש +אין דו-משמעות, אין התנגשויות + +### דוגמה: תכונות של ישויות + +**טקסט קלט:** +``` +This Cornish pasty recipe serves 4-6 people and takes 45 minutes to prepare. +``` + +**סכימת אונטולוגיה (מוצגת למודל שפה גדול):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method + +## Attributes: +- serves: Indicates what the recipe is intended to serve (Recipe → text) +- preparation_time: Time needed to prepare the recipe (Recipe → text) +``` + +**מה שהמודל השפה הגדול מחזיר (JSON פשוט):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty recipe", + "type": "Recipe" + } + ], + "attributes": [ + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4-6 people" + }, + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "preparation_time", + "value": "45 minutes" + } + ] +} +``` + +**מה הקוד מייצר (משולשים RDF):** +```python +# Normalize entity name to URI +recipe_uri = "https://trustgraph.ai/food/cornish-pasty-recipe" + +# Look up attribute URIs from ontology +serves_uri = "http://purl.org/ontology/fo/serves" # from fo/serves +prep_time_uri = "http://purl.org/ontology/fo/preparation_time" # from fo/preparation_time + +triples = [ + # Entity type triple + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdf_type, is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + + # Label triple (automatic) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdfs_label, is_uri=True), + o=Value(value="Cornish pasty recipe", is_uri=False) + ), + + # Attribute triples (objects are literals, not URIs) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=serves_uri, is_uri=True), + o=Value(value="4-6 people", is_uri=False) # Literal value! + ), + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=prep_time_uri, is_uri=True), + o=Value(value="45 minutes", is_uri=False) # Literal value! + ) +] +``` + +**נקודות עיקריות:** +מודל שפה גדול (LLM) מחלץ ערכים מילוליים: `"4-6 people"`, `"45 minutes"` +מודל שפה גדול (LLM) כולל סוג ישות לצורך הבחנה: `entity-type` +מודל שפה גדול (LLM) משתמש בשם תכונה מהסכימה: `"serves"`, `"preparation_time"` +הקוד מחפש את ה-URI של התכונה ממאפייני סוג הנתונים של האונטולוגיה +**האובייקט הוא מילולי** (`is_uri=False`), ולא הפניה ל-URI +הערכים נשארים כטקסט רגיל, אין צורך בנרמול + +**ההבדל מיחסים:** +יחסים: גם הנושא וגם האובייקט הם ישויות (URIs) +תכונות: הנושא הוא ישות (URI), האובייקט הוא ערך מילולי (מחרוזת/מספר) + +### דוגמה מלאה: ישויות + יחסים + תכונות + +**טקסט קלט:** +``` +Cornish pasty is a savory pastry filled with beef and potatoes. +This recipe serves 4 people. +``` + +**מה מודל שפה גדול מחזיר:** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ], + "attributes": [ + { + "entity": "Cornish pasty", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4 people" + } + ] +} +``` + +**תוצאה:** נוצרו 11 משולשים של RDF: +3 משולשים מסוג ישות (rdf:type) +3 משולשים של תווית ישות (rdfs:label) - אוטומטי +2 משולשים של קשר (has_ingredient) +משולש אחד של תכונה (serves) + +הכל נוצר מחילוץ פשוט משפה טבעית על ידי מודל השפה הגדול! + +## הפניות + +יישום נוכחי: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` +תבנית הנחיה: `ontology-prompt.md` +מקרים בדיקה: `tests/unit/test_extract/test_ontology/` +אונטולוגיה לדוגמה: `e2e/test-data/food.ontology` diff --git a/docs/tech-specs/ontology-extract-phase-2.hi.md b/docs/tech-specs/ontology-extract-phase-2.hi.md new file mode 100644 index 00000000..34bd59b7 --- /dev/null +++ b/docs/tech-specs/ontology-extract-phase-2.hi.md @@ -0,0 +1,761 @@ +# ऑन्टोलॉजी ज्ञान निष्कर्षण - चरण 2 का पुनर्गठन + +**स्थिति**: मसौदा +**लेखक**: विश्लेषण सत्र 2025-12-03 +**संबंधित**: `ontology.md`, `ontorag.md` + +## अवलोकन + +यह दस्तावेज़ वर्तमान ऑन्टोलॉजी-आधारित ज्ञान निष्कर्षण प्रणाली में मौजूद विसंगतियों की पहचान करता है और एलएलएम प्रदर्शन को बेहतर बनाने और सूचना हानि को कम करने के लिए एक पुनर्गठन का प्रस्ताव करता है। + +## वर्तमान कार्यान्वयन + +### यह वर्तमान में कैसे काम करता है + +1. **ऑन्टोलॉजी लोडिंग** (`ontology_loader.py`) + `"fo/Recipe"`, `"fo/Food"`, `"fo/produces"` जैसे कुंजियों के साथ ऑन्टोलॉजी JSON लोड करता है। + क्लास आईडी में नामस्थान उपसर्ग स्वयं कुंजी में शामिल होता है। + `food.ontology` से उदाहरण: + ```json + "classes": { + "fo/Recipe": { + "uri": "http://purl.org/ontology/fo/Recipe", + "rdfs:comment": "A Recipe is a combination..." + } + } + ``` + +2. **प्रॉम्प्ट निर्माण** (`extract.py:299-307`, `ontology-prompt.md`) + टेम्पलेट को `classes`, `object_properties`, `datatype_properties` डिक्ट प्राप्त होते हैं। + टेम्पलेट पुनरावृति करता है: `{% for class_id, class_def in classes.items() %}` + एलएलएम देखता है: `**fo/Recipe**: A Recipe is a combination...` + उदाहरण आउटपुट प्रारूप दर्शाता है: + ```json + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} + {"subject": "recipe:cornish-pasty", "predicate": "has_ingredient", "object": "ingredient:flour"} + ``` + +3. **प्रतिक्रिया पार्सिंग** (`extract.py:382-428`) + JSON सरणी की अपेक्षा है: `[{"subject": "...", "predicate": "...", "object": "..."}]` + यह एक उप-शब्दकोष के विरुद्ध मान्य है। + `expand_uri()` के माध्यम से URI का विस्तार (extract.py:473-521) + +4. **URI विस्तार** (`extract.py:473-521`) + जांच करता है कि क्या मान `ontology_subset.classes` डिक्शनरी में है। + यदि पाया जाता है, तो क्लास परिभाषा से URI निकालता है। + यदि नहीं मिला, तो URI का निर्माण करता है: `f"https://trustgraph.ai/ontology/{ontology_id}#{value}"` + +### डेटा प्रवाह उदाहरण + +**शब्दकोष JSON → लोडर → प्रॉम्प्ट:** +``` +"fo/Recipe" → classes["fo/Recipe"] → LLM sees "**fo/Recipe**" +``` + +**एलएलएम → पार्सर → आउटपुट:** +``` +"Recipe" → not in classes["fo/Recipe"] → constructs URI → LOSES original URI +"fo/Recipe" → found in classes → uses original URI → PRESERVES URI +``` + +## पहचाने गए मुद्दे + +### 1. **प्रॉम्प्ट में असंगत उदाहरण** + +**समस्या**: प्रॉम्प्ट टेम्पलेट क्लास आईडी को उपसर्गों (`fo/Recipe`) के साथ दिखाता है, लेकिन उदाहरण आउटपुट में उपसर्ग रहित क्लास नाम (`Recipe`) का उपयोग किया गया है। + +**स्थान**: `ontology-prompt.md:5-52` + +```markdown +## Ontology Classes: +- **fo/Recipe**: A Recipe is... + +## Example Output: +{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} +``` + +**प्रभाव**: एलएलएम को किस प्रारूप का उपयोग करना है, इसके बारे में विरोधाभासी संकेत प्राप्त होते हैं। + +### 2. **यूआरआई विस्तार में सूचना का नुकसान** + +**समस्या**: जब एलएलएम उदाहरण के बाद बिना उपसर्ग वाले क्लास नामों को लौटाता है, तो `expand_uri()` उन्हें ऑन्टोलॉजी डिक्शनरी में नहीं ढूंढ पाता है और डिफ़ॉल्ट यूआरआई बनाता है, जिससे मूल सही यूआरआई खो जाते हैं। + +**स्थान**: `extract.py:494-500` + +```python +if value in ontology_subset.classes: # Looks for "Recipe" + class_def = ontology_subset.classes[value] # But key is "fo/Recipe" + if isinstance(class_def, dict) and 'uri' in class_def: + return class_def['uri'] # Never reached! +return f"https://trustgraph.ai/ontology/{ontology_id}#{value}" # Fallback +``` + +**प्रभाव:** +मूल यूआरआई: `http://purl.org/ontology/fo/Recipe` +निर्मित यूआरआई: `https://trustgraph.ai/ontology/food#Recipe` +अर्थ संबंधी जानकारी खो जाती है, इससे अंतर-क्षमता बाधित होती है। + +### 3. **अस्पष्ट इकाई उदाहरण प्रारूप** + +**समस्या:** इकाई उदाहरण यूआरआई प्रारूप के बारे में कोई स्पष्ट मार्गदर्शन नहीं है। + +**प्रॉम्प्ट में उदाहरण:** +`"recipe:cornish-pasty"` (नेमस्पेस जैसा उपसर्ग) +`"ingredient:flour"` (एक अलग उपसर्ग) + +**वास्तविक व्यवहार** (extract.py:517-520): +```python +# Treat as entity instance - construct unique URI +normalized = value.replace(" ", "-").lower() +return f"https://trustgraph.ai/{ontology_id}/{normalized}" +``` + +**प्रभाव**: एलएलएम को किसी भी संदर्भ के बिना उपसर्ग सम्मेलन का अनुमान लगाना होगा। + +### 4. **कोई नेमस्पेस उपसर्ग मार्गदर्शन नहीं** + +**समस्या**: ऑन्टोलॉजी JSON में नेमस्पेस परिभाषाएँ हैं (food.ontology में पंक्ति 10-25): +```json +"namespaces": { + "fo": "http://purl.org/ontology/fo/", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + ... +} +``` + +लेकिन ये जानकारी कभी भी एलएलएम (LLM) तक नहीं पहुंचती। एलएलएम को यह नहीं पता: +"fo" का क्या मतलब है +एंटिटीज के लिए किस उपसर्ग का उपयोग करना है +कौन सा नेमस्पेस किस तत्व पर लागू होता है + +### 5. **प्रॉम्प्ट में उपयोग नहीं किए गए लेबल** + +**समस्या**: प्रत्येक क्लास में `rdfs:label` फ़ील्ड होते हैं (उदाहरण के लिए, `{"value": "Recipe", "lang": "en-gb"}`), लेकिन प्रॉम्प्ट टेम्पलेट इनका उपयोग नहीं करता है। + +**वर्तमान**: केवल `class_id` और `comment` दिखाता है। +```jinja +- **{{class_id}}**{% if class_def.comment %}: {{class_def.comment}}{% endif %} +``` + +**उपलब्ध लेकिन अप्रयुक्त**: +```python +"rdfs:label": [{"value": "Recipe", "lang": "en-gb"}] +``` + +**प्रभाव**: यह तकनीकी आईडी के साथ पठनीय नाम प्रदान कर सकता है। + +## प्रस्तावित समाधान + +### विकल्प ए: उपसर्ग रहित आईडी में मानकीकरण + +**दृष्टिकोण**: एलएलएम को दिखाने से पहले क्लास आईडी से उपसर्ग हटाएं। + +**परिवर्तन**: +1. `build_extraction_variables()` को बदलने के लिए: + ```python + classes_for_prompt = { + k.split('/')[-1]: v # "fo/Recipe" → "Recipe" + for k, v in ontology_subset.classes.items() + } + ``` + +2. उदाहरण प्रॉम्प्ट को अपडेट करें ताकि वह मेल खाए (यह पहले से ही बिना उपसर्ग वाले नामों का उपयोग करता है)। + +3. `expand_uri()` को दोनों प्रारूपों को संभालने के लिए संशोधित करें: + ```python + # Try exact match first + if value in ontology_subset.classes: + return ontology_subset.classes[value]['uri'] + + # Try with prefix + for prefix in ['fo/', 'rdf:', 'rdfs:']: + prefixed = f"{prefix}{value}" + if prefixed in ontology_subset.classes: + return ontology_subset.classes[prefixed]['uri'] + ``` + +**लाभ:** +अधिक स्पष्ट, अधिक मानव-पठनीय +मौजूदा प्रॉम्प्ट उदाहरणों से मेल खाता है +एलएलएम सरल टोकन के साथ बेहतर काम करते हैं + +**नुकसान:** +यदि कई ऑन्टोलॉजी में समान क्लास नाम है तो क्लास नाम टकराव हो सकता है +नेमस्पेस जानकारी खो जाती है +लुकअप के लिए फॉलबैक लॉजिक की आवश्यकता होती है + +### विकल्प बी: पूर्ण उपसर्ग आईडी का लगातार उपयोग करें + +**दृष्टिकोण:** उदाहरणों को अपडेट करें ताकि वे क्लास सूची में दिखाए गए उपसर्ग आईडी से मेल खाएं। + +**परिवर्तन:** +1. प्रॉम्प्ट उदाहरण अपडेट करें (ontology-prompt.md:46-52): + ```json + [ + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "fo/Recipe"}, + {"subject": "recipe:cornish-pasty", "predicate": "rdfs:label", "object": "Cornish Pasty"}, + {"subject": "recipe:cornish-pasty", "predicate": "fo/produces", "object": "food:cornish-pasty"}, + {"subject": "food:cornish-pasty", "predicate": "rdf:type", "object": "fo/Food"} + ] + ``` + +2. प्रॉम्प्ट में नेमस्पेस स्पष्टीकरण जोड़ें: + ```markdown + ## Namespace Prefixes: + - **fo/**: Food Ontology (http://purl.org/ontology/fo/) + - **rdf:**: RDF Schema + - **rdfs:**: RDF Schema + + Use these prefixes exactly as shown when referencing classes and properties. + ``` + +3. `expand_uri()` को वैसे ही रखें (जब मिलान पाया जाता है तो यह ठीक से काम करता है)। + +**लाभ:** +इनपुट = आउटपुट स्थिरता +कोई जानकारी हानि नहीं +नेमस्पेस सिमेंटिक्स को संरक्षित करता है +कई ऑन्टोलॉजी के साथ काम करता है + +**नुकसान:** +एलएलएम के लिए अधिक विस्तृत टोकन +एलएलएम को उपसर्गों को ट्रैक करने की आवश्यकता होती है + +### विकल्प सी: हाइब्रिड - लेबल और आईडी दोनों दिखाएं + +**दृष्टिकोण:** प्रॉम्प्ट को इस तरह से बेहतर बनाएं कि मानव-पठनीय लेबल और तकनीकी आईडी दोनों दिखाए जाएं। + +**परिवर्तन:** +1. प्रॉम्प्ट टेम्पलेट को अपडेट करें: + ```jinja + {% for class_id, class_def in classes.items() %} + - **{{class_id}}** (label: "{{class_def.labels[0].value if class_def.labels else class_id}}"){% if class_def.comment %}: {{class_def.comment}}{% endif %} + {% endfor %} + ``` + + उदाहरण आउटपुट: + ```markdown + - **fo/Recipe** (label: "Recipe"): A Recipe is a combination... + ``` + +2. अपडेट निर्देश: + ```markdown + When referencing classes: + - Use the full prefixed ID (e.g., "fo/Recipe") in JSON output + - The label (e.g., "Recipe") is for human understanding only + ``` + +**लाभ:** +एलएलएम (LLM) के लिए सबसे स्पष्ट। +सभी जानकारी को संरक्षित करता है। +यह स्पष्ट करता है कि क्या उपयोग करना है। + +**नुकसान:** +लंबा प्रॉम्प्ट। +अधिक जटिल टेम्पलेट। + +## कार्यान्वित दृष्टिकोण + +**सरलीकृत इकाई-संबंध-विशेषता प्रारूप** - पुराने ट्रिपल-आधारित प्रारूप को पूरी तरह से बदल देता है। + +इस नए दृष्टिकोण को इसलिए चुना गया क्योंकि: + +1. **कोई जानकारी हानि नहीं:** मूल यूआरआई (URI) सही ढंग से संरक्षित हैं। +2. **सरल तर्क:** किसी रूपांतरण की आवश्यकता नहीं है, सीधे डिक्ट (dict) लुकअप काम करते हैं। +3. **नेमस्पेस सुरक्षा:** टकराव के बिना कई ऑन्टोलॉजी (ontology) को संभालता है। +4. **सिमेंटिक (semantic) शुद्धता:** आरडीएफ/ओडब्ल्यूएल (RDF/OWL) सिमेंटिक्स को बनाए रखता है। + +## कार्यान्वयन पूर्ण + +### क्या बनाया गया: + +1. **नया प्रॉम्प्ट टेम्पलेट** (`prompts/ontology-extract-v2.txt`) + ✅ स्पष्ट अनुभाग: इकाई प्रकार, संबंध, विशेषताएँ। + ✅ पूर्ण प्रकार पहचानकर्ताओं का उपयोग करके उदाहरण (`fo/Recipe`, `fo/has_ingredient`)। + ✅ स्कीमा (schema) से सटीक पहचानकर्ताओं का उपयोग करने के निर्देश। + ✅ संस्थाओं/संबंधों/विशेषताओं के सरणियों के साथ नया JSON प्रारूप। + +2. **एंटिटी नॉर्मलाइजेशन** (`entity_normalizer.py`) + ✅ `normalize_entity_name()` - नामों को URI-सुरक्षित प्रारूप में परिवर्तित करता है + ✅ `normalize_type_identifier()` - प्रकारों में स्लैश को संभालता है (`fo/Recipe` → `fo-recipe`) + ✅ `build_entity_uri()` - (नाम, प्रकार) टपल का उपयोग करके अद्वितीय URI बनाता है + ✅ `EntityRegistry` - डुप्लिकेट से बचने के लिए एंटिटीज को ट्रैक करता है + +3. **JSON पार्सर** (`simplified_parser.py`) + ✅ नए प्रारूप को पार्स करता है: `{entities: [...], relationships: [...], attributes: [...]}` + ✅ केबाब-केस और स्नेक_केस फ़ील्ड नामों का समर्थन करता है + ✅ संरचित डेटाक्लासेस लौटाता है + ✅ लॉगिंग के साथ त्रुटि प्रबंधन + +4. **ट्रिपल कन्वर्टर** (`triple_converter.py`) + ✅ `convert_entity()` - स्वचालित रूप से प्रकार + लेबल त्रिक उत्पन्न करता है। + ✅ `convert_relationship()` - एंटिटी यूआरआई को गुणों के माध्यम से जोड़ता है। + ✅ `convert_attribute()` - शाब्दिक मान जोड़ता है। + ✅ ऑन्टोलॉजी परिभाषाओं से पूर्ण यूआरआई की खोज करता है। + +5. **अपडेटेड मुख्य प्रोसेसर** (`extract.py`) + ✅ पुराने ट्रिपल-आधारित निष्कर्षण कोड को हटा दिया गया। + ✅ `extract_with_simplified_format()` विधि जोड़ी गई। + ✅ अब केवल नए सरलीकृत प्रारूप का उपयोग करता है। + ✅ `extract-with-ontologies-v2` आईडी के साथ प्रॉम्प्ट को कॉल करता है। + +## परीक्षण मामले + +### परीक्षण 1: यूआरआई संरक्षण +```python +# Given ontology class +classes = {"fo/Recipe": {"uri": "http://purl.org/ontology/fo/Recipe", ...}} + +# When LLM returns +llm_output = {"subject": "x", "predicate": "rdf:type", "object": "fo/Recipe"} + +# Then expanded URI should be +assert expanded == "http://purl.org/ontology/fo/Recipe" +# Not: "https://trustgraph.ai/ontology/food#Recipe" +``` + +### परीक्षण 2: बहु-ऑन्टोलॉजी टकराव +```python +# Given two ontologies +ont1 = {"fo/Recipe": {...}} +ont2 = {"cooking/Recipe": {...}} + +# LLM should use full prefix to disambiguate +llm_output = {"object": "fo/Recipe"} # Not just "Recipe" +``` + +### परीक्षण 3: इकाई उदाहरण प्रारूप +```python +# Given prompt with food ontology +# LLM should create instances like +{"subject": "recipe:cornish-pasty"} # Namespace-style +{"subject": "food:beef"} # Consistent prefix +``` + +## खुले प्रश्न + +1. **क्या एंटिटी इंस्टेंस में नेमस्पेस उपसर्गों का उपयोग किया जाना चाहिए?** + वर्तमान: `"recipe:cornish-pasty"` (यादृच्छिक) + वैकल्पिक: क्या हमें ऑन्टोलॉजी उपसर्ग `"fo:cornish-pasty"` का उपयोग करना चाहिए? + वैकल्पिक: कोई उपसर्ग नहीं, URI में विस्तार करें `"cornish-pasty"` → पूर्ण URI? + +2. **प्रॉम्प्ट में डोमेन/रेंज को कैसे संभालें?** + वर्तमान में दिखाता है: `(Recipe → Food)` + क्या इसे `(fo/Recipe → fo/Food)` होना चाहिए? + +3. **क्या हमें डोमेन/रेंज बाधाओं को मान्य करना चाहिए?** + TODO टिप्पणी extract.py:470 पर + यह अधिक त्रुटियों को पकड़ लेगा लेकिन अधिक जटिल होगा + +4. **उलटा गुण और तुल्यता के बारे में क्या?** + ऑन्टोलॉजी में `owl:inverseOf`, `owl:equivalentClass` है + वर्तमान में निष्कर्षण में उपयोग नहीं किया जाता है + क्या उन्हें उपयोग किया जाना चाहिए? + +## सफलता मेट्रिक्स + +✅ शून्य URI जानकारी हानि (मूल URIs का 100% संरक्षण) +✅ LLM आउटपुट प्रारूप इनपुट प्रारूप से मेल खाता है +✅ प्रॉम्प्ट में कोई अस्पष्ट उदाहरण नहीं +✅ कई ऑन्टोलॉजी के साथ परीक्षण पास होते हैं +✅ बेहतर निष्कर्षण गुणवत्ता (वैध ट्रिपल % द्वारा मापा गया) + +## वैकल्पिक दृष्टिकोण: सरलीकृत निष्कर्षण प्रारूप + +### दर्शन + +LLM से RDF/OWL सिमेंटिक्स को समझने के बजाय, उससे वह कार्य करवाएं जिसमें वह अच्छा है: **पाठ में एंटिटीज और संबंधों को ढूंढना।** + +URI निर्माण, RDF रूपांतरण और सिमेंटिक वेब औपचारिकताएं कोड द्वारा संभाली जाएं। + +### उदाहरण: एंटिटी वर्गीकरण + +**इनपुट टेक्स्ट:** +``` +Cornish pasty is a traditional British pastry filled with meat and vegetables. +``` + +**ऑन्टोलॉजी स्कीमा (एलएलएम को दिखाया गया):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food +``` + +**एलएलएम क्या लौटाता है (सरल JSON):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + } + ] +} +``` + +**कोड क्या उत्पन्न करता है (आरडीएफ ट्रिपल्स):** +```python +# 1. Normalize entity name + type to ID (type prevents collisions) +entity_id = "recipe-cornish-pasty" # normalize("Cornish pasty", "Recipe") +entity_uri = "https://trustgraph.ai/food/recipe-cornish-pasty" + +# Note: Same name, different type = different URI +# "Cornish pasty" (Recipe) → recipe-cornish-pasty +# "Cornish pasty" (Food) → food-cornish-pasty + +# 2. Generate triples +triples = [ + # Type triple + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/1999/02/22-rdf-syntax-ns#type", is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + # Label triple (automatic) + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/2000/01/rdf-schema#label", is_uri=True), + o=Value(value="Cornish pasty", is_uri=False) + ) +] +``` + +### लाभ + +1. **एलएलएम को इसकी आवश्यकता नहीं है:** + यूआरआई सिंटैक्स को समझना + पहचानकर्ता उपसर्गों का आविष्कार करना (`recipe:`, `ingredient:`) + `rdf:type` या `rdfs:label` के बारे में जानना + सिमेंटिक वेब पहचानकर्ताओं का निर्माण करना + +2. **एलएलएम को केवल इसकी आवश्यकता है:** + पाठ में संस्थाओं को खोजना + उन्हें ऑन्टोलॉजी कक्षाओं में मैप करना + संबंधों और विशेषताओं को निकालना + +3. **कोड द्वारा संभाला जाता है:** + यूआरआई सामान्यीकरण और निर्माण + आरडीएफ ट्रिपल पीढ़ी + स्वचालित लेबल असाइनमेंट + नेमस्पेस प्रबंधन + +### यह बेहतर क्यों है + +**सरल प्रॉम्प्ट** = कम भ्रम = कम त्रुटियां +**संगत आईडी** = कोड सामान्यीकरण नियमों को नियंत्रित करता है +**स्वचालित रूप से उत्पन्न लेबल** = कोई छूटी हुई rdfs:label ट्रिपल नहीं +**एलएलएम निष्कर्षण पर केंद्रित है** = जो कि वास्तव में इसकी क्षमता है + +### उदाहरण: इकाई संबंध + +**इनपुट टेक्स्ट:** +``` +Cornish pasty is a traditional British pastry filled with beef and potatoes. +``` + +**ऑन्टोलॉजी स्कीमा (एलएलएम को दिखाया गया):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food + +## Relationships: +- has_ingredient: Relates a recipe to an ingredient it uses (Recipe → Ingredient) +- food: Relates an ingredient to the food that is required (Ingredient → Food) +``` + +**एलएलएम क्या लौटाता है (सरल JSON):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ] +} +``` + +**कोड क्या उत्पन्न करता है (आरडीएफ ट्रिपल्स):** +```python +# Normalize entity names to URIs +cornish_pasty_uri = "https://trustgraph.ai/food/cornish-pasty" +beef_uri = "https://trustgraph.ai/food/beef" +potatoes_uri = "https://trustgraph.ai/food/potatoes" + +# Look up relation URI from ontology +has_ingredient_uri = "http://purl.org/ontology/fo/ingredients" # from fo/has_ingredient + +triples = [ + # Entity type triples (as before) + Triple(s=cornish_pasty_uri, p=rdf_type, o="http://purl.org/ontology/fo/Recipe"), + Triple(s=cornish_pasty_uri, p=rdfs_label, o="Cornish pasty"), + + Triple(s=beef_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=beef_uri, p=rdfs_label, o="beef"), + + Triple(s=potatoes_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=potatoes_uri, p=rdfs_label, o="potatoes"), + + # Relationship triples + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=beef_uri, is_uri=True) + ), + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=potatoes_uri, is_uri=True) + ) +] +``` + +**मुख्य बातें:** +एलएलएम प्राकृतिक भाषा में इकाई नामों को लौटाता है: `"Cornish pasty"`, `"beef"`, `"potatoes"` +एलएलएम अस्पष्टता को दूर करने के लिए प्रकारों को शामिल करता है: `subject-type`, `object-type` +एलएलएम स्कीमा से संबंध नाम का उपयोग करता है: `"has_ingredient"` +कोड (नाम, प्रकार) का उपयोग करके सुसंगत आईडी प्राप्त करता है: `("Cornish pasty", "Recipe")` → `recipe-cornish-pasty` +कोड ऑन्टोलॉजी से संबंध यूआरआई को देखता है: `fo/has_ingredient` → पूर्ण यूआरआई +समान (नाम, प्रकार) टपल हमेशा समान यूआरआई प्राप्त करता है (डुप्लिकेट हटाने)। + +### उदाहरण: इकाई नाम का अस्पष्टता निवारण + +**समस्या:** एक ही नाम अलग-अलग इकाई प्रकारों को संदर्भित कर सकता है। + +**वास्तविक दुनिया का मामला:** +``` +"Cornish pasty" can be: +- A Recipe (instructions for making it) +- A Food (the dish itself) +``` + +**यह कैसे संभाला जाता है:** + +एलएलएम दोनों को अलग-अलग इकाइयों के रूप में लौटाता है: +```json +{ + "entities": [ + {"entity": "Cornish pasty", "type": "Recipe"}, + {"entity": "Cornish pasty", "type": "Food"} + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "produces", + "object": "Cornish pasty", + "object-type": "Food" + } + ] +} +``` + +**कोड समाधान:** +```python +# Different types → different URIs +recipe_uri = normalize("Cornish pasty", "Recipe") +# → "https://trustgraph.ai/food/recipe-cornish-pasty" + +food_uri = normalize("Cornish pasty", "Food") +# → "https://trustgraph.ai/food/food-cornish-pasty" + +# Relationship connects them correctly +triple = Triple( + s=recipe_uri, # The Recipe + p="http://purl.org/ontology/fo/produces", + o=food_uri # The Food +) +``` + +**यह क्यों काम करता है:** +प्रकार सभी संदर्भों (इकाइयों, संबंधों, विशेषताओं) में शामिल है। +कोड `(name, type)` टपल को लुकअप कुंजी के रूप में उपयोग करता है। +कोई अस्पष्टता नहीं, कोई टकराव नहीं। + +### उदाहरण: इकाई विशेषताएँ + +**इनपुट टेक्स्ट:** +``` +This Cornish pasty recipe serves 4-6 people and takes 45 minutes to prepare. +``` + +**ऑन्टोलॉजी स्कीमा (एलएलएम को दिखाया गया):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method + +## Attributes: +- serves: Indicates what the recipe is intended to serve (Recipe → text) +- preparation_time: Time needed to prepare the recipe (Recipe → text) +``` + +**एलएलएम क्या लौटाता है (सरल JSON):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty recipe", + "type": "Recipe" + } + ], + "attributes": [ + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4-6 people" + }, + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "preparation_time", + "value": "45 minutes" + } + ] +} +``` + +**कोड क्या उत्पन्न करता है (आरडीएफ ट्रिपल्स):** +```python +# Normalize entity name to URI +recipe_uri = "https://trustgraph.ai/food/cornish-pasty-recipe" + +# Look up attribute URIs from ontology +serves_uri = "http://purl.org/ontology/fo/serves" # from fo/serves +prep_time_uri = "http://purl.org/ontology/fo/preparation_time" # from fo/preparation_time + +triples = [ + # Entity type triple + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdf_type, is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + + # Label triple (automatic) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdfs_label, is_uri=True), + o=Value(value="Cornish pasty recipe", is_uri=False) + ), + + # Attribute triples (objects are literals, not URIs) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=serves_uri, is_uri=True), + o=Value(value="4-6 people", is_uri=False) # Literal value! + ), + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=prep_time_uri, is_uri=True), + o=Value(value="45 minutes", is_uri=False) # Literal value! + ) +] +``` + +**मुख्य बातें:** +एलएलएम शाब्दिक मानों को निकालता है: `"4-6 people"`, `"45 minutes"` +एलएलएम अस्पष्टता को दूर करने के लिए इकाई प्रकार को शामिल करता है: `entity-type` +एलएलएम स्कीमा से विशेषता नाम का उपयोग करता है: `"serves"`, `"preparation_time"` +कोड ऑन्टोलॉजी डेटाटाइप गुणों से विशेषता यूआरआई को देखता है +**ऑब्जेक्ट शाब्दिक है** (`is_uri=False`), कोई यूआरआई संदर्भ नहीं है +मान प्राकृतिक पाठ के रूप में रहते हैं, किसी सामान्यीकरण की आवश्यकता नहीं है + +**संबंधों से अंतर:** +संबंध: विषय और वस्तु दोनों इकाइयाँ (यूआरआई) हैं +विशेषताएँ: विषय इकाई (यूआरआई) है, वस्तु शाब्दिक मान (स्ट्रिंग/संख्या) है + +### संपूर्ण उदाहरण: इकाइयाँ + संबंध + विशेषताएँ + +**इनपुट टेक्स्ट:** +``` +Cornish pasty is a savory pastry filled with beef and potatoes. +This recipe serves 4 people. +``` + +**एलएलएम क्या लौटाता है:** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ], + "attributes": [ + { + "entity": "Cornish pasty", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4 people" + } + ] +} +``` + +**परिणाम:** 11 आरडीएफ त्रिगुण उत्पन्न हुए: +3 इकाई प्रकार त्रिगुण (rdf:type) +3 इकाई लेबल त्रिगुण (rdfs:label) - स्वचालित +2 संबंध त्रिगुण (has_ingredient) +1 विशेषता त्रिगुण (serves) + +ये सभी एलएलएम द्वारा सरल, प्राकृतिक भाषा निष्कर्षण से प्राप्त हुए! + +## संदर्भ + +वर्तमान कार्यान्वयन: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` +प्रॉम्प्ट टेम्पलेट: `ontology-prompt.md` +परीक्षण मामले: `tests/unit/test_extract/test_ontology/` +उदाहरण ऑन्टोलॉजी: `e2e/test-data/food.ontology` diff --git a/docs/tech-specs/ontology-extract-phase-2.pt.md b/docs/tech-specs/ontology-extract-phase-2.pt.md new file mode 100644 index 00000000..7352681b --- /dev/null +++ b/docs/tech-specs/ontology-extract-phase-2.pt.md @@ -0,0 +1,761 @@ +# Extração de Conhecimento de Ontologias - Fase 2 de Refatoração + +**Status**: Rascunho +**Autor**: Sessão de Análise 2025-12-03 +**Relacionado**: `ontology.md`, `ontorag.md` + +## Visão Geral + +Este documento identifica inconsistências no sistema atual de extração de conhecimento baseado em ontologias e propõe uma refatoração para melhorar o desempenho do LLM e reduzir a perda de informações. + +## Implementação Atual + +### Como Funciona Atualmente + +1. **Carregamento da Ontologia** (`ontology_loader.py`) + Carrega o arquivo JSON da ontologia com chaves como `"fo/Recipe"`, `"fo/Food"`, `"fo/produces"` + Os IDs das classes incluem o prefixo do namespace na própria chave + Exemplo de `food.ontology`: + ```json + "classes": { + "fo/Recipe": { + "uri": "http://purl.org/ontology/fo/Recipe", + "rdfs:comment": "A Recipe is a combination..." + } + } + ``` + +2. **Construção do Prompt** (`extract.py:299-307`, `ontology-prompt.md`) + O modelo recebe os dicionários `classes`, `object_properties`, `datatype_properties` + O modelo itera: `{% for class_id, class_def in classes.items() %}` + O LLM vê: `**fo/Recipe**: A Recipe is a combination...` + O formato de saída de exemplo mostra: + ```json + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} + {"subject": "recipe:cornish-pasty", "predicate": "has_ingredient", "object": "ingredient:flour"} + ``` + +3. **Análise da Resposta** (`extract.py:382-428`) + Espera um array JSON: `[{"subject": "...", "predicate": "...", "object": "..."}]` + Valida em relação a um subconjunto da ontologia + Expande URIs via `expand_uri()` (extract.py:473-521) + +4. **Expansão de URIs** (`extract.py:473-521`) + Verifica se o valor está no dicionário `ontology_subset.classes` + Se encontrado, extrai o URI da definição da classe + Se não encontrado, constrói o URI: `f"https://trustgraph.ai/ontology/{ontology_id}#{value}"` + +### Exemplo de Fluxo de Dados + +**JSON da Ontologia → Loader → Prompt:** +``` +"fo/Recipe" → classes["fo/Recipe"] → LLM sees "**fo/Recipe**" +``` + +**LLM → Parser → Output:** +``` +"Recipe" → not in classes["fo/Recipe"] → constructs URI → LOSES original URI +"fo/Recipe" → found in classes → uses original URI → PRESERVES URI +``` + +## Problemas Identificados + +### 1. **Exemplos Inconsistentes no Prompt** + +**Problema**: O modelo de prompt mostra IDs de classe com prefixos (`fo/Recipe`), mas a saída de exemplo usa nomes de classe sem prefixo (`Recipe`). + +**Localização**: `ontology-prompt.md:5-52` + +```markdown +## Ontology Classes: +- **fo/Recipe**: A Recipe is... + +## Example Output: +{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} +``` + +**Impacto**: O LLM recebe sinais conflitantes sobre qual formato usar. + +### 2. **Perda de Informação na Expansão de URIs** + +**Problema**: Quando o LLM retorna nomes de classe sem prefixo, seguindo o exemplo, `expand_uri()` não consegue encontrá-los no dicionário de ontologias e constrói URIs de fallback, perdendo os URIs originais corretos. + +**Localização**: `extract.py:494-500` + +```python +if value in ontology_subset.classes: # Looks for "Recipe" + class_def = ontology_subset.classes[value] # But key is "fo/Recipe" + if isinstance(class_def, dict) and 'uri' in class_def: + return class_def['uri'] # Never reached! +return f"https://trustgraph.ai/ontology/{ontology_id}#{value}" # Fallback +``` + +**Impacto:** +URI original: `http://purl.org/ontology/fo/Recipe` +URI construído: `https://trustgraph.ai/ontology/food#Recipe` +Perda de significado semântico, quebra a interoperabilidade + +### 3. **Formato Ambíguo de Instância de Entidade** + +**Problema:** Não há orientação clara sobre o formato do URI da instância de entidade. + +**Exemplos no prompt:** +`"recipe:cornish-pasty"` (prefixo semelhante a um namespace) +`"ingredient:flour"` (prefixo diferente) + +**Comportamento real** (extract.py:517-520): +```python +# Treat as entity instance - construct unique URI +normalized = value.replace(" ", "-").lower() +return f"https://trustgraph.ai/{ontology_id}/{normalized}" +``` + +**Impacto**: O modelo de linguagem deve adivinhar a convenção de prefixo sem contexto ontológico. + +### 4. **Sem Orientação de Prefixo de Namespace** + +**Problema**: O JSON da ontologia contém definições de namespace (linha 10-25 em food.ontology): +```json +"namespaces": { + "fo": "http://purl.org/ontology/fo/", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + ... +} +``` + +Mas estas informações nunca são transmitidas para o LLM. O LLM não sabe: +O que "fo" significa +Qual prefixo usar para entidades +Qual namespace se aplica a quais elementos + +### 5. **Rótulos Não Utilizados no Prompt** + +**Problema**: Cada classe tem campos `rdfs:label` (por exemplo, `{"value": "Recipe", "lang": "en-gb"}`), mas o modelo de prompt não os utiliza. + +**Atual**: Mostra apenas `class_id` e `comment` +```jinja +- **{{class_id}}**{% if class_def.comment %}: {{class_def.comment}}{% endif %} +``` + +**Disponível, mas não utilizado**: +```python +"rdfs:label": [{"value": "Recipe", "lang": "en-gb"}] +``` + +**Impacto**: Poderia fornecer nomes legíveis para humanos, juntamente com IDs técnicos. + +## Soluções Propostas + +### Opção A: Normalizar para IDs sem Prefixo + +**Abordagem**: Remover os prefixos dos IDs de classe antes de exibi-los para o LLM. + +**Alterações**: +1. Modificar `build_extraction_variables()` para transformar chaves: + ```python + classes_for_prompt = { + k.split('/')[-1]: v # "fo/Recipe" → "Recipe" + for k, v in ontology_subset.classes.items() + } + ``` + +2. Atualizar o exemplo de prompt para corresponder (já usa nomes sem prefixo). + +3. Modificar `expand_uri()` para lidar com ambos os formatos: + ```python + # Try exact match first + if value in ontology_subset.classes: + return ontology_subset.classes[value]['uri'] + + # Try with prefix + for prefix in ['fo/', 'rdf:', 'rdfs:']: + prefixed = f"{prefix}{value}" + if prefixed in ontology_subset.classes: + return ontology_subset.classes[prefixed]['uri'] + ``` + +**Prós:** +Mais limpo, mais legível para humanos +Compatível com exemplos de prompts existentes +Modelos de linguagem grandes (LLMs) funcionam melhor com tokens mais simples + +**Contras:** +Colisões de nomes de classe se múltiplas ontologias tiverem o mesmo nome de classe +Perde informações de namespace +Requer lógica de fallback para pesquisas + +### Opção B: Usar IDs com Prefixo Completo Consistentemente + +**Abordagem:** Atualizar exemplos para usar IDs com prefixo correspondentes ao que é mostrado na lista de classes. + +**Mudanças:** +1. Atualizar exemplo de prompt (ontology-prompt.md:46-52): + ```json + [ + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "fo/Recipe"}, + {"subject": "recipe:cornish-pasty", "predicate": "rdfs:label", "object": "Cornish Pasty"}, + {"subject": "recipe:cornish-pasty", "predicate": "fo/produces", "object": "food:cornish-pasty"}, + {"subject": "food:cornish-pasty", "predicate": "rdf:type", "object": "fo/Food"} + ] + ``` + +2. Adicionar explicação do namespace ao prompt: + ```markdown + ## Namespace Prefixes: + - **fo/**: Food Ontology (http://purl.org/ontology/fo/) + - **rdf:**: RDF Schema + - **rdfs:**: RDF Schema + + Use these prefixes exactly as shown when referencing classes and properties. + ``` + +3. Mantenha `expand_uri()` como está (funciona corretamente quando as correspondências são encontradas). + +**Prós:** +Consistência entre entrada e saída. +Sem perda de informação. +Preserva a semântica do namespace. +Funciona com múltiplas ontologias. + +**Contras:** +Tokens mais verbosos para o LLM. +Requer que o LLM rastreie os prefixos. + +### Opção C: Híbrida - Mostrar Tanto o Rótulo quanto o ID + +**Abordagem:** Aprimorar o prompt para mostrar tanto os rótulos legíveis por humanos quanto os IDs técnicos. + +**Alterações:** +1. Atualizar o modelo do prompt: + ```jinja + {% for class_id, class_def in classes.items() %} + - **{{class_id}}** (label: "{{class_def.labels[0].value if class_def.labels else class_id}}"){% if class_def.comment %}: {{class_def.comment}}{% endif %} + {% endfor %} + ``` + + Exemplo de saída: + ```markdown + - **fo/Recipe** (label: "Recipe"): A Recipe is a combination... + ``` + +2. Instruções de atualização: + ```markdown + When referencing classes: + - Use the full prefixed ID (e.g., "fo/Recipe") in JSON output + - The label (e.g., "Recipe") is for human understanding only + ``` + +**Prós**: +Mais claro para LLM +Preserva todas as informações +Explícito sobre o que usar + +**Contras**: +Prompt mais longo +Modelo mais complexo + +## Abordagem Implementada + +**Formato Simplificado de Entidade-Relacionamento-Atributo** - substitui completamente o formato antigo baseado em triplas. + +A nova abordagem foi escolhida porque: + +1. **Nenhuma Perda de Informação**: URIs originais preservados corretamente +2. **Lógica Mais Simples**: Nenhuma transformação necessária, pesquisas diretas em dicionários funcionam +3. **Segurança de Namespace**: Lida com múltiplas ontologias sem colisões +4. **Correção Semântica**: Mantém a semântica RDF/OWL + +## Implementação Completa + +### O Que Foi Construído: + +1. **Novo Modelo de Prompt** (`prompts/ontology-extract-v2.txt`) + ✅ Seções claras: Tipos de Entidade, Relacionamentos, Atributos + ✅ Exemplo usando identificadores de tipo completos (`fo/Recipe`, `fo/has_ingredient`) + ✅ Instruções para usar identificadores exatos do esquema + ✅ Novo formato JSON com arrays de entidades/relacionamentos/atributos + +2. **Normalização de Entidade** (`entity_normalizer.py`) + ✅ `normalize_entity_name()` - Converte nomes para formato seguro para URI + ✅ `normalize_type_identifier()` - Lida com barras em tipos (`fo/Recipe` → `fo-recipe`) + ✅ `build_entity_uri()` - Cria URIs únicos usando a tupla (nome, tipo) + ✅ `EntityRegistry` - Rastreia entidades para desduplicação + +3. **Analisador JSON** (`simplified_parser.py`) + ✅ Analisa o novo formato: `{entities: [...], relationships: [...], attributes: [...]}` + ✅ Suporta nomes de campos em kebab-case e snake_case + ✅ Retorna dataclasses estruturadas + ✅ Tratamento de erros elegante com registro + +4. **Conversor de Triplas** (`triple_converter.py`) + ✅ `convert_entity()` - Gera automaticamente triplas de tipo + rótulo + ✅ `convert_relationship()` - Conecta URIs de entidade via propriedades + ✅ `convert_attribute()` - Adiciona valores literais + ✅ Consulta URIs completos a partir de definições de ontologia + +5. **Processador Principal Atualizado** (`extract.py`) + ✅ Removeu o código antigo de extração baseado em triplas + ✅ Adicionado método `extract_with_simplified_format()` + ✅ Agora usa exclusivamente o novo formato simplificado + ✅ Chama o prompt com o ID `extract-with-ontologies-v2` + +## Casos de Teste + +### Teste 1: Preservação de URI +```python +# Given ontology class +classes = {"fo/Recipe": {"uri": "http://purl.org/ontology/fo/Recipe", ...}} + +# When LLM returns +llm_output = {"subject": "x", "predicate": "rdf:type", "object": "fo/Recipe"} + +# Then expanded URI should be +assert expanded == "http://purl.org/ontology/fo/Recipe" +# Not: "https://trustgraph.ai/ontology/food#Recipe" +``` + +### Teste 2: Colisão Multi-Ontologia +```python +# Given two ontologies +ont1 = {"fo/Recipe": {...}} +ont2 = {"cooking/Recipe": {...}} + +# LLM should use full prefix to disambiguate +llm_output = {"object": "fo/Recipe"} # Not just "Recipe" +``` + +### Teste 3: Formato de Instância de Entidade +```python +# Given prompt with food ontology +# LLM should create instances like +{"subject": "recipe:cornish-pasty"} # Namespace-style +{"subject": "food:beef"} # Consistent prefix +``` + +## Perguntas Abertas + +1. **As instâncias de entidades devem usar prefixos de namespace?** + Atual: `"recipe:cornish-pasty"` (arbitrário) + Alternativa: Usar o prefixo da ontologia `"fo:cornish-pasty"`? + Alternativa: Sem prefixo, expandir no URI `"cornish-pasty"` → URI completo? + +2. **Como lidar com o domínio/alcance no prompt?** + Atualmente mostra: `(Recipe → Food)` + Deveria ser: `(fo/Recipe → fo/Food)`? + +3. **Devemos validar as restrições de domínio/alcance?** + TODO: comentário em extract.py:470 + Detectaria mais erros, mas seria mais complexo + +4. **O que dizer das propriedades inversas e equivalências?** + A ontologia tem `owl:inverseOf`, `owl:equivalentClass` + Não está atualmente sendo usado na extração + Deveria estar? + +## Métricas de Sucesso + +✅ Perda zero de informações de URI (100% de preservação dos URIs originais) +✅ O formato de saída do LLM corresponde ao formato de entrada +✅ Nenhum exemplo ambíguo no prompt +✅ Os testes passam com múltiplas ontologias +✅ Qualidade de extração aprimorada (medida pela porcentagem de triplas válidas) + +## Abordagem Alternativa: Formato de Extração Simplificado + +### Filosofia + +Em vez de pedir ao LLM para entender a semântica RDF/OWL, peça para ele fazer o que ele faz de melhor: **encontrar entidades e relacionamentos no texto**. + +Deixe que o código lide com a construção de URIs, a conversão RDF e as formalidades da web semântica. + +### Exemplo: Classificação de Entidades + +**Texto de Entrada:** +``` +Cornish pasty is a traditional British pastry filled with meat and vegetables. +``` + +**Esquema de Ontologia (mostrado ao LLM):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food +``` + +**O que o LLM retorna (JSON simples):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + } + ] +} +``` + +**O que o Código Produz (Triplas RDF):** +```python +# 1. Normalize entity name + type to ID (type prevents collisions) +entity_id = "recipe-cornish-pasty" # normalize("Cornish pasty", "Recipe") +entity_uri = "https://trustgraph.ai/food/recipe-cornish-pasty" + +# Note: Same name, different type = different URI +# "Cornish pasty" (Recipe) → recipe-cornish-pasty +# "Cornish pasty" (Food) → food-cornish-pasty + +# 2. Generate triples +triples = [ + # Type triple + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/1999/02/22-rdf-syntax-ns#type", is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + # Label triple (automatic) + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/2000/01/rdf-schema#label", is_uri=True), + o=Value(value="Cornish pasty", is_uri=False) + ) +] +``` + +### Benefícios + +1. **O LLM não precisa de:** + Entender a sintaxe de URI + Inventar prefixos de identificadores (`recipe:`, `ingredient:`) + Saber sobre `rdf:type` ou `rdfs:label` + Construir identificadores da web semântica + +2. **O LLM precisa apenas de:** + Encontrar entidades no texto + Mapeá-las para classes de ontologia + Extrair relacionamentos e atributos + +3. **O código lida com:** + Normalização e construção de URI + Geração de triplas RDF + Atribuição automática de rótulos + Gerenciamento de namespaces + +### Por que Isso Funciona Melhor + +**Prompt mais simples** = menos confusão = menos erros +**IDs consistentes** = o código controla as regras de normalização +**Rótulos gerados automaticamente** = sem triplas rdfs:label ausentes +**O LLM se concentra na extração** = o que ele realmente faz bem + +### Exemplo: Relacionamentos de Entidades + +**Texto de entrada:** +``` +Cornish pasty is a traditional British pastry filled with beef and potatoes. +``` + +**Esquema de Ontologia (mostrado ao LLM):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food + +## Relationships: +- has_ingredient: Relates a recipe to an ingredient it uses (Recipe → Ingredient) +- food: Relates an ingredient to the food that is required (Ingredient → Food) +``` + +**O que o LLM retorna (JSON simples):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ] +} +``` + +**O que o Código Produz (Triplas RDF):** +```python +# Normalize entity names to URIs +cornish_pasty_uri = "https://trustgraph.ai/food/cornish-pasty" +beef_uri = "https://trustgraph.ai/food/beef" +potatoes_uri = "https://trustgraph.ai/food/potatoes" + +# Look up relation URI from ontology +has_ingredient_uri = "http://purl.org/ontology/fo/ingredients" # from fo/has_ingredient + +triples = [ + # Entity type triples (as before) + Triple(s=cornish_pasty_uri, p=rdf_type, o="http://purl.org/ontology/fo/Recipe"), + Triple(s=cornish_pasty_uri, p=rdfs_label, o="Cornish pasty"), + + Triple(s=beef_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=beef_uri, p=rdfs_label, o="beef"), + + Triple(s=potatoes_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=potatoes_uri, p=rdfs_label, o="potatoes"), + + # Relationship triples + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=beef_uri, is_uri=True) + ), + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=potatoes_uri, is_uri=True) + ) +] +``` + +**Pontos-chave:** +O LLM retorna nomes de entidades em linguagem natural: `"Cornish pasty"`, `"beef"`, `"potatoes"` +O LLM inclui tipos para disambiguar: `subject-type`, `object-type` +O LLM usa o nome da relação do esquema: `"has_ingredient"` +O código deriva IDs consistentes usando (nome, tipo): `("Cornish pasty", "Recipe")` → `recipe-cornish-pasty` +O código pesquisa o URI da relação na ontologia: `fo/has_ingredient` → URI completo +A mesma tupla (nome, tipo) sempre obtém o mesmo URI (desduplicação) + +### Exemplo: Desambiguação de Nomes de Entidades + +**Problema:** O mesmo nome pode se referir a diferentes tipos de entidade. + +**Caso real:** +``` +"Cornish pasty" can be: +- A Recipe (instructions for making it) +- A Food (the dish itself) +``` + +**Como é tratado:** + +O LLM retorna ambos como entidades separadas: +```json +{ + "entities": [ + {"entity": "Cornish pasty", "type": "Recipe"}, + {"entity": "Cornish pasty", "type": "Food"} + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "produces", + "object": "Cornish pasty", + "object-type": "Food" + } + ] +} +``` + +**Resolução de Código:** +```python +# Different types → different URIs +recipe_uri = normalize("Cornish pasty", "Recipe") +# → "https://trustgraph.ai/food/recipe-cornish-pasty" + +food_uri = normalize("Cornish pasty", "Food") +# → "https://trustgraph.ai/food/food-cornish-pasty" + +# Relationship connects them correctly +triple = Triple( + s=recipe_uri, # The Recipe + p="http://purl.org/ontology/fo/produces", + o=food_uri # The Food +) +``` + +**Por que isso funciona:** +O tipo está incluído em TODAS as referências (entidades, relacionamentos, atributos). +O código usa a tupla `(name, type)` como chave de pesquisa. +Sem ambiguidades, sem colisões. + +### Exemplo: Atributos de Entidade + +**Texto de entrada:** +``` +This Cornish pasty recipe serves 4-6 people and takes 45 minutes to prepare. +``` + +**Esquema de Ontologia (mostrado ao LLM):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method + +## Attributes: +- serves: Indicates what the recipe is intended to serve (Recipe → text) +- preparation_time: Time needed to prepare the recipe (Recipe → text) +``` + +**O que o LLM retorna (JSON simples):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty recipe", + "type": "Recipe" + } + ], + "attributes": [ + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4-6 people" + }, + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "preparation_time", + "value": "45 minutes" + } + ] +} +``` + +**O que o Código Produz (Triplas RDF):** +```python +# Normalize entity name to URI +recipe_uri = "https://trustgraph.ai/food/cornish-pasty-recipe" + +# Look up attribute URIs from ontology +serves_uri = "http://purl.org/ontology/fo/serves" # from fo/serves +prep_time_uri = "http://purl.org/ontology/fo/preparation_time" # from fo/preparation_time + +triples = [ + # Entity type triple + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdf_type, is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + + # Label triple (automatic) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdfs_label, is_uri=True), + o=Value(value="Cornish pasty recipe", is_uri=False) + ), + + # Attribute triples (objects are literals, not URIs) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=serves_uri, is_uri=True), + o=Value(value="4-6 people", is_uri=False) # Literal value! + ), + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=prep_time_uri, is_uri=True), + o=Value(value="45 minutes", is_uri=False) # Literal value! + ) +] +``` + +**Pontos-chave:** +O LLM extrai valores literais: `"4-6 people"`, `"45 minutes"` +O LLM inclui o tipo de entidade para desambiguação: `entity-type` +O LLM usa o nome do atributo do esquema: `"serves"`, `"preparation_time"` +O código pesquisa o URI do atributo a partir das propriedades do tipo de dados da ontologia +**O objeto é literal** (`is_uri=False`), não uma referência de URI +Os valores permanecem como texto natural, sem necessidade de normalização + +**Diferença em relação a Relacionamentos:** +Relacionamentos: tanto o sujeito quanto o objeto são entidades (URIs) +Atributos: o sujeito é uma entidade (URI), o objeto é um valor literal (string/número) + +### Exemplo Completo: Entidades + Relacionamentos + Atributos + +**Texto de Entrada:** +``` +Cornish pasty is a savory pastry filled with beef and potatoes. +This recipe serves 4 people. +``` + +**O que o LLM retorna:** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ], + "attributes": [ + { + "entity": "Cornish pasty", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4 people" + } + ] +} +``` + +**Resultado:** 11 triplas RDF geradas: +3 triplas de tipo de entidade (rdf:type) +3 triplas de rótulo de entidade (rdfs:label) - automático +2 triplas de relacionamento (has_ingredient) +1 tripla de atributo (serves) + +Tudo isso a partir de extrações simples e em linguagem natural pelo LLM! + +## Referências + +Implementação atual: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` +Modelo de prompt: `ontology-prompt.md` +Casos de teste: `tests/unit/test_extract/test_ontology/` +Ontologia de exemplo: `e2e/test-data/food.ontology` diff --git a/docs/tech-specs/ontology-extract-phase-2.ru.md b/docs/tech-specs/ontology-extract-phase-2.ru.md new file mode 100644 index 00000000..6388b38a --- /dev/null +++ b/docs/tech-specs/ontology-extract-phase-2.ru.md @@ -0,0 +1,761 @@ +# Извлечение знаний из онтологий - Фаза 2, рефакторинг + +**Статус**: Черновик +**Автор**: Аналитическая сессия 2025-12-03 +**Связанные**: `ontology.md`, `ontorag.md` + +## Обзор + +Этот документ выявляет несоответствия в текущей системе извлечения знаний на основе онтологий и предлагает рефакторинг для повышения производительности LLM и снижения потери информации. + +## Текущая реализация + +### Как это работает сейчас + +1. **Загрузка онтологии** (`ontology_loader.py`) + Загружает JSON-файл онтологии с ключами, такими как `"fo/Recipe"`, `"fo/Food"`, `"fo/produces"` + Идентификаторы классов включают префикс пространства имен в самом ключе + Пример из `food.ontology`: + ```json + "classes": { + "fo/Recipe": { + "uri": "http://purl.org/ontology/fo/Recipe", + "rdfs:comment": "A Recipe is a combination..." + } + } + ``` + +2. **Построение запроса** (`extract.py:299-307`, `ontology-prompt.md`) + Шаблон получает словари `classes`, `object_properties`, `datatype_properties` + Шаблон выполняет итерацию: `{% for class_id, class_def in classes.items() %}` + LLM видит: `**fo/Recipe**: A Recipe is a combination...` + Пример формата вывода показывает: + ```json + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} + {"subject": "recipe:cornish-pasty", "predicate": "has_ingredient", "object": "ingredient:flour"} + ``` + +3. **Разбор ответа** (`extract.py:382-428`) + Ожидается массив JSON: `[{"subject": "...", "predicate": "...", "object": "..."}]` + Проверка на соответствие подмножеству онтологии + Расширение URI с помощью `expand_uri()` (extract.py:473-521) + +4. **Расширение URI** (`extract.py:473-521`) + Проверяет, присутствует ли значение в словаре `ontology_subset.classes` + Если найдено, извлекает URI из определения класса + Если не найдено, создает URI: `f"https://trustgraph.ai/ontology/{ontology_id}#{value}"` + +### Пример потока данных + +**JSON онтологии → Загрузчик → Запрос:** +``` +"fo/Recipe" → classes["fo/Recipe"] → LLM sees "**fo/Recipe**" +``` + +**Большая языковая модель → Парсер → Вывод:** +``` +"Recipe" → not in classes["fo/Recipe"] → constructs URI → LOSES original URI +"fo/Recipe" → found in classes → uses original URI → PRESERVES URI +``` + +## Выявленные проблемы + +### 1. **Несоответствие примеров в запросе** + +**Проблема**: Шаблон запроса показывает идентификаторы классов с префиксами (`fo/Recipe`), но пример вывода использует имена классов без префиксов (`Recipe`). + +**Местоположение**: `ontology-prompt.md:5-52` + +```markdown +## Ontology Classes: +- **fo/Recipe**: A Recipe is... + +## Example Output: +{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} +``` + +**Влияние**: LLM получает противоречивые сигналы о том, какой формат использовать. + +### 2. **Потеря информации при расширении URI** + +**Проблема**: Когда LLM возвращает имена классов без префикса, следуя примеру, `expand_uri()` не может найти их в словаре онтологии и создает резервные URI, теряя исходные правильные URI. + +**Местоположение**: `extract.py:494-500` + +```python +if value in ontology_subset.classes: # Looks for "Recipe" + class_def = ontology_subset.classes[value] # But key is "fo/Recipe" + if isinstance(class_def, dict) and 'uri' in class_def: + return class_def['uri'] # Never reached! +return f"https://trustgraph.ai/ontology/{ontology_id}#{value}" # Fallback +``` + +**Влияние:** +Исходный URI: `http://purl.org/ontology/fo/Recipe` +Сформированный URI: `https://trustgraph.ai/ontology/food#Recipe` +Семантическое значение потеряно, нарушается совместимость. + +### 3. **Неоднозначный формат экземпляра сущности** + +**Проблема:** Отсутствуют четкие указания относительно формата URI экземпляра сущности. + +**Примеры в запросе:** +`"recipe:cornish-pasty"` (префикс, похожий на пространство имен) +`"ingredient:flour"` (другой префикс) + +**Фактическое поведение** (extract.py:517-520): +```python +# Treat as entity instance - construct unique URI +normalized = value.replace(" ", "-").lower() +return f"https://trustgraph.ai/{ontology_id}/{normalized}" +``` + +**Влияние**: LLM должна угадать соглашение о префиксах без контекста онтологии. + +### 4. **Отсутствие рекомендаций по префиксам пространств имен** + +**Проблема**: JSON-файл онтологии содержит определения пространств имен (строки 10-25 в food.ontology): +```json +"namespaces": { + "fo": "http://purl.org/ontology/fo/", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + ... +} +``` + +Но эти данные никогда не передаются в языковую модель. Языковая модель не знает: +Что означает "fo" +Какой префикс использовать для сущностей +К каким элементам относится какое пространство имен + +### 5. **Метки, не используемые в запросе** + +**Проблема**: У каждого класса есть поля `rdfs:label` (например, `{"value": "Recipe", "lang": "en-gb"}`), но шаблон запроса их не использует. + +**Текущая ситуация**: Отображаются только `class_id` и `comment` +```jinja +- **{{class_id}}**{% if class_def.comment %}: {{class_def.comment}}{% endif %} +``` + +**Доступно, но не используется**: +```python +"rdfs:label": [{"value": "Recipe", "lang": "en-gb"}] +``` + +**Влияние**: Может предоставить удобочитаемые имена наряду с техническими идентификаторами. + +## Предлагаемые решения + +### Вариант A: Нормализация до идентификаторов без префиксов + +**Подход**: Удалять префиксы из идентификаторов классов перед отображением LLM. + +**Изменения**: +1. Изменить `build_extraction_variables()` для преобразования ключей: + ```python + classes_for_prompt = { + k.split('/')[-1]: v # "fo/Recipe" → "Recipe" + for k, v in ontology_subset.classes.items() + } + ``` + +2. Обновить пример запроса, чтобы он соответствовал (уже использует имена без префиксов). + +3. Изменить `expand_uri()` для обработки обоих форматов: + ```python + # Try exact match first + if value in ontology_subset.classes: + return ontology_subset.classes[value]['uri'] + + # Try with prefix + for prefix in ['fo/', 'rdf:', 'rdfs:']: + prefixed = f"{prefix}{value}" + if prefixed in ontology_subset.classes: + return ontology_subset.classes[prefixed]['uri'] + ``` + +**Преимущества:** +Более понятный и читаемый для человека. +Соответствует существующим примерам запросов. +Большие языковые модели (LLM) лучше работают с более простыми токенами. + +**Недостатки:** +Конфликты имен классов, если несколько онтологий имеют одинаковое имя класса. +Потеря информации о пространстве имен. +Требуется логика обработки исключений для поиска. + +### Вариант B: Использовать полные префиксные идентификаторы последовательно + +**Подход:** Обновить примеры для использования префиксных идентификаторов, соответствующих тем, которые показаны в списке классов. + +**Изменения:** +1. Обновить пример запроса (ontology-prompt.md:46-52): + ```json + [ + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "fo/Recipe"}, + {"subject": "recipe:cornish-pasty", "predicate": "rdfs:label", "object": "Cornish Pasty"}, + {"subject": "recipe:cornish-pasty", "predicate": "fo/produces", "object": "food:cornish-pasty"}, + {"subject": "food:cornish-pasty", "predicate": "rdf:type", "object": "fo/Food"} + ] + ``` + +2. Добавьте объяснение пространства имен в запрос: + ```markdown + ## Namespace Prefixes: + - **fo/**: Food Ontology (http://purl.org/ontology/fo/) + - **rdf:**: RDF Schema + - **rdfs:**: RDF Schema + + Use these prefixes exactly as shown when referencing classes and properties. + ``` + +3. Оставьте `expand_uri()` без изменений (это работает правильно, когда найдены совпадения). + +**Преимущества:** +Согласованность входных и выходных данных. +Отсутствие потери информации. +Сохраняет семантику пространства имен. +Работает с несколькими онтологиями. + +**Недостатки:** +Более многословные токены для LLM. +Требует от LLM отслеживания префиксов. + +### Вариант C: Гибридный - Отображать и метку, и идентификатор. + +**Подход:** Улучшить запрос, чтобы отображать как читаемые человеком метки, так и технические идентификаторы. + +**Изменения:** +1. Обновить шаблон запроса: + ```jinja + {% for class_id, class_def in classes.items() %} + - **{{class_id}}** (label: "{{class_def.labels[0].value if class_def.labels else class_id}}"){% if class_def.comment %}: {{class_def.comment}}{% endif %} + {% endfor %} + ``` + + Пример вывода: + ```markdown + - **fo/Recipe** (label: "Recipe"): A Recipe is a combination... + ``` + +2. Инструкции по обновлению: + ```markdown + When referencing classes: + - Use the full prefixed ID (e.g., "fo/Recipe") in JSON output + - The label (e.g., "Recipe") is for human understanding only + ``` + +**Преимущества:** +Наиболее понятный формат для больших языковых моделей (LLM). +Сохраняет всю информацию. +Явно указывает, что использовать. + +**Недостатки:** +Более длинный запрос. +Более сложный шаблон. + +## Реализованный подход + +**Упрощенный формат "Сущность-Отношение-Атрибут"** - полностью заменяет старый формат на основе троек. + +Новый подход был выбран, потому что: + +1. **Отсутствие потери информации:** Оригинальные URI сохраняются корректно. +2. **Более простая логика:** Не требуется преобразование, прямые запросы к словарям работают. +3. **Безопасность пространств имен:** Обрабатывает несколько онтологий без конфликтов. +4. **Семантическая корректность:** Сохраняет семантику RDF/OWL. + +## Реализация завершена + +### Что было создано: + +1. **Новый шаблон запроса** (`prompts/ontology-extract-v2.txt`) + ✅ Четкие разделы: Типы сущностей, Отношения, Атрибуты. + ✅ Пример использования полных идентификаторов типов (`fo/Recipe`, `fo/has_ingredient`). + ✅ Инструкции по использованию точных идентификаторов из схемы. + ✅ Новый формат JSON с массивами сущностей/отношений/атрибутов. + +2. **Нормализация сущностей** (`entity_normalizer.py`) + ✅ `normalize_entity_name()` - Преобразует имена в формат, безопасный для URI. + ✅ `normalize_type_identifier()` - Обрабатывает слеши в типах (`fo/Recipe` → `fo-recipe`). + ✅ `build_entity_uri()` - Создает уникальные URI, используя кортеж (имя, тип). + ✅ `EntityRegistry` - Отслеживает сущности для исключения дубликатов. + +3. **JSON-парсер** (`simplified_parser.py`) + ✅ Парсит новый формат: `{entities: [...], relationships: [...], attributes: [...]}` + ✅ Поддерживает имена полей в формате kebab-case и snake_case. + ✅ Возвращает структурированные классы данных. + ✅ Корректная обработка ошибок с ведением журнала. + +4. **Тройной преобразователь** (`triple_converter.py`) + ✅ `convert_entity()` - Автоматически генерирует тройки типа + метки. + ✅ `convert_relationship()` - Соединяет URI сущностей через свойства. + ✅ `convert_attribute()` - Добавляет литеральные значения. + ✅ Выполняет поиск полных URI из определений онтологии. + +5. **Обновленный основной процессор** (`extract.py`) + ✅ Удален старый код извлечения на основе троек. + ✅ Добавлен метод `extract_with_simplified_format()`. + ✅ Теперь использует только новый упрощенный формат. + ✅ Вызывает запрос с идентификатором `extract-with-ontologies-v2`. + +## Тестовые примеры + +### Тест 1: Сохранение URI +```python +# Given ontology class +classes = {"fo/Recipe": {"uri": "http://purl.org/ontology/fo/Recipe", ...}} + +# When LLM returns +llm_output = {"subject": "x", "predicate": "rdf:type", "object": "fo/Recipe"} + +# Then expanded URI should be +assert expanded == "http://purl.org/ontology/fo/Recipe" +# Not: "https://trustgraph.ai/ontology/food#Recipe" +``` + +### Тест 2: Конфликт между несколькими онтологиями +```python +# Given two ontologies +ont1 = {"fo/Recipe": {...}} +ont2 = {"cooking/Recipe": {...}} + +# LLM should use full prefix to disambiguate +llm_output = {"object": "fo/Recipe"} # Not just "Recipe" +``` + +### Тест 3: Формат экземпляра сущности +```python +# Given prompt with food ontology +# LLM should create instances like +{"subject": "recipe:cornish-pasty"} # Namespace-style +{"subject": "food:beef"} # Consistent prefix +``` + +## Открытые вопросы + +1. **Следует ли экземплярам сущностей использовать префиксы пространств имен?** + Сейчас: `"recipe:cornish-pasty"` (произвольно) + Альтернатива: Использовать префикс онтологии `"fo:cornish-pasty"`? + Альтернатива: Без префикса, расширить в URI `"cornish-pasty"` → полный URI? + +2. **Как обрабатывать область определения/область значений в запросе?** + В настоящее время отображается: `(Recipe → Food)` + Должно ли быть: `(fo/Recipe → fo/Food)`? + +3. **Следует ли нам проверять ограничения области определения/области значений?** + TODO комментарий в extract.py:470 + Это позволило бы выявлять больше ошибок, но было бы сложнее. + +4. **Что касается обратных свойств и эквивалентностей?** + В онтологии есть `owl:inverseOf`, `owl:equivalentClass` + В настоящее время не используются при извлечении. + Следует ли их использовать? + +## Показатели успеха + +✅ Отсутствие потери информации об URI (100% сохранение исходных URI). +✅ Формат вывода LLM соответствует формату входных данных. +✅ Отсутствие неоднозначных примеров в запросе. +✅ Тесты проходят с использованием нескольких онтологий. +✅ Улучшенное качество извлечения (измеряется процентом допустимых троек). + +## Альтернативный подход: Упрощенный формат извлечения + +### Философия + +Вместо того, чтобы просить LLM понимать семантику RDF/OWL, попросите его делать то, что он умеет хорошо: **находить сущности и отношения в тексте**. + +Пусть код занимается построением URI, преобразованием в RDF и формальностями семантической паутины. + +### Пример: Классификация сущностей + +**Исходный текст:** +``` +Cornish pasty is a traditional British pastry filled with meat and vegetables. +``` + +**Схема онтологии (показана LLM):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food +``` + +**Что возвращает большая языковая модель (простой JSON):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + } + ] +} +``` + +**Что генерирует код (тройки RDF):** +```python +# 1. Normalize entity name + type to ID (type prevents collisions) +entity_id = "recipe-cornish-pasty" # normalize("Cornish pasty", "Recipe") +entity_uri = "https://trustgraph.ai/food/recipe-cornish-pasty" + +# Note: Same name, different type = different URI +# "Cornish pasty" (Recipe) → recipe-cornish-pasty +# "Cornish pasty" (Food) → food-cornish-pasty + +# 2. Generate triples +triples = [ + # Type triple + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/1999/02/22-rdf-syntax-ns#type", is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + # Label triple (automatic) + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/2000/01/rdf-schema#label", is_uri=True), + o=Value(value="Cornish pasty", is_uri=False) + ) +] +``` + +### Преимущества + +1. **LLM (большая языковая модель) не должна:** + Понимать синтаксис URI + Придумывать префиксы идентификаторов (`recipe:`, `ingredient:`) + Знать о `rdf:type` или `rdfs:label` + Конструировать идентификаторы семантической паутины + +2. **LLM просто должна:** + Находить сущности в тексте + Сопоставлять их с классами онтологии + Извлекать отношения и атрибуты + +3. **Код обрабатывает:** + Нормализацию и построение URI + Генерацию триплетов RDF + Автоматическое присвоение меток + Управление пространствами имен + +### Почему это работает лучше + +**Более простой запрос** = меньше путаницы = меньше ошибок +**Согласованные идентификаторы** = код контролирует правила нормализации +**Автоматически сгенерированные метки** = нет отсутствующих триплетов rdfs:label +**LLM фокусируется на извлечении** = на том, что она действительно хороша + +### Пример: Отношения между сущностями + +**Исходный текст:** +``` +Cornish pasty is a traditional British pastry filled with beef and potatoes. +``` + +**Схема онтологии (показана LLM):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food + +## Relationships: +- has_ingredient: Relates a recipe to an ingredient it uses (Recipe → Ingredient) +- food: Relates an ingredient to the food that is required (Ingredient → Food) +``` + +**Что возвращает большая языковая модель (простой JSON):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ] +} +``` + +**Что генерирует код (тройки RDF):** +```python +# Normalize entity names to URIs +cornish_pasty_uri = "https://trustgraph.ai/food/cornish-pasty" +beef_uri = "https://trustgraph.ai/food/beef" +potatoes_uri = "https://trustgraph.ai/food/potatoes" + +# Look up relation URI from ontology +has_ingredient_uri = "http://purl.org/ontology/fo/ingredients" # from fo/has_ingredient + +triples = [ + # Entity type triples (as before) + Triple(s=cornish_pasty_uri, p=rdf_type, o="http://purl.org/ontology/fo/Recipe"), + Triple(s=cornish_pasty_uri, p=rdfs_label, o="Cornish pasty"), + + Triple(s=beef_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=beef_uri, p=rdfs_label, o="beef"), + + Triple(s=potatoes_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=potatoes_uri, p=rdfs_label, o="potatoes"), + + # Relationship triples + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=beef_uri, is_uri=True) + ), + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=potatoes_uri, is_uri=True) + ) +] +``` + +**Основные моменты:** +LLM возвращает имена сущностей на естественном языке: `"Cornish pasty"`, `"beef"`, `"potatoes"` +LLM включает типы для устранения неоднозначности: `subject-type`, `object-type` +LLM использует имя отношения из схемы: `"has_ingredient"` +Код генерирует согласованные идентификаторы, используя (имя, тип): `("Cornish pasty", "Recipe")` → `recipe-cornish-pasty` +Код ищет URI отношения в онтологии: `fo/has_ingredient` → полный URI +Одна и та же (имя, тип) всегда получает один и тот же URI (дедупликация) + +### Пример: Разрешение неоднозначности имени сущности + +**Проблема:** Одно и то же имя может относиться к разным типам сущностей. + +**Реальный пример:** +``` +"Cornish pasty" can be: +- A Recipe (instructions for making it) +- A Food (the dish itself) +``` + +**Как это обрабатывается:** + +LLM возвращает оба элемента как отдельные сущности: +```json +{ + "entities": [ + {"entity": "Cornish pasty", "type": "Recipe"}, + {"entity": "Cornish pasty", "type": "Food"} + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "produces", + "object": "Cornish pasty", + "object-type": "Food" + } + ] +} +``` + +**Разрешение кода:** +```python +# Different types → different URIs +recipe_uri = normalize("Cornish pasty", "Recipe") +# → "https://trustgraph.ai/food/recipe-cornish-pasty" + +food_uri = normalize("Cornish pasty", "Food") +# → "https://trustgraph.ai/food/food-cornish-pasty" + +# Relationship connects them correctly +triple = Triple( + s=recipe_uri, # The Recipe + p="http://purl.org/ontology/fo/produces", + o=food_uri # The Food +) +``` + +**Почему это работает:** +Тип включен во ВСЕ ссылки (сущности, отношения, атрибуты). +Код использует кортеж `(name, type)` в качестве ключа поиска. +Отсутствие неоднозначности, отсутствие конфликтов. + +### Пример: Атрибуты сущности + +**Исходный текст:** +``` +This Cornish pasty recipe serves 4-6 people and takes 45 minutes to prepare. +``` + +**Схема онтологии (показана LLM):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method + +## Attributes: +- serves: Indicates what the recipe is intended to serve (Recipe → text) +- preparation_time: Time needed to prepare the recipe (Recipe → text) +``` + +**Что возвращает большая языковая модель (простой JSON):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty recipe", + "type": "Recipe" + } + ], + "attributes": [ + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4-6 people" + }, + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "preparation_time", + "value": "45 minutes" + } + ] +} +``` + +**Что генерирует код (тройки RDF):** +```python +# Normalize entity name to URI +recipe_uri = "https://trustgraph.ai/food/cornish-pasty-recipe" + +# Look up attribute URIs from ontology +serves_uri = "http://purl.org/ontology/fo/serves" # from fo/serves +prep_time_uri = "http://purl.org/ontology/fo/preparation_time" # from fo/preparation_time + +triples = [ + # Entity type triple + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdf_type, is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + + # Label triple (automatic) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdfs_label, is_uri=True), + o=Value(value="Cornish pasty recipe", is_uri=False) + ), + + # Attribute triples (objects are literals, not URIs) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=serves_uri, is_uri=True), + o=Value(value="4-6 people", is_uri=False) # Literal value! + ), + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=prep_time_uri, is_uri=True), + o=Value(value="45 minutes", is_uri=False) # Literal value! + ) +] +``` + +**Основные моменты:** +LLM извлекает строковые значения: `"4-6 people"`, `"45 minutes"` +LLM включает тип сущности для устранения неоднозначности: `entity-type` +LLM использует имя атрибута из схемы: `"serves"`, `"preparation_time"` +Код ищет URI атрибута из свойств типа данных онтологии +**Объект является строковым значением** (`is_uri=False`), а не ссылкой URI +Значения остаются в виде обычного текста, нормализация не требуется + +**Различия с отношениями:** +Отношения: и субъект, и объект являются сущностями (URI) +Атрибуты: субъект является сущностью (URI), объект является строковым значением (строка/число) + +### Полный пример: Сущности + Отношения + Атрибуты + +**Исходный текст:** +``` +Cornish pasty is a savory pastry filled with beef and potatoes. +This recipe serves 4 people. +``` + +**Что возвращает большая языковая модель:** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ], + "attributes": [ + { + "entity": "Cornish pasty", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4 people" + } + ] +} +``` + +**Результат:** Сгенерировано 11 тройных наборов RDF: +3 тройных набора, определяющих тип сущности (rdf:type) +3 тройных набора, определяющих метку сущности (rdfs:label) - автоматически +2 тройных набора, описывающих отношения (has_ingredient) +1 тройной набор, описывающий атрибут (serves) + +Все это получено из простых, естественных текстовых извлечений с помощью LLM! + +## Ссылки + +Текущая реализация: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` +Шаблон запроса: `ontology-prompt.md` +Тестовые примеры: `tests/unit/test_extract/test_ontology/` +Пример онтологии: `e2e/test-data/food.ontology` diff --git a/docs/tech-specs/ontology-extract-phase-2.sw.md b/docs/tech-specs/ontology-extract-phase-2.sw.md new file mode 100644 index 00000000..ad965e02 --- /dev/null +++ b/docs/tech-specs/ontology-extract-phase-2.sw.md @@ -0,0 +1,761 @@ +# Dondoo la Maarifa la Ontolojia - Awamu ya 2 ya Urekebishaji + +**Hali**: Rasimu +**Mwandishi**: Mkutano wa Uchambuzi wa 2025-12-03 +**Inahusiana na**: `ontology.md`, `ontorag.md` + +## Muhtasari + +Hati hii inataja kutofautiana katika mfumo wa sasa wa dondoo la maarifa unaotegemea ontolojia na inapendekeza urekebishaji ili kuboresha utendaji wa LLM na kupunguza upotevu wa habari. + +## Utendaji wa Sasa + +### Inavyofanya Sasa + +1. **Kupakia Ontolojia** (`ontology_loader.py`) + Inapakia JSON ya ontolojia na vitufe kama `"fo/Recipe"`, `"fo/Food"`, `"fo/produces"` + Nambari za darasa zina jalizi la nafasi katika kitufe yenyewe + Mfano kutoka `food.ontology`: + ```json + "classes": { + "fo/Recipe": { + "uri": "http://purl.org/ontology/fo/Recipe", + "rdfs:comment": "A Recipe is a combination..." + } + } + ``` + +2. **Uundaji wa Maagizo** (`extract.py:299-307`, `ontology-prompt.md`) + Kiolezo kinapokea dictionaries `classes`, `object_properties`, `datatype_properties` + Kiolezo huchanganua: `{% for class_id, class_def in classes.items() %}` + LLM inaona: `**fo/Recipe**: A Recipe is a combination...` + Muundo wa mfano wa matokeo unaonyesha: + ```json + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} + {"subject": "recipe:cornish-pasty", "predicate": "has_ingredient", "object": "ingredient:flour"} + ``` + +3. **Uchambuzi wa Majibu** (`extract.py:382-428`) + Inatarajia safu ya JSON: `[{"subject": "...", "predicate": "...", "object": "..."}]` + Inathibitisha dhidi ya sehemu ya ontolojia + Inapanua URI kupitia `expand_uri()` (extract.py:473-521) + +4. **Upanuzi wa URI** (`extract.py:473-521`) + Inangalia ikiwa thamani iko katika kamusi `ontology_subset.classes` + Ikiwa imepatikana, inatoa URI kutoka kwenye ufafanuzi wa darasa + Ikiwa haijapatikana, inaunda URI: `f"https://trustgraph.ai/ontology/{ontology_id}#{value}"` + +### Mfano wa Mtiririko wa Data + +**Ontolojia ya JSON → Mpakuzi → Ombi:** +``` +"fo/Recipe" → classes["fo/Recipe"] → LLM sees "**fo/Recipe**" +``` + +**LLM → Mfumo wa Uchambuzi → Matokeo:** +``` +"Recipe" → not in classes["fo/Recipe"] → constructs URI → LOSES original URI +"fo/Recipe" → found in classes → uses original URI → PRESERVES URI +``` + +## Matatizo Yaliyobainika + +### 1. **Mfano Usiofuata Kanuni katika Maagizo** + +**Tatizo**: Kiolezo cha maagizo huonyesha vitambulisho vya darasa na mabainisha (`fo/Recipe`) lakini matokeo ya mfano hutumia majina ya darasa yasiyo na mabainisha (`Recipe`). + +**Mahali**: `ontology-prompt.md:5-52` + +```markdown +## Ontology Classes: +- **fo/Recipe**: A Recipe is... + +## Example Output: +{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} +``` + +**Athari**: Mfumo wa lugha (LLM) hupokea ishara tofauti kuhusu muundo ambao unapaswa kutumika. + +### 2. **Upatanishi wa Habari katika Upanuzi wa URI** + +**Tatizo**: Wakati LLM hurudisha majina ya darasa ambayo hayana alama ya mbele, kama ilivyoelezwa katika mfano, `expand_uri()` hayawezi kuyakuta katika kamusi ya ontolojia na huunda URI za dharura, na kusababisha kupoteza URI za asili. + +**Mahali**: `extract.py:494-500` + +```python +if value in ontology_subset.classes: # Looks for "Recipe" + class_def = ontology_subset.classes[value] # But key is "fo/Recipe" + if isinstance(class_def, dict) and 'uri' in class_def: + return class_def['uri'] # Never reached! +return f"https://trustgraph.ai/ontology/{ontology_id}#{value}" # Fallback +``` + +**Athari**: +URI asili: `http://purl.org/ontology/fo/Recipe` +URI iliyoundwa: `https://trustgraph.ai/ontology/food#Recipe` +Maana ya kielelezo yamepotea, husababisha kutofanya kazi kwa pamoja. + +### 3. **Muundo Usio Wazi wa Eneo la Kitu** + +**Tatizo**: Hakuna mwongozo wazi kuhusu muundo wa URI ya eneo la kitu. + +**Mfano katika maagizo**: +`"recipe:cornish-pasty"` (kielezi kama kielezi) +`"ingredient:flour"` (kielezi tofauti) + +**Tabia halisi** (extract.py:517-520): +```python +# Treat as entity instance - construct unique URI +normalized = value.replace(" ", "-").lower() +return f"https://trustgraph.ai/{ontology_id}/{normalized}" +``` + +**Athari**: Mfumo wa lugha (LLM) lazima ajue mbinu ya kuweka alama (prefixing) bila kuwa na msingi wa elimu (ontology). + +### 4. **Hakuna Maelekezo ya Mbele ya Nafasi (Namespace)** + +**Tatizo**: Faili ya JSON ya elimu ina maelezo ya nafasi (namespace) (kwa mstari wa 10-25 katika food.ontology): +```json +"namespaces": { + "fo": "http://purl.org/ontology/fo/", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + ... +} +``` + +Lakini mistari hii haionyeshwi kwa mfumo wa lugha (LLM). MFUMO WA LUGHA (LLM) haujua: +Maana ya "fo" +Njia gani ya kutumia kwa vitu +Nafasi gani inayotumika kwa vipengele + +### 5. **Lebo Ambazo Hazitumiki katika Swali** + +**Tatizo**: Kila darasa lina sehemu za `rdfs:label` (k.m., `{"value": "Recipe", "lang": "en-gb"}`), lakini kigezo cha swali haziitumii. + +**Hali ya sasa**: Inaonyesha tu `class_id` na `comment` +```jinja +- **{{class_id}}**{% if class_def.comment %}: {{class_def.comment}}{% endif %} +``` + +**Inapatikana lakini haitumiki:** +```python +"rdfs:label": [{"value": "Recipe", "lang": "en-gb"}] +``` + +**Athari**: Inaweza kutoa majina ambayo yanaweza kueleweka kwa binadamu pamoja na vitambulisho vya kiufundi. + +## Suluhisho Zilizopendekezwa + +### Chaguo A: Kuweka Vipengele sawa na Vitambulisho visivyo na Mbele + +**Mbinu**: Ondoa mbele kutoka kwa vitambulisho vya darasa kabla ya kuviwasha kwa mfumo wa akili bandia (LLM). + +**Mabadiliko**: +1. Badilisha `build_extraction_variables()` ili kubadilisha funguo: + ```python + classes_for_prompt = { + k.split('/')[-1]: v # "fo/Recipe" → "Recipe" + for k, v in ontology_subset.classes.items() + } + ``` + +2. Sasisha mfano wa maagizo ili ufanane (tayari hutumia majina yasiyo na alama). + +3. Badilisha `expand_uri()` ili iweze kushughulikia aina zote mbili: + ```python + # Try exact match first + if value in ontology_subset.classes: + return ontology_subset.classes[value]['uri'] + + # Try with prefix + for prefix in ['fo/', 'rdf:', 'rdfs:']: + prefixed = f"{prefix}{value}" + if prefixed in ontology_subset.classes: + return ontology_subset.classes[prefixed]['uri'] + ``` + +**Faida:** +Safi zaidi, rahisi zaidi kusoma na kuelewa. +Inafanana na mifano iliyopo ya maagizo. +Mifumo ya lugha kubwa (LLMs) hufanya kazi vizuri zaidi na alama (tokens) rahisi. + +**Hasara:** +Migongano ya majina ya madarasa ikiwa ontolojia nyingi zina jina sawa la darasa. +Inapoteza habari ya nafasi (namespace). +Inahitaji mantiki ya dharura kwa utafutaji. + +### Chaguo B: Tumia Kitambulisho Kamili Chenye Alama (Prefix) kwa Ufanisi + +**Mbinu:** Sasisha mifano ili kutumia kitambulisho chenye alama kinacholingana na kile kinachoonyeshwa katika orodha ya madarasa. + +**Mabadiliko:** +1. Sasisha mfano wa agizo (ontology-prompt.md:46-52): + ```json + [ + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "fo/Recipe"}, + {"subject": "recipe:cornish-pasty", "predicate": "rdfs:label", "object": "Cornish Pasty"}, + {"subject": "recipe:cornish-pasty", "predicate": "fo/produces", "object": "food:cornish-pasty"}, + {"subject": "food:cornish-pasty", "predicate": "rdf:type", "object": "fo/Food"} + ] + ``` + +2. Ongeza maelezo ya nafasi ya kazi kwenye swali: + ```markdown + ## Namespace Prefixes: + - **fo/**: Food Ontology (http://purl.org/ontology/fo/) + - **rdf:**: RDF Schema + - **rdfs:**: RDF Schema + + Use these prefixes exactly as shown when referencing classes and properties. + ``` + +3. Acha `expand_uri()` kama ilivyo (hufanya kazi vizuri wakati mechi zinapopatikana). + +**Faida:** +Ulinganisho kati ya ingizo na pato. +Hakuna upotevu wa habari. +Inahifadhi maana ya nafasi (namespace). +Inafanya kazi na ontolojia nyingi. + +**Hasara:** +Alama (tokens) zaidi kwa LLM. +Inahitaji LLM kufuatilia alama za mbele (prefixes). + +### Chaguo C: Mchanganyiko - Onyesha Lebo na Kitambulisho (ID) + +**Mbinu:** Ongeza maagizo katika swali ili kuonyesha lebo zinazoweza kusomwa na binadamu na kitambulisho (ID) cha kiufundi. + +**Mabadiliko:** +1. Sasisha mfumo wa swali: + ```jinja + {% for class_id, class_def in classes.items() %} + - **{{class_id}}** (label: "{{class_def.labels[0].value if class_def.labels else class_id}}"){% if class_def.comment %}: {{class_def.comment}}{% endif %} + {% endfor %} + ``` + + Matokeo ya mfano: + ```markdown + - **fo/Recipe** (label: "Recipe"): A Recipe is a combination... + ``` + +2. Maelekezo ya sasisho: + ```markdown + When referencing classes: + - Use the full prefixed ID (e.g., "fo/Recipe") in JSON output + - The label (e.g., "Recipe") is for human understanding only + ``` + +**Faida:** +Inafaa zaidi kwa mifumo ya lugha kubwa (LLM). +Inahifadhi habari yote. +Inaeleza wazi ni nini kinachotakiwa kutumika. + +**Hasara:** +Ombi refu zaidi. +Mfumo mgumu zaidi. + +## Njia Iliyotekelezwa + +**Muundo Ulioboreshwa wa Muhusiano wa Vitu na Sifa** - unaibadilisha kabisa mfumo wa zamani unaotegemea triplet. + +Njia mpya ilichaguliwa kwa sababu: + +1. **Hakuna Upotevu wa Habari:** Anwani za mtandaoni (URIs) za awali zinaendelea kuhifadhiwa kwa usahihi. +2. **Mantiki Rahisi:** Hakuna mabadiliko yanayohitajika, utafutaji wa moja kwa moja wa kamusi unafanya kazi. +3. **Usalama wa Nafasi:** Inashughulikia ontolojia nyingi bila migongano. +4. **Ukweli wa Kisia:** Inahifadhi maana ya RDF/OWL. + +## Utendaji Uliofanyika + +### Kilichojengwa: + +1. **Mfumo Mpya wa Ombi** (`prompts/ontology-extract-v2.txt`) + ✅ Sehemu zilizoelezwa wazi: Aina za Vitu, Mahusiano, Sifa. + ✅ Mfano unaotumia kitambulisho kamili cha aina (`fo/Recipe`, `fo/has_ingredient`). + ✅ Maelekezo ya kutumia kitambulisho halisi kutoka kwa schema. + ✅ Muundo mpya wa JSON na safu za vitu/mahusiano/sifa. + +2. **Urekebishaji wa Vitu** (`entity_normalizer.py`) + ✅ `normalize_entity_name()` - Inabadilisha majina kuwa muundo salama wa URI. + ✅ `normalize_type_identifier()` - Inashughulikia alama za upande katika aina (`fo/Recipe` → `fo-recipe`). + ✅ `build_entity_uri()` - Inaunda anwani za kipekee (URIs) kwa kutumia jozi (jina, aina). + ✅ `EntityRegistry` - Inafuatilia vitu ili kuepuka marudia. + +3. **Mchangamizi wa JSON** (`simplified_parser.py`) + ✅ Inachanganua muundo mpya: `{entities: [...], relationships: [...], attributes: [...]}`. + ✅ Inasaidia majina ya sehemu katika muundo wa kebab na muundo wa nyoka. + ✅ Inarudisha madarasa ya data iliyopangwa. + ✅ Usimamizi wa makosa kwa njia nzuri pamoja na uandishi wa matukio. + +4. **Mabadilishaji wa Triplet** (`triple_converter.py`) + ✅ `convert_entity()` - Inaunda triplet za aina + lebo moja kwa moja. + ✅ `convert_relationship()` - Inaunganisha anwani za vitu (URIs) kupitia sifa. + ✅ `convert_attribute()` - Inaongeza maadili ya moja kwa moja. + ✅ Inatafuta anwani kamili kutoka kwa maelezo ya ontolojia. + +5. **Mchakato Mkuu Uliosasishwa** (`extract.py`) + ✅ Imeondoa msimbo wa zamani wa uondoaji wa triplet. + ✅ Imeongeza `extract_with_simplified_format()`. + ✅ Sasa inatumia tu muundo uliorahisishwa. + ✅ Inaitisha ombi na kitambulisho `extract-with-ontologies-v2`. + +## Majaribio + +### Jaribio la 1: Uhifadhi wa URI +```python +# Given ontology class +classes = {"fo/Recipe": {"uri": "http://purl.org/ontology/fo/Recipe", ...}} + +# When LLM returns +llm_output = {"subject": "x", "predicate": "rdf:type", "object": "fo/Recipe"} + +# Then expanded URI should be +assert expanded == "http://purl.org/ontology/fo/Recipe" +# Not: "https://trustgraph.ai/ontology/food#Recipe" +``` + +### Mtihani wa 2: Mzozo wa Ontolojia Nyingi +```python +# Given two ontologies +ont1 = {"fo/Recipe": {...}} +ont2 = {"cooking/Recipe": {...}} + +# LLM should use full prefix to disambiguate +llm_output = {"object": "fo/Recipe"} # Not just "Recipe" +``` + +### Mtihani wa 3: Muundo wa Eneo la Mfano +```python +# Given prompt with food ontology +# LLM should create instances like +{"subject": "recipe:cornish-pasty"} # Namespace-style +{"subject": "food:beef"} # Consistent prefix +``` + +## Maswali ya Kufungua + +1. **Je, vipozi vya mifano ya vitu vinapaswa kutumia mbele za nafasi?** + Sasa: `"recipe:cornish-pasty"` (ya hiari) + Mbadala: Je, kutumia mbele ya ontolojia `"fo:cornish-pasty"`? + Mbadala: Hakuna mbele, kupanua katika URI `"cornish-pasty"` → URI kamili? + +2. **Jinsi ya kushughulikia uwanja/jukumu katika swali?** + Kwa sasa inaonyesha: `(Recipe → Food)` + Je, inapaswa kuwa: `(fo/Recipe → fo/Food)`? + +3. **Je, tunapaswa kuthibitisha vikwazo vya uwanja/jukumu?** + TODO maoni katika extract.py:470 + Itakamata makosa zaidi lakini ni ngumu zaidi + +4. **Hebu kuhusu sifa za kinyume na usawa?** + Ontolojia ina `owl:inverseOf`, `owl:equivalentClass` + Hasa haitumiki katika uondoaji + Je, inapaswa kutumika? + +## Viashiria vya Mafanikio + +✅ Hakuna upotevu wa habari ya URI (uhifadhi wa 100% wa URI za awali) +✅ Muundo wa pato la LLM unalingana na muundo wa ingizo +✅ Hakuna mifano ya kusumbua katika swali +✅ Vipimo hufanikiwa na ontolojia nyingi +✅ Ubora wa uondoaji ulioboreshwa (uliofanywa na asilimia ya triple halali) + +## Mbinu Mbadala: Muundo Ulioboreshwa wa Uondoaji + +### Falsafa + +Badala ya kuuliza LLM kuelewa maana ya RDF/OWL, waulize ifanye kile ambacho ni nzuri: **kutafuta vitu na uhusiano katika maandishi**. + +Acha msimbo kushughulikia uundaji wa URI, ubadilishaji wa RDF, na mambo rasmi ya wavuti ya kiakili. + +### Mfano: Uainishaji wa Vitu + +**Maandishi ya Ingizo:** +``` +Cornish pasty is a traditional British pastry filled with meat and vegetables. +``` + +**Muundo wa Ontolojia (unaonyeshwa kwa mfumo wa lugha kubwa):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food +``` + +**Kinachorudishwa na Mfumo wa Lugha Kubwa (JSON Rahisi):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + } + ] +} +``` + +**Ni Nini Ambo Inazalisha (Triple za RDF):** +```python +# 1. Normalize entity name + type to ID (type prevents collisions) +entity_id = "recipe-cornish-pasty" # normalize("Cornish pasty", "Recipe") +entity_uri = "https://trustgraph.ai/food/recipe-cornish-pasty" + +# Note: Same name, different type = different URI +# "Cornish pasty" (Recipe) → recipe-cornish-pasty +# "Cornish pasty" (Food) → food-cornish-pasty + +# 2. Generate triples +triples = [ + # Type triple + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/1999/02/22-rdf-syntax-ns#type", is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + # Label triple (automatic) + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/2000/01/rdf-schema#label", is_uri=True), + o=Value(value="Cornish pasty", is_uri=False) + ) +] +``` + +### Faida + +1. **LLM haihitaji:** + Kuelewa sintaksia ya URI + Kuunda mbele za kitambulisho (`recipe:`, `ingredient:`) + Kujua kuhusu `rdf:type` au `rdfs:label` + Kuunda kitambulisho cha mtandao wa maana + +2. **LLM inahitaji tu:** + Kupata vitu katika maandishi + Kuviweka katika madarasa ya ontolojia + Kuchukua uhusiano na sifa + +3. **Msimbo hushughulikia:** + Usanifu na uundaji wa URI + Uzalishaji wa triple za RDF + Uwekaji wa kiotomatiki wa lebo + Usimamizi wa nafasi + +### Kwa Nini Hii Inafanya Vyema + +**Swali rahisi** = uchanganyifu mdogo = makosa machache +**Kitambulisho thabiti** = msimbo udhibiti sheria za usanifu +**Lebo zilizozalishwa kiotomatiki** = hakuna triple za rdfs:label zilizopotea +**LLM inazingatia uondoaji** = ambayo ni jambo ambalo inafaa + +### Mfano: Uhusiano wa Vitu + +**Maandishi ya Ingizo:** +``` +Cornish pasty is a traditional British pastry filled with beef and potatoes. +``` + +**Muundo wa Ontolojia (unaonyeshwa kwa LLM):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food + +## Relationships: +- has_ingredient: Relates a recipe to an ingredient it uses (Recipe → Ingredient) +- food: Relates an ingredient to the food that is required (Ingredient → Food) +``` + +**Kinachorudishwa na Mfumo wa Lugha Kubwa (JSON Rahisi):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ] +} +``` + +**Ni Nini Ambo Inazalisha (Triple za RDF):** +```python +# Normalize entity names to URIs +cornish_pasty_uri = "https://trustgraph.ai/food/cornish-pasty" +beef_uri = "https://trustgraph.ai/food/beef" +potatoes_uri = "https://trustgraph.ai/food/potatoes" + +# Look up relation URI from ontology +has_ingredient_uri = "http://purl.org/ontology/fo/ingredients" # from fo/has_ingredient + +triples = [ + # Entity type triples (as before) + Triple(s=cornish_pasty_uri, p=rdf_type, o="http://purl.org/ontology/fo/Recipe"), + Triple(s=cornish_pasty_uri, p=rdfs_label, o="Cornish pasty"), + + Triple(s=beef_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=beef_uri, p=rdfs_label, o="beef"), + + Triple(s=potatoes_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=potatoes_uri, p=rdfs_label, o="potatoes"), + + # Relationship triples + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=beef_uri, is_uri=True) + ), + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=potatoes_uri, is_uri=True) + ) +] +``` + +**Pointi Muhimu:** +LLM hurudia majina ya vitu katika lugha ya asili: `"Cornish pasty"`, `"beef"`, `"potatoes"` +LLM hujumuisha aina ili kufafanua: `subject-type`, `object-type` +LLM hutumia jina la uhusiano kutoka kwa schema: `"has_ingredient"` +Msimbo hutengeneza vitambulisho vinavyolingana kwa kutumia (jina, aina): `("Cornish pasty", "Recipe")` → `recipe-cornish-pasty` +Msimbo hutafuta URI ya uhusiano kutoka kwa ontolojia: `fo/has_ingredient` → URI kamili +Jozi sawa (jina, aina) daima hupata URI sawa (kuondoa marudia) + +### Mfano: Utambuzi wa Jina la Kitu + +**Tatizo:** Jina lile lile linaweza kurejelea aina tofauti za vitu. + +**Mfano halisi:** +``` +"Cornish pasty" can be: +- A Recipe (instructions for making it) +- A Food (the dish itself) +``` + +**Jinsi Inavyoshughuliwa:** + +Mfumo wa lugha kubwa (LLM) hurudisha yote kama vitu tofauti: +```json +{ + "entities": [ + {"entity": "Cornish pasty", "type": "Recipe"}, + {"entity": "Cornish pasty", "type": "Food"} + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "produces", + "object": "Cornish pasty", + "object-type": "Food" + } + ] +} +``` + +**Suluhisho la Msimbo:** +```python +# Different types → different URIs +recipe_uri = normalize("Cornish pasty", "Recipe") +# → "https://trustgraph.ai/food/recipe-cornish-pasty" + +food_uri = normalize("Cornish pasty", "Food") +# → "https://trustgraph.ai/food/food-cornish-pasty" + +# Relationship connects them correctly +triple = Triple( + s=recipe_uri, # The Recipe + p="http://purl.org/ontology/fo/produces", + o=food_uri # The Food +) +``` + +**Kwa Nini Hifanya Kazi:** +Aina (type) imejumuishwa katika marejeleo yote (vitu, uhusiano, sifa). +Msimbo hutumia `(name, type)` kama ufunguo wa utafutaji. +Hakuna ukosefu wa uwazi, hakuna migongano. + +### Mifano: Sifa za Vitu + +**Nakala ya Ingizo:** +``` +This Cornish pasty recipe serves 4-6 people and takes 45 minutes to prepare. +``` + +**Muundo wa Ontolojia (unaonyeshwa kwa LLM):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method + +## Attributes: +- serves: Indicates what the recipe is intended to serve (Recipe → text) +- preparation_time: Time needed to prepare the recipe (Recipe → text) +``` + +**Kinachorudishwa na Mfumo wa Lugha Kubwa (JSON Rahisi):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty recipe", + "type": "Recipe" + } + ], + "attributes": [ + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4-6 people" + }, + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "preparation_time", + "value": "45 minutes" + } + ] +} +``` + +**Ni Nini Ambo Inazalisha (Triple za RDF):** +```python +# Normalize entity name to URI +recipe_uri = "https://trustgraph.ai/food/cornish-pasty-recipe" + +# Look up attribute URIs from ontology +serves_uri = "http://purl.org/ontology/fo/serves" # from fo/serves +prep_time_uri = "http://purl.org/ontology/fo/preparation_time" # from fo/preparation_time + +triples = [ + # Entity type triple + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdf_type, is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + + # Label triple (automatic) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdfs_label, is_uri=True), + o=Value(value="Cornish pasty recipe", is_uri=False) + ), + + # Attribute triples (objects are literals, not URIs) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=serves_uri, is_uri=True), + o=Value(value="4-6 people", is_uri=False) # Literal value! + ), + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=prep_time_uri, is_uri=True), + o=Value(value="45 minutes", is_uri=False) # Literal value! + ) +] +``` + +**Pointi Muhimu:** +LLM huchukua maadili halisi: `"4-6 people"`, `"45 minutes"` +LLM hujumuisha aina ya kitu ili kuepusha utofauti: `entity-type` +LLM hutumia jina la sifa kutoka kwa schema: `"serves"`, `"preparation_time"` +Msimbo hutafuta URI ya sifa kutoka kwa sifa za aina ya ontology +**Kitu ni halali** (`is_uri=False`), si rejea la URI +Maadili husalia kama maandishi ya asili, hakuna haja ya urekebishaji + +**Tofauti na Mahusiano:** +Mahusiano: kitu cha kwanza na cha pili ni vitu (URIs) +Sifa: kitu cha kwanza ni kitu (URI), kitu cha pili ni thamani halali (mstari/nambari) + +### Mfano Kamili: Vitu + Mahusiano + Sifa + +**Maandishi ya Ingizo:** +``` +Cornish pasty is a savory pastry filled with beef and potatoes. +This recipe serves 4 people. +``` + +**Hili Ni Lile Ambalo Mfumo wa Lugha Kubwa Hurudisha:** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ], + "attributes": [ + { + "entity": "Cornish pasty", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4 people" + } + ] +} +``` + +**Matokeo:** Triple 11 za RDF zilizoundwa: +Triple 3 za aina ya kitu (rdf:type) +Triple 3 za lebo ya kitu (rdfs:label) - moja kwa moja +Triple 2 za uhusiano (ina_viungo) +Triple 1 ya sifa (inafaa) + +Yote kutoka kwa uundaji rahisi, wa lugha ya asili na mfumo wa akili bandia (LLM)! + +## Marejeleo + +Utaratibu wa sasa: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` +Mfumo wa swali: `ontology-prompt.md` +Majaribio: `tests/unit/test_extract/test_ontology/` +Ontolojia ya mfano: `e2e/test-data/food.ontology` diff --git a/docs/tech-specs/ontology-extract-phase-2.tr.md b/docs/tech-specs/ontology-extract-phase-2.tr.md new file mode 100644 index 00000000..58c6c02a --- /dev/null +++ b/docs/tech-specs/ontology-extract-phase-2.tr.md @@ -0,0 +1,761 @@ +# Ontoloji Bilgi Çıkarma - 2. Aşama Yeniden Düzenleme + +**Durum**: Taslak +**Yazar**: Analiz Oturumu 2025-12-03 +**İlgili**: `ontology.md`, `ontorag.md` + +## Genel Bakış + +Bu belge, mevcut ontoloji tabanlı bilgi çıkarma sistemindeki tutarsızlıkları belirlemektedir ve LLM performansını iyileştirmek ve bilgi kaybını azaltmak için bir yeniden düzenleme önermektedir. + +## Mevcut Uygulama + +### Şu Anda Nasıl Çalışıyor + +1. **Ontoloji Yükleme** (`ontology_loader.py`) + `"fo/Recipe"`, `"fo/Food"`, `"fo/produces"` gibi anahtarlara sahip ontoloji JSON'unu yükler. + Sınıf kimlikleri, anahtar içinde namespace önekini içerir. + `food.ontology`'dan bir örnek: + ```json + "classes": { + "fo/Recipe": { + "uri": "http://purl.org/ontology/fo/Recipe", + "rdfs:comment": "A Recipe is a combination..." + } + } + ``` + +2. **İstem Oluşturma** (`extract.py:299-307`, `ontology-prompt.md`) + Şablon, `classes`, `object_properties`, `datatype_properties` sözlüklerini alır. + Şablon döngüye girer: `{% for class_id, class_def in classes.items() %}` + LLM (Büyük Dil Modeli) şunları görür: `**fo/Recipe**: A Recipe is a combination...` + Örnek çıktı formatı şöyledir: + ```json + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} + {"subject": "recipe:cornish-pasty", "predicate": "has_ingredient", "object": "ingredient:flour"} + ``` + +3. **Yanıt Ayrıştırma** (`extract.py:382-428`) + JSON dizisi beklenir: `[{"subject": "...", "predicate": "...", "object": "..."}]` + Ontoloji alt kümesine göre doğrulanır. + URI'lar `expand_uri()` aracılığıyla genişletilir (extract.py:473-521). + +4. **URI Genişletme** (`extract.py:473-521`) + Değerin `ontology_subset.classes` sözlüğünde olup olmadığını kontrol eder. + Bulunursa, URI sınıf tanımından çıkarılır. + Bulunmazsa, URI oluşturulur: `f"https://trustgraph.ai/ontology/{ontology_id}#{value}"` + +### Veri Akışı Örneği + +**Ontoloji JSON → Yükleyici → İstek:** +``` +"fo/Recipe" → classes["fo/Recipe"] → LLM sees "**fo/Recipe**" +``` + +**LLM → Ayrıştırıcı → Çıktı:** +``` +"Recipe" → not in classes["fo/Recipe"] → constructs URI → LOSES original URI +"fo/Recipe" → found in classes → uses original URI → PRESERVES URI +``` + +## Belirlenen Sorunlar + +### 1. **İstemde Tutarsız Örnekler** + +**Sorun**: İstem şablonu, sınıf kimliklerini öneklerle (`fo/Recipe`) gösterirken, örnek çıktı önek kullanılmayan sınıf adlarını kullanır (`Recipe`). + +**Konum**: `ontology-prompt.md:5-52` + +```markdown +## Ontology Classes: +- **fo/Recipe**: A Recipe is... + +## Example Output: +{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} +``` + +**Etki**: LLM, hangi formatı kullanması gerektiği konusunda çelişkili sinyaller alır. + +### 2. **URI Genişletmesinde Bilgi Kaybı** + +**Sorun**: LLM, örneğe uygun olarak önekli olmayan sınıf adları döndürdüğünde, `expand_uri()` bunları ontoloji sözlüğünde bulamaz ve yedek URI'ler oluşturur, böylece orijinal doğru URI'ler kaybolur. + +**Konum**: `extract.py:494-500` + +```python +if value in ontology_subset.classes: # Looks for "Recipe" + class_def = ontology_subset.classes[value] # But key is "fo/Recipe" + if isinstance(class_def, dict) and 'uri' in class_def: + return class_def['uri'] # Never reached! +return f"https://trustgraph.ai/ontology/{ontology_id}#{value}" # Fallback +``` + +**Etki:** +Orijinal URI: `http://purl.org/ontology/fo/Recipe` +Oluşturulmuş URI: `https://trustgraph.ai/ontology/food#Recipe` +Anlamsal anlam kayboluyor, birlikte çalışabilirlik bozuluyor. + +### 3. **Belirsiz Varlık Örneği Biçimi** + +**Sorun:** Varlık örneği URI biçimi hakkında net bir rehberlik yok. + +**İpuçlarındaki örnekler:** +`"recipe:cornish-pasty"` (namespace benzeri önek) +`"ingredient:flour"` (farklı önek) + +**Gerçek davranış** (extract.py:517-520): +```python +# Treat as entity instance - construct unique URI +normalized = value.replace(" ", "-").lower() +return f"https://trustgraph.ai/{ontology_id}/{normalized}" +``` + +**Etki**: LLM'nin, herhangi bir ontoloji bağlamı olmadan, önekleme kuralını tahmin etmesi gerekir. + +### 4. **Ada Alanı Önekleri Hakkında Rehberlik Yok** + +**Sorun**: Ontoloji JSON dosyası, ada alanı tanımlarını içerir (food.ontology dosyasının 10-25. satırları): +```json +"namespaces": { + "fo": "http://purl.org/ontology/fo/", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + ... +} +``` + +Ancak bunlar asla LLM'ye iletilmez. LLM şunları bilmez: +"fo" kelimesinin ne anlama geldiğini +Varlıklar için hangi öneklerin kullanılması gerektiğini +Hangi ad alanının hangi öğelere uygulandığını + +### 5. **İpuçunda Kullanılmayan Etiketler** + +**Sorun**: Her sınıfın `rdfs:label` alanları vardır (örneğin, `{"value": "Recipe", "lang": "en-gb"}`), ancak ipucu şablonu bunları kullanmaz. + +**Mevcut durum**: Sadece `class_id` ve `comment` gösteriliyor. +```jinja +- **{{class_id}}**{% if class_def.comment %}: {{class_def.comment}}{% endif %} +``` + +**Kullanılabilir ancak kullanılmayan:** +```python +"rdfs:label": [{"value": "Recipe", "lang": "en-gb"}] +``` + +**Etki**: Teknik kimliklerin yanı sıra insan tarafından okunabilir isimler sağlayabilir. + +## Önerilen Çözümler + +### Seçenek A: Önek Olmayan Kimliklere Normalleştirme + +**Yaklaşım**: Sınıf kimliklerinden önekleri, LLM'ye göstermeden önce kaldırın. + +**Değişiklikler**: +1. `build_extraction_variables()`'ı, anahtarları dönüştürmek için değiştirin: + ```python + classes_for_prompt = { + k.split('/')[-1]: v # "fo/Recipe" → "Recipe" + for k, v in ontology_subset.classes.items() + } + ``` + +2. İstem örneğini, (zaten önek kullanmayan) mevcut duruma uygun hale getirin. + +3. `expand_uri()`'ı, her iki formatı da işleyebilecek şekilde değiştirin: + ```python + # Try exact match first + if value in ontology_subset.classes: + return ontology_subset.classes[value]['uri'] + + # Try with prefix + for prefix in ['fo/', 'rdf:', 'rdfs:']: + prefixed = f"{prefix}{value}" + if prefixed in ontology_subset.classes: + return ontology_subset.classes[prefixed]['uri'] + ``` + +**Artıları:** +Daha temiz, daha insan tarafından okunabilir +Mevcut örnek istemlerle eşleşir +Büyük dil modelleri (LLM'ler), daha basit belirteçlerle daha iyi çalışır + +**Eksileri:** +Birden fazla ontolojinin aynı sınıf adına sahip olması durumunda sınıf adı çakışmaları +Ad alanı bilgilerini kaybettirir +Arama işlemlerinde yedekleme mantığı gerektirir + +### B Seçeneği: Tam Önekli Kimlikleri Tutarlı Bir Şekilde Kullanın + +**Yaklaşım:** Örnekleri, sınıf listesinde gösterilenlerle eşleşen önekli kimlikleri kullanacak şekilde güncelleyin. + +**Değişiklikler:** +1. Örnek istemi güncelleyin (ontology-prompt.md:46-52): + ```json + [ + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "fo/Recipe"}, + {"subject": "recipe:cornish-pasty", "predicate": "rdfs:label", "object": "Cornish Pasty"}, + {"subject": "recipe:cornish-pasty", "predicate": "fo/produces", "object": "food:cornish-pasty"}, + {"subject": "food:cornish-pasty", "predicate": "rdf:type", "object": "fo/Food"} + ] + ``` + +2. İstemde (prompt) ad alanı açıklamasını ekleyin: + ```markdown + ## Namespace Prefixes: + - **fo/**: Food Ontology (http://purl.org/ontology/fo/) + - **rdf:**: RDF Schema + - **rdfs:**: RDF Schema + + Use these prefixes exactly as shown when referencing classes and properties. + ``` + +3. `expand_uri()`'ı olduğu gibi tutun (eşleşmeler bulunduğunda doğru şekilde çalışır). + +**Avantajları:** +Giriş = Çıkış tutarlılığı +Bilgi kaybı yok +Ada alanı semantiğini korur +Birden fazla ontoloji ile çalışır + +**Dezavantajları:** +LLM için daha ayrıntılı belirteçler +LLM'nin önekleri takip etmesini gerektirir + +### Seçenek C: Hibrit - Hem Etiketi Hem de Kimliği Gösterin + +**Yaklaşım:** İnsan tarafından okunabilir etiketleri ve teknik kimlikleri göstermek için istemi geliştirin. + +**Değişiklikler:** +1. İstem şablonunu güncelleyin: + ```jinja + {% for class_id, class_def in classes.items() %} + - **{{class_id}}** (label: "{{class_def.labels[0].value if class_def.labels else class_id}}"){% if class_def.comment %}: {{class_def.comment}}{% endif %} + {% endfor %} + ``` + + Örnek çıktı: + ```markdown + - **fo/Recipe** (label: "Recipe"): A Recipe is a combination... + ``` + +2. Güncelleme talimatları: + ```markdown + When referencing classes: + - Use the full prefixed ID (e.g., "fo/Recipe") in JSON output + - The label (e.g., "Recipe") is for human understanding only + ``` + +**Avantajları**: +LLM için en anlaşılır olanı +Tüm bilgileri korur +Ne kullanılması gerektiği konusunda açık + +**Dezavantajları**: +Daha uzun bir istem +Daha karmaşık bir şablon + +## Uygulanan Yaklaşım + +**Basitleştirilmiş Varlık-İlişki-Özellik Formatı** - eski üçlü tabanlı formatın tamamen yerini alır. + +Bu yeni yaklaşım aşağıdaki nedenlerle seçilmiştir: + +1. **Bilgi Kaybı Yok**: Orijinal URI'ler doğru şekilde korunur +2. **Daha Basit Mantık**: Dönüştürmeye gerek yoktur, doğrudan sözlük aramaları çalışır +3. **Ad Alanı Güvenliği**: Çakışmalar olmadan birden fazla ontolojiyi işler +4. **Anlamsal Doğruluk**: RDF/OWL semantiğini korur + +## Uygulama Tamamlandı + +### Oluşturulanlar: + +1. **Yeni İstek Şablonu** (`prompts/ontology-extract-v2.txt`) + ✅ Açık bölümler: Varlık Türleri, İlişkiler, Özellikler + ✅ Tam tür tanımlayıcılarını kullanan örnek (`fo/Recipe`, `fo/has_ingredient`) + ✅ Şemadan tam tanımlayıcıları kullanma talimatları + ✅ Varlıklar/ilişkiler/özellikler dizileri içeren yeni JSON formatı + +2. **Varlık Normalizasyonu** (`entity_normalizer.py`) + ✅ `normalize_entity_name()` - İsimleri URI'ye uygun formata dönüştürür + ✅ `normalize_type_identifier()` - Türlerdeki eğik çizgileri işler (`fo/Recipe` → `fo-recipe`) + ✅ `build_entity_uri()` - (isim, tür) tuple'ını kullanarak benzersiz URI'ler oluşturur + ✅ `EntityRegistry` - Tekrarlamayı önlemek için varlıkları takip eder + +3. **JSON Ayrıştırıcı** (`simplified_parser.py`) + ✅ Yeni formatı ayrıştırır: `{entities: [...], relationships: [...], attributes: [...]}` + ✅ kebab-case ve snake_case alan adlarını destekler + ✅ Yapılandırılmış veri sınıfları döndürür + ✅ Günlükleme ile zarif hata işleme + +4. **Üçlü Dönüştürücü** (`triple_converter.py`) + ✅ `convert_entity()` - Tür + etiket üçlülerini otomatik olarak oluşturur + ✅ `convert_relationship()` - Varlık URI'lerini özellikler aracılığıyla bağlar + ✅ `convert_attribute()` - Literal değerleri ekler + ✅ Ontoloji tanımlarından tam URI'leri alır + +5. **Güncellenmiş Ana İşlemci** (`extract.py`) + ✅ Eski üçlü tabanlı çıkarma kodunu kaldırdı + ✅ `extract_with_simplified_format()` yöntemini ekledi + ✅ Artık yalnızca yeni, basitleştirilmiş formatı kullanır + ✅ İstemleri `extract-with-ontologies-v2` kimliğiyle çağırır + +## Test Senaryoları + +### Test 1: URI Korunması +```python +# Given ontology class +classes = {"fo/Recipe": {"uri": "http://purl.org/ontology/fo/Recipe", ...}} + +# When LLM returns +llm_output = {"subject": "x", "predicate": "rdf:type", "object": "fo/Recipe"} + +# Then expanded URI should be +assert expanded == "http://purl.org/ontology/fo/Recipe" +# Not: "https://trustgraph.ai/ontology/food#Recipe" +``` + +### Test 2: Çoklu Ontoloji Çakışması +```python +# Given two ontologies +ont1 = {"fo/Recipe": {...}} +ont2 = {"cooking/Recipe": {...}} + +# LLM should use full prefix to disambiguate +llm_output = {"object": "fo/Recipe"} # Not just "Recipe" +``` + +### Test 3: Varlık Örneği Formatı +```python +# Given prompt with food ontology +# LLM should create instances like +{"subject": "recipe:cornish-pasty"} # Namespace-style +{"subject": "food:beef"} # Consistent prefix +``` + +## Açık Sorular + +1. **Varlık örnekleri namespace önekleri kullanmalı mı?** + Mevcut durum: `"recipe:cornish-pasty"` (keyfi) + Alternatif: Ontoloji önekini kullanın `"fo:cornish-pasty"`? + Alternatif: Önek yok, URI'da genişletin `"cornish-pasty"` → tam URI? + +2. **Alan/kapsam (domain/range) nasıl işlenmeli?** + Şu anda gösterilen: `(Recipe → Food)` + Şu şekilde olmalı mı: `(fo/Recipe → fo/Food)`? + +3. **Alan/kapsam kısıtlamalarını doğrulamalı mıyız?** + TODO yorumu extract.py:470 satırında + Daha fazla hata yakalanır, ancak daha karmaşık olur + +4. **Ters özellikler ve eşdeğerlikler hakkında ne düşünülmeli?** + Ontolojide `owl:inverseOf`, `owl:equivalentClass` bulunmaktadır + Şu anda çıkarımda kullanılmıyor + Kullanılmalı mı? + +## Başarı Metrikleri + +✅ Sıfır URI bilgisi kaybı (orijinal URI'lerin %100 korunması) +✅ LLM çıktısı formatı, giriş formatıyla eşleşiyor +✅ Girişte belirsiz örnek yok +✅ Birden fazla ontolojiyle testler geçiliyor +✅ İyileştirilmiş çıkarım kalitesi (geçerli üçlü yüzdesi ile ölçülür) + +## Alternatif Yaklaşım: Basitleştirilmiş Çıkarım Formatı + +### Felsefe + +LLM'den RDF/OWL semantiğini anlamasını istemek yerine, LLM'nin iyi olduğu şeyi yapmasını isteyin: **metindeki varlıkları ve ilişkileri bulun**. + +URI oluşturma, RDF'ye dönüştürme ve semantik web formalitelerini kodun halletmesine izin verin. + +### Örnek: Varlık Sınıflandırması + +**Giriş Metni:** +``` +Cornish pasty is a traditional British pastry filled with meat and vegetables. +``` + +**Ontoloji Şeması (LLM'ye gösterilen):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food +``` + +**LLM'nin Döndürdükleri (Basit JSON):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + } + ] +} +``` + +**Kodun Ürettiği Şeyler (RDF Üçlüleri):** +```python +# 1. Normalize entity name + type to ID (type prevents collisions) +entity_id = "recipe-cornish-pasty" # normalize("Cornish pasty", "Recipe") +entity_uri = "https://trustgraph.ai/food/recipe-cornish-pasty" + +# Note: Same name, different type = different URI +# "Cornish pasty" (Recipe) → recipe-cornish-pasty +# "Cornish pasty" (Food) → food-cornish-pasty + +# 2. Generate triples +triples = [ + # Type triple + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/1999/02/22-rdf-syntax-ns#type", is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + # Label triple (automatic) + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/2000/01/rdf-schema#label", is_uri=True), + o=Value(value="Cornish pasty", is_uri=False) + ) +] +``` + +### Faydalar + +1. **LLM'nin (Büyük Dil Modeli) yapması gerekmiyor:** + URI sözdizimini anlamak + Tanımlayıcı önekleri oluşturmak (`recipe:`, `ingredient:`) + `rdf:type` veya `rdfs:label` hakkında bilgi sahibi olmak + Semantik web tanımlayıcıları oluşturmak + +2. **LLM'nin sadece yapması gerekiyor:** + Metindeki varlıkları bulmak + Bunları ontoloji sınıflarına eşlemek + İlişkileri ve özellikleri çıkarmak + +3. **Kod şunları yönetir:** + URI normalizasyonu ve oluşturulması + RDF üçlü üretimi + Otomatik etiket ataması + İsim alanı yönetimi + +### Neden Bu Daha İyi Çalışıyor + +**Daha basit istem** = daha az kafa karışıklığı = daha az hata +**Tutarlı kimlikler** = kod, normalizasyon kurallarını kontrol eder +**Otomatik olarak oluşturulan etiketler** = eksik rdfs:label üçlüleri yok +**LLM, çıkarma üzerine odaklanır** = aslında iyi olduğu şey + +### Örnek: Varlık İlişkileri + +**Giriş Metni:** +``` +Cornish pasty is a traditional British pastry filled with beef and potatoes. +``` + +**Ontoloji Şeması (LLM'ye gösterilen):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food + +## Relationships: +- has_ingredient: Relates a recipe to an ingredient it uses (Recipe → Ingredient) +- food: Relates an ingredient to the food that is required (Ingredient → Food) +``` + +**LLM'nin Döndürdükleri (Basit JSON):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ] +} +``` + +**Kodun Ürettiği Şeyler (RDF Üçlüleri):** +```python +# Normalize entity names to URIs +cornish_pasty_uri = "https://trustgraph.ai/food/cornish-pasty" +beef_uri = "https://trustgraph.ai/food/beef" +potatoes_uri = "https://trustgraph.ai/food/potatoes" + +# Look up relation URI from ontology +has_ingredient_uri = "http://purl.org/ontology/fo/ingredients" # from fo/has_ingredient + +triples = [ + # Entity type triples (as before) + Triple(s=cornish_pasty_uri, p=rdf_type, o="http://purl.org/ontology/fo/Recipe"), + Triple(s=cornish_pasty_uri, p=rdfs_label, o="Cornish pasty"), + + Triple(s=beef_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=beef_uri, p=rdfs_label, o="beef"), + + Triple(s=potatoes_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=potatoes_uri, p=rdfs_label, o="potatoes"), + + # Relationship triples + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=beef_uri, is_uri=True) + ), + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=potatoes_uri, is_uri=True) + ) +] +``` + +**Önemli Noktalar:** +LLM, doğal dil varlık isimlerini döndürür: `"Cornish pasty"`, `"beef"`, `"potatoes"` +LLM, anlam belirsizliğini gidermek için türleri içerir: `subject-type`, `object-type` +LLM, şemadan ilişki adını kullanır: `"has_ingredient"` +Kod, (isim, tür) kullanarak tutarlı kimlikler türetir: `("Cornish pasty", "Recipe")` → `recipe-cornish-pasty` +Kod, ontolojiden ilişki URI'sini arar: `fo/has_ingredient` → tam URI +Aynı (isim, tür) ikilisi her zaman aynı URI'yi alır (çiftleme önleme) + +### Örnek: Varlık İsimlerinin Anlam Belirsizliğinin Giderilmesi + +**Sorun:** Aynı isim, farklı varlık türlerini ifade edebilir. + +**Gerçek dünya örneği:** +``` +"Cornish pasty" can be: +- A Recipe (instructions for making it) +- A Food (the dish itself) +``` + +**Nasıl İşlendiği:** + +LLM, her ikisini de ayrı varlıklar olarak döndürür: +```json +{ + "entities": [ + {"entity": "Cornish pasty", "type": "Recipe"}, + {"entity": "Cornish pasty", "type": "Food"} + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "produces", + "object": "Cornish pasty", + "object-type": "Food" + } + ] +} +``` + +**Kod Çözümleme:** +```python +# Different types → different URIs +recipe_uri = normalize("Cornish pasty", "Recipe") +# → "https://trustgraph.ai/food/recipe-cornish-pasty" + +food_uri = normalize("Cornish pasty", "Food") +# → "https://trustgraph.ai/food/food-cornish-pasty" + +# Relationship connects them correctly +triple = Triple( + s=recipe_uri, # The Recipe + p="http://purl.org/ontology/fo/produces", + o=food_uri # The Food +) +``` + +**Neden İşe Yarıyor:** +Tip, TÜM referanslarda (varlıklar, ilişkiler, özellikler) bulunur. +Kod, arama anahtarı olarak `(name, type)` tuple'ını kullanır. +Herhangi bir belirsizlik, herhangi bir çakışma yoktur. + +### Örnek: Varlık Özellikleri + +**Giriş Metni:** +``` +This Cornish pasty recipe serves 4-6 people and takes 45 minutes to prepare. +``` + +**Ontoloji Şeması (LLM'ye gösterilen):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method + +## Attributes: +- serves: Indicates what the recipe is intended to serve (Recipe → text) +- preparation_time: Time needed to prepare the recipe (Recipe → text) +``` + +**LLM'nin Döndürdükleri (Basit JSON):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty recipe", + "type": "Recipe" + } + ], + "attributes": [ + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4-6 people" + }, + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "preparation_time", + "value": "45 minutes" + } + ] +} +``` + +**Kodun Ürettiği Şeyler (RDF Üçlüleri):** +```python +# Normalize entity name to URI +recipe_uri = "https://trustgraph.ai/food/cornish-pasty-recipe" + +# Look up attribute URIs from ontology +serves_uri = "http://purl.org/ontology/fo/serves" # from fo/serves +prep_time_uri = "http://purl.org/ontology/fo/preparation_time" # from fo/preparation_time + +triples = [ + # Entity type triple + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdf_type, is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + + # Label triple (automatic) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdfs_label, is_uri=True), + o=Value(value="Cornish pasty recipe", is_uri=False) + ), + + # Attribute triples (objects are literals, not URIs) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=serves_uri, is_uri=True), + o=Value(value="4-6 people", is_uri=False) # Literal value! + ), + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=prep_time_uri, is_uri=True), + o=Value(value="45 minutes", is_uri=False) # Literal value! + ) +] +``` + +**Önemli Noktalar:** +LLM, gerçek değerleri çıkarır: `"4-6 people"`, `"45 minutes"` +LLM, anlam ayrımı için varlık türünü içerir: `entity-type` +LLM, şemadan öznitelik adını kullanır: `"serves"`, `"preparation_time"` +Kod, öznitelik URI'sini ontoloji veri türü özelliklerinden arar +**Nesne bir literaldir** (`is_uri=False`), bir URI referansı değildir +Değerler, doğal metin olarak kalır, normalleştirmeye gerek yoktur + +**İlişkilerden Farkı:** +İlişkiler: hem konu hem de nesne varlıklardır (URI'ler) +Öznitelikler: konu bir varlıktır (URI), nesne bir literal değerdir (dize/sayı) + +### Tam Örnek: Varlıklar + İlişkiler + Öznitelikler + +**Giriş Metni:** +``` +Cornish pasty is a savory pastry filled with beef and potatoes. +This recipe serves 4 people. +``` + +**LLM'nin Döndürdükleri:** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ], + "attributes": [ + { + "entity": "Cornish pasty", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4 people" + } + ] +} +``` + +**Sonuç:** 11 RDF üçlüsü oluşturuldu: +3 varlık türü üçlüsü (rdf:type) +3 varlık etiket üçlüsü (rdfs:label) - otomatik +2 ilişki üçlüsü (has_ingredient) +1 özellik üçlüsü (serves) + +Bunların hepsi, LLM tarafından yapılan basit, doğal dil çıkarımlarından elde edilmiştir! + +## Referanslar + +Mevcut uygulama: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` +İstek şablonu: `ontology-prompt.md` +Test senaryoları: `tests/unit/test_extract/test_ontology/` +Örnek ontoloji: `e2e/test-data/food.ontology` diff --git a/docs/tech-specs/ontology-extract-phase-2.zh-cn.md b/docs/tech-specs/ontology-extract-phase-2.zh-cn.md new file mode 100644 index 00000000..cacfb1cf --- /dev/null +++ b/docs/tech-specs/ontology-extract-phase-2.zh-cn.md @@ -0,0 +1,761 @@ +# 本体知识抽取 - 第二阶段重构 + +**状态**: 草稿 +**作者**: 分析会议 2025-12-03 +**相关**: `ontology.md`, `ontorag.md` + +## 概述 + +本文档识别了当前基于本体的知识抽取系统中存在的缺陷,并提出了重构方案,以提高 LLM 的性能并减少信息损失。 + +## 当前实现 + +### 当前工作方式 + +1. **本体加载** (`ontology_loader.py`) + 加载本体 JSON 文件,其中包含键,例如 `"fo/Recipe"`, `"fo/Food"`, `"fo/produces"` + 类 ID 在键本身中包含命名空间前缀 + 示例来自 `food.ontology`: + ```json + "classes": { + "fo/Recipe": { + "uri": "http://purl.org/ontology/fo/Recipe", + "rdfs:comment": "A Recipe is a combination..." + } + } + ``` + +2. **提示构建** (`extract.py:299-307`, `ontology-prompt.md`) + 模板接收 `classes`, `object_properties`, `datatype_properties` 字典 + 模板循环:`{% for class_id, class_def in classes.items() %}` + LLM 看到:`**fo/Recipe**: A Recipe is a combination...` + 示例输出格式如下: + ```json + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} + {"subject": "recipe:cornish-pasty", "predicate": "has_ingredient", "object": "ingredient:flour"} + ``` + +3. **响应解析** (`extract.py:382-428`) + 期望接收 JSON 数组: `[{"subject": "...", "predicate": "...", "object": "..."}]` + 验证是否符合本体子集 + 通过 `expand_uri()` 扩展 URI (extract.py:473-521) + +4. **URI 扩展** (`extract.py:473-521`) + 检查值是否在 `ontology_subset.classes` 字典中 + 如果找到,从类定义中提取 URI + 如果未找到,则构建 URI: `f"https://trustgraph.ai/ontology/{ontology_id}#{value}"` + +### 数据流示例 + +**本体 JSON → 加载器 → 提示:** +``` +"fo/Recipe" → classes["fo/Recipe"] → LLM sees "**fo/Recipe**" +``` + +**LLM → 解析器 → 输出:** +``` +"Recipe" → not in classes["fo/Recipe"] → constructs URI → LOSES original URI +"fo/Recipe" → found in classes → uses original URI → PRESERVES URI +``` + +## 发现的问题 + +### 1. **提示语中的示例不一致** + +**问题**: 提示模板显示带有前缀的类ID (`fo/Recipe`),但示例输出使用不带前缀的类名 (`Recipe`)。 + +**位置**: `ontology-prompt.md:5-52` + +```markdown +## Ontology Classes: +- **fo/Recipe**: A Recipe is... + +## Example Output: +{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"} +``` + +**影响:** LLM 接收到关于应该使用哪种格式的冲突信号。 + +### 2. **URI 扩展中的信息丢失** + +**问题:** 当 LLM 返回不带前缀的类名,例如示例中的情况时,`expand_uri()` 无法在本体字典中找到它们,而是构造了备用 URI,从而丢失了原始的正确 URI。 + +**位置:** `extract.py:494-500` + +```python +if value in ontology_subset.classes: # Looks for "Recipe" + class_def = ontology_subset.classes[value] # But key is "fo/Recipe" + if isinstance(class_def, dict) and 'uri' in class_def: + return class_def['uri'] # Never reached! +return f"https://trustgraph.ai/ontology/{ontology_id}#{value}" # Fallback +``` + +**影响 (Impact):** +原始 URI: `http://purl.org/ontology/fo/Recipe` +构建的 URI: `https://trustgraph.ai/ontology/food#Recipe` +语义信息丢失,破坏互操作性 + +### 3. **实体实例格式不明确 (Ambiguous Entity Instance Format)** + +**问题 (Issue):** 没有关于实体实例 URI 格式的明确指导。 + +**提示中的示例 (Examples in prompt):** +`"recipe:cornish-pasty"` (类似于命名空间的 前缀) +`"ingredient:flour"` (不同的前缀) + +**实际行为 (Actual behavior) (extract.py:517-520):** +```python +# Treat as entity instance - construct unique URI +normalized = value.replace(" ", "-").lower() +return f"https://trustgraph.ai/{ontology_id}/{normalized}" +``` + +**影响:** LLM 必须在没有任何本体知识的情况下猜测前缀约定。 + +### 4. **没有命名空间前缀的指导** + +**问题:** 本体 JSON 包含命名空间定义(food.ontology 中的第 10-25 行): +```json +"namespaces": { + "fo": "http://purl.org/ontology/fo/", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + ... +} +``` + +但是这些内容永远不会传递给大型语言模型。大型语言模型不知道: +"fo" 的含义 +应使用哪个前缀来表示实体 +哪个命名空间适用于哪些元素 + +### 5. **未在提示中使用标签** + +**问题:** 每一个类都有 `rdfs:label` 字段(例如,`{"value": "Recipe", "lang": "en-gb"}`),但提示模板没有使用它们。 + +**当前:** 只显示 `class_id` 和 `comment` +```jinja +- **{{class_id}}**{% if class_def.comment %}: {{class_def.comment}}{% endif %} +``` + +**可用但未使用的:** +```python +"rdfs:label": [{"value": "Recipe", "lang": "en-gb"}] +``` + +**影响:** 可以为技术 ID 旁边提供人类可读的名称。 + +## 提出的解决方案 + +### 方案 A:标准化为不带前缀的 ID + +**方法:** 在向 LLM 显示之前,从类 ID 中移除前缀。 + +**变更:** +1. 修改 `build_extraction_variables()` 以转换键: + ```python + classes_for_prompt = { + k.split('/')[-1]: v # "fo/Recipe" → "Recipe" + for k, v in ontology_subset.classes.items() + } + ``` + +2. 将提示示例更新为匹配项(已使用未加前缀的名称)。 + +3. 修改 `expand_uri()` 以处理两种格式: + ```python + # Try exact match first + if value in ontology_subset.classes: + return ontology_subset.classes[value]['uri'] + + # Try with prefix + for prefix in ['fo/', 'rdf:', 'rdfs:']: + prefixed = f"{prefix}{value}" + if prefixed in ontology_subset.classes: + return ontology_subset.classes[prefixed]['uri'] + ``` + +**优点:** +更清晰,更易于人类阅读 +与现有的提示示例相符 +LLM(大型语言模型)在处理更简单的token时效果更好 + +**缺点:** +如果多个本体具有相同的类名,则可能发生类名冲突 +丢失命名空间信息 +需要回退逻辑来执行查找 + +### 选项 B:始终使用完整的带前缀的 ID + +**方法:** 更新示例,使其使用与类列表中显示的前缀 ID 匹配。 + +**更改:** +1. 更新提示示例(ontology-prompt.md:46-52): + ```json + [ + {"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "fo/Recipe"}, + {"subject": "recipe:cornish-pasty", "predicate": "rdfs:label", "object": "Cornish Pasty"}, + {"subject": "recipe:cornish-pasty", "predicate": "fo/produces", "object": "food:cornish-pasty"}, + {"subject": "food:cornish-pasty", "predicate": "rdf:type", "object": "fo/Food"} + ] + ``` + +2. 在提示语中添加命名空间说明: + ```markdown + ## Namespace Prefixes: + - **fo/**: Food Ontology (http://purl.org/ontology/fo/) + - **rdf:**: RDF Schema + - **rdfs:**: RDF Schema + + Use these prefixes exactly as shown when referencing classes and properties. + ``` + +3. 保持 `expand_uri()` 的原样 (当找到匹配项时,它可以正常工作)。 + +**优点:** +输入 = 输出的一致性。 +没有信息损失。 +保留命名空间语义。 +适用于多个本体。 + +**缺点:** +对于 LLM 来说,token 更加冗长。 +需要 LLM 跟踪前缀。 + +### 选项 C:混合 - 同时显示标签和 ID + +**方法:** 增强提示,同时显示人类可读的标签和技术 ID。 + +**更改:** +1. 更新提示模板: + ```jinja + {% for class_id, class_def in classes.items() %} + - **{{class_id}}** (label: "{{class_def.labels[0].value if class_def.labels else class_id}}"){% if class_def.comment %}: {{class_def.comment}}{% endif %} + {% endfor %} + ``` + + 示例输出: + ```markdown + - **fo/Recipe** (label: "Recipe"): A Recipe is a combination... + ``` + +2. 更新说明: + ```markdown + When referencing classes: + - Use the full prefixed ID (e.g., "fo/Recipe") in JSON output + - The label (e.g., "Recipe") is for human understanding only + ``` + +**优点 (Pros)**: +对 LLM 最清晰 +保留所有信息 +明确说明应该使用什么 + +**缺点 (Cons)**: +提示更长 +模板更复杂 + +## 实施方法 (Implemented Approach) + +**简化的实体-关系-属性格式** - 完全取代了旧的三元组格式。 + +选择了这种新方法的原因是: + +1. **无信息损失 (No Information Loss)**: 原始 URI 正确保留 +2. **更简单的逻辑 (Simpler Logic)**: 无需转换,可以直接使用字典查找 +3. **命名空间安全 (Namespace Safety)**: 能够处理多个本体而不会发生冲突 +4. **语义正确性 (Semantic Correctness)**: 保持 RDF/OWL 语义 + +## 实施完成 (Implementation Complete) + +### 构建内容 (What Was Built): + +1. **新的提示模板 (New Prompt Template)** (`prompts/ontology-extract-v2.txt`) + ✅ 清晰的章节:实体类型、关系、属性 + ✅ 使用完整类型标识符的示例 (`fo/Recipe`, `fo/has_ingredient`) + ✅ 指示使用模式中确切的标识符 + ✅ 新的 JSON 格式,包含实体/关系/属性数组 + +2. **实体规范化 (Entity Normalization)** (`entity_normalizer.py`) + ✅ `normalize_entity_name()` - 将名称转换为 URI 安全格式 + ✅ `normalize_type_identifier()` - 处理类型中的斜杠 (`fo/Recipe` → `fo-recipe`) + ✅ `build_entity_uri()` - 使用 (名称, 类型) 元组创建唯一 URI + ✅ `EntityRegistry` - 跟踪实体以进行去重 + +3. **JSON 解析器 (JSON Parser)** (`simplified_parser.py`) + ✅ 解析新的格式:`{entities: [...], relationships: [...], attributes: [...]}` + ✅ 支持 kebab-case 和 snake_case 字段名称 + ✅ 返回结构化的数据类 + ✅ 具有优雅的错误处理和日志记录 + +4. **三元组转换器 (Triple Converter)** (`triple_converter.py`) + ✅ `convert_entity()` - 自动生成类型 + 标签三元组 + ✅ `convert_relationship()` - 通过属性连接实体 URI + ✅ `convert_attribute()` - 添加字面值 + ✅ 从本体定义中查找完整的 URI + +5. **更新的主要处理器 (Updated Main Processor)** (`extract.py`) + ✅ 删除了旧的三元组提取代码 + ✅ 添加了 `extract_with_simplified_format()` 方法 + ✅ 现在仅使用新的简化格式 + ✅ 使用 `extract-with-ontologies-v2` ID 调用提示 + +## 测试用例 (Test Cases) + +### 测试 1: URI 保留 (Test 1: URI Preservation) +```python +# Given ontology class +classes = {"fo/Recipe": {"uri": "http://purl.org/ontology/fo/Recipe", ...}} + +# When LLM returns +llm_output = {"subject": "x", "predicate": "rdf:type", "object": "fo/Recipe"} + +# Then expanded URI should be +assert expanded == "http://purl.org/ontology/fo/Recipe" +# Not: "https://trustgraph.ai/ontology/food#Recipe" +``` + +### 测试 2:多本体冲突 +```python +# Given two ontologies +ont1 = {"fo/Recipe": {...}} +ont2 = {"cooking/Recipe": {...}} + +# LLM should use full prefix to disambiguate +llm_output = {"object": "fo/Recipe"} # Not just "Recipe" +``` + +### 测试 3:实体实例格式 +```python +# Given prompt with food ontology +# LLM should create instances like +{"subject": "recipe:cornish-pasty"} # Namespace-style +{"subject": "food:beef"} # Consistent prefix +``` + +## 待解决的问题 + +1. **实体实例是否应该使用命名空间前缀?** + 当前:`"recipe:cornish-pasty"` (任意) + 替代方案:使用本体前缀 `"fo:cornish-pasty"`? + 替代方案:不使用前缀,在 URI 中展开 `"cornish-pasty"` → 完整 URI? + +2. **如何在提示中处理域/范围?** + 当前显示:`(Recipe → Food)` + 应该是:`(fo/Recipe → fo/Food)`? + +3. **是否应该验证域/范围约束?** + TODO 注释在 extract.py:470 + 可以捕获更多错误,但更复杂 + +4. **关于反向属性和等价性?** + 本体有 `owl:inverseOf`,`owl:equivalentClass` + 当前未在提取中使用 + 应该使用吗? + +## 成功指标 + +✅ 零 URI 信息损失(100% 保留原始 URI) +✅ LLM 输出格式与输入格式匹配 +✅ 提示中没有歧义的示例 +✅ 使用多个本体的测试通过 +✅ 提取质量得到改进(通过有效的三元组百分比衡量) + +## 替代方法:简化的提取格式 + +### 理念 + +不要让 LLM 理解 RDF/OWL 语义,而是让它做擅长的事情:**在文本中查找实体和关系**。 + +让代码处理 URI 构造、RDF 转换和语义网规范。 + +### 示例:实体分类 + +**输入文本:** +``` +Cornish pasty is a traditional British pastry filled with meat and vegetables. +``` + +**本体模式(显示给LLM):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food +``` + +**LLM 返回的内容(简单 JSON):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + } + ] +} +``` + +**生成的代码(RDF 三元组):** +```python +# 1. Normalize entity name + type to ID (type prevents collisions) +entity_id = "recipe-cornish-pasty" # normalize("Cornish pasty", "Recipe") +entity_uri = "https://trustgraph.ai/food/recipe-cornish-pasty" + +# Note: Same name, different type = different URI +# "Cornish pasty" (Recipe) → recipe-cornish-pasty +# "Cornish pasty" (Food) → food-cornish-pasty + +# 2. Generate triples +triples = [ + # Type triple + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/1999/02/22-rdf-syntax-ns#type", is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + # Label triple (automatic) + Triple( + s=Value(value=entity_uri, is_uri=True), + p=Value(value="http://www.w3.org/2000/01/rdf-schema#label", is_uri=True), + o=Value(value="Cornish pasty", is_uri=False) + ) +] +``` + +### 优点 + +1. **LLM 不需要:** + 理解 URI 语法 + 编造标识符前缀 (`recipe:`, `ingredient:`) + 了解 `rdf:type` 或 `rdfs:label` + 构建语义网标识符 + +2. **LLM 只需要:** + 在文本中找到实体 + 将它们映射到本体类 + 提取关系和属性 + +3. **代码负责:** + URI 规范化和构建 + RDF 三元组生成 + 自动标签分配 + 命名空间管理 + +### 为什么这样更好 + +**更简单的提示** = 减少困惑 = 更少的错误 +**一致的 ID** = 代码控制规范化规则 +**自动生成的标签** = 没有遗漏的 rdfs:label 三元组 +**LLM 专注于提取** = 这是它擅长的事情 + +### 示例:实体关系 + +**输入文本:** +``` +Cornish pasty is a traditional British pastry filled with beef and potatoes. +``` + +**本体模式(显示给LLM):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method +- Food: A food is something that can be eaten +- Ingredient: An ingredient combines a quantity and a food + +## Relationships: +- has_ingredient: Relates a recipe to an ingredient it uses (Recipe → Ingredient) +- food: Relates an ingredient to the food that is required (Ingredient → Food) +``` + +**LLM 返回的内容(简单 JSON):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ] +} +``` + +**生成的代码(RDF 三元组):** +```python +# Normalize entity names to URIs +cornish_pasty_uri = "https://trustgraph.ai/food/cornish-pasty" +beef_uri = "https://trustgraph.ai/food/beef" +potatoes_uri = "https://trustgraph.ai/food/potatoes" + +# Look up relation URI from ontology +has_ingredient_uri = "http://purl.org/ontology/fo/ingredients" # from fo/has_ingredient + +triples = [ + # Entity type triples (as before) + Triple(s=cornish_pasty_uri, p=rdf_type, o="http://purl.org/ontology/fo/Recipe"), + Triple(s=cornish_pasty_uri, p=rdfs_label, o="Cornish pasty"), + + Triple(s=beef_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=beef_uri, p=rdfs_label, o="beef"), + + Triple(s=potatoes_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"), + Triple(s=potatoes_uri, p=rdfs_label, o="potatoes"), + + # Relationship triples + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=beef_uri, is_uri=True) + ), + Triple( + s=Value(value=cornish_pasty_uri, is_uri=True), + p=Value(value=has_ingredient_uri, is_uri=True), + o=Value(value=potatoes_uri, is_uri=True) + ) +] +``` + +**关键点:** +LLM 返回自然语言实体名称:`"Cornish pasty"`, `"beef"`, `"potatoes"` +LLM 包含类型信息以消除歧义:`subject-type`, `object-type` +LLM 使用模式中的关系名称:`"has_ingredient"` +代码使用 (名称, 类型) 推导一致的 ID:`("Cornish pasty", "Recipe")` → `recipe-cornish-pasty` +代码从本体中查找关系 URI:`fo/has_ingredient` → 完整 URI +相同的 (名称, 类型) 元组始终获得相同的 URI (去重) + +### 示例:实体名称消除歧义 + +**问题:** 相同的名称可能指不同的实体类型。 + +**实际案例:** +``` +"Cornish pasty" can be: +- A Recipe (instructions for making it) +- A Food (the dish itself) +``` + +**处理方式:** + +LLM 将两者都以独立的实体返回: +```json +{ + "entities": [ + {"entity": "Cornish pasty", "type": "Recipe"}, + {"entity": "Cornish pasty", "type": "Food"} + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "produces", + "object": "Cornish pasty", + "object-type": "Food" + } + ] +} +``` + +**代码解析:** +```python +# Different types → different URIs +recipe_uri = normalize("Cornish pasty", "Recipe") +# → "https://trustgraph.ai/food/recipe-cornish-pasty" + +food_uri = normalize("Cornish pasty", "Food") +# → "https://trustgraph.ai/food/food-cornish-pasty" + +# Relationship connects them correctly +triple = Triple( + s=recipe_uri, # The Recipe + p="http://purl.org/ontology/fo/produces", + o=food_uri # The Food +) +``` + +**原理:** +类型包含在所有引用中(实体、关系、属性)。 +代码使用 `(name, type)` 元组作为查找键。 +没有歧义,没有冲突。 + +### 示例:实体属性 + +**输入文本:** +``` +This Cornish pasty recipe serves 4-6 people and takes 45 minutes to prepare. +``` + +**本体模式(显示给LLM):** +```markdown +## Entity Types: +- Recipe: A recipe is a combination of ingredients and a method + +## Attributes: +- serves: Indicates what the recipe is intended to serve (Recipe → text) +- preparation_time: Time needed to prepare the recipe (Recipe → text) +``` + +**LLM 返回的内容(简单 JSON):** +```json +{ + "entities": [ + { + "entity": "Cornish pasty recipe", + "type": "Recipe" + } + ], + "attributes": [ + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4-6 people" + }, + { + "entity": "Cornish pasty recipe", + "entity-type": "Recipe", + "attribute": "preparation_time", + "value": "45 minutes" + } + ] +} +``` + +**生成的代码(RDF 三元组):** +```python +# Normalize entity name to URI +recipe_uri = "https://trustgraph.ai/food/cornish-pasty-recipe" + +# Look up attribute URIs from ontology +serves_uri = "http://purl.org/ontology/fo/serves" # from fo/serves +prep_time_uri = "http://purl.org/ontology/fo/preparation_time" # from fo/preparation_time + +triples = [ + # Entity type triple + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdf_type, is_uri=True), + o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True) + ), + + # Label triple (automatic) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=rdfs_label, is_uri=True), + o=Value(value="Cornish pasty recipe", is_uri=False) + ), + + # Attribute triples (objects are literals, not URIs) + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=serves_uri, is_uri=True), + o=Value(value="4-6 people", is_uri=False) # Literal value! + ), + Triple( + s=Value(value=recipe_uri, is_uri=True), + p=Value(value=prep_time_uri, is_uri=True), + o=Value(value="45 minutes", is_uri=False) # Literal value! + ) +] +``` + +**关键点:** +LLM 提取字面值:`"4-6 people"`, `"45 minutes"` +LLM 包含实体类型以消除歧义:`entity-type` +LLM 使用来自模式的属性名称:`"serves"`, `"preparation_time"` +代码从本体数据类型属性中查找属性 URI +**对象是字面值** (`is_uri=False`),而不是 URI 引用 +值保持为自然文本,无需进行任何标准化 + +**与关系的差异:** +关系:主语和宾语都是实体(URI) +属性:主语是实体(URI),宾语是字面值(字符串/数字) + +### 完整示例:实体 + 关系 + 属性 + +**输入文本:** +``` +Cornish pasty is a savory pastry filled with beef and potatoes. +This recipe serves 4 people. +``` + +**LLM 返回的内容:** +```json +{ + "entities": [ + { + "entity": "Cornish pasty", + "type": "Recipe" + }, + { + "entity": "beef", + "type": "Food" + }, + { + "entity": "potatoes", + "type": "Food" + } + ], + "relationships": [ + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "beef", + "object-type": "Food" + }, + { + "subject": "Cornish pasty", + "subject-type": "Recipe", + "relation": "has_ingredient", + "object": "potatoes", + "object-type": "Food" + } + ], + "attributes": [ + { + "entity": "Cornish pasty", + "entity-type": "Recipe", + "attribute": "serves", + "value": "4 people" + } + ] +} +``` + +**结果:** 生成了 11 个 RDF 三元组: +3 个实体类型三元组 (rdf:type) +3 个实体标签三元组 (rdfs:label) - 自动 +2 个关系三元组 (has_ingredient) +1 个属性三元组 (serves) + +所有内容均由 LLM 通过简单的、自然的语言提取得出! + +## 参考文献 + +当前实现:`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` +提示模板:`ontology-prompt.md` +测试用例:`tests/unit/test_extract/test_ontology/` +示例本体:`e2e/test-data/food.ontology` diff --git a/docs/tech-specs/ontology.pt.md b/docs/tech-specs/ontology.pt.md new file mode 100644 index 00000000..cdefb583 --- /dev/null +++ b/docs/tech-specs/ontology.pt.md @@ -0,0 +1,286 @@ +# Especificação Técnica da Estrutura da Ontologia + +## Visão Geral + +Esta especificação descreve a estrutura e o formato das ontologias dentro do sistema TrustGraph. As ontologias fornecem modelos de conhecimento formais que definem classes, propriedades e relacionamentos, suportando capacidades de raciocínio e inferência. O sistema usa um formato de configuração inspirado em OWL que representa amplamente os conceitos OWL/RDFS, ao mesmo tempo que é otimizado para os requisitos do TrustGraph. + +**Convenção de Nomenclatura**: Este projeto usa kebab-case para todos os identificadores (chaves de configuração, pontos finais de API, nomes de módulos, etc.) em vez de snake_case. + +## Objetivos + +**Gerenciamento de Classes e Propriedades**: Definir classes semelhantes a OWL com propriedades, domínios, intervalos e restrições de tipo. +**Suporte Semântico Rico**: Habilitar propriedades abrangentes RDFS/OWL, incluindo rótulos, suporte multilíngue e restrições formais. +**Suporte a Múltiplas Ontologias**: Permitir que várias ontologias coexistam e interoperem. +**Validação e Raciocínio**: Garantir que as ontologias estejam em conformidade com padrões semelhantes a OWL, com verificação de consistência e suporte de inferência. +**Compatibilidade com Padrões**: Suportar importação/exportação em formatos padrão (Turtle, RDF/XML, OWL/XML) mantendo a otimização interna. + +## Contexto + +O TrustGraph armazena ontologias como itens de configuração em um sistema flexível de chave-valor. Embora o formato seja inspirado em OWL (Web Ontology Language), ele é otimizado para casos de uso específicos do TrustGraph e não adere estritamente a todas as especificações do OWL. + +As ontologias no TrustGraph permitem: +Definição de tipos de objetos formais e suas propriedades. +Especificação de domínios, intervalos e restrições de tipo de propriedade. +Raciocínio e inferência lógica. +Relacionamentos complexos e restrições de cardinalidade. +Suporte multilíngue para internacionalização. + +## Estrutura da Ontologia + +### Armazenamento de Configuração + +As ontologias são armazenadas como itens de configuração com o seguinte padrão: +**Tipo**: `ontology` +**Chave**: Identificador de ontologia exclusivo (por exemplo, `natural-world`, `domain-model`) +**Valor**: Ontologia completa em formato JSON. + +### Estrutura JSON + +O formato JSON da ontologia consiste em quatro seções principais: + +#### 1. Metadados + +Contém informações administrativas e descritivas sobre a ontologia: + +```json +{ + "metadata": { + "name": "The natural world", + "description": "Ontology covering the natural order", + "version": "1.0.0", + "created": "2025-09-20T12:07:37.068Z", + "modified": "2025-09-20T12:12:20.725Z", + "creator": "current-user", + "namespace": "http://trustgraph.ai/ontologies/natural-world", + "imports": ["http://www.w3.org/2002/07/owl#"] + } +} +``` + +**Campos:** +`name`: Nome legível para humanos da ontologia +`description`: Breve descrição do propósito da ontologia +`version`: Número de versão semântico +`created`: Carimbo de data/hora ISO 8601 de criação +`modified`: Carimbo de data/hora ISO 8601 da última modificação +`creator`: Identificador do usuário/sistema que criou +`namespace`: URI base para elementos da ontologia +`imports`: Array de URIs de ontologias importadas + +#### 2. Classes + +Define os tipos de objeto e seus relacionamentos hierárquicos: + +```json +{ + "classes": { + "animal": { + "uri": "http://trustgraph.ai/ontologies/natural-world#animal", + "type": "owl:Class", + "rdfs:label": [{"value": "Animal", "lang": "en"}], + "rdfs:comment": "An animal", + "rdfs:subClassOf": "lifeform", + "owl:equivalentClass": ["creature"], + "owl:disjointWith": ["plant"], + "dcterms:identifier": "ANI-001" + } + } +} +``` + +**Propriedades Suportadas:** +`uri`: URI completo da classe +`type`: Sempre `"owl:Class"` +`rdfs:label`: Array de rótulos com informações de idioma +`rdfs:comment`: Descrição da classe +`rdfs:subClassOf`: Identificador da classe pai (herança simples) +`owl:equivalentClass`: Array de identificadores de classes equivalentes +`owl:disjointWith`: Array de identificadores de classes disjuntas +`dcterms:identifier`: Identificador de referência externa opcional + +#### 3. Propriedades de Objeto + +Propriedades que conectam instâncias a outras instâncias: + +```json +{ + "objectProperties": { + "has-parent": { + "uri": "http://trustgraph.ai/ontologies/natural-world#has-parent", + "type": "owl:ObjectProperty", + "rdfs:label": [{"value": "has parent", "lang": "en"}], + "rdfs:comment": "Links an animal to its parent", + "rdfs:domain": "animal", + "rdfs:range": "animal", + "owl:inverseOf": "parent-of", + "owl:functionalProperty": false + } + } +} +``` + +**Propriedades Suportadas:** +`uri`: URI completo da propriedade +`type`: Sempre `"owl:ObjectProperty"` +`rdfs:label`: Array de rótulos com informações de idioma +`rdfs:comment`: Descrição da propriedade +`rdfs:domain`: Identificador da classe que possui esta propriedade +`rdfs:range`: Identificador da classe para valores de propriedade +`owl:inverseOf`: Identificador da propriedade inversa +`owl:functionalProperty`: Booleano indicando no máximo um valor +`owl:inverseFunctionalProperty`: Booleano para propriedades de identificação única + +#### 4. Propriedades de Tipo de Dado + +Propriedades que conectam instâncias a valores literais: + +```json +{ + "datatypeProperties": { + "number-of-legs": { + "uri": "http://trustgraph.ai/ontologies/natural-world#number-of-legs", + "type": "owl:DatatypeProperty", + "rdfs:label": [{"value": "number of legs", "lang": "en"}], + "rdfs:comment": "Count of number of legs of the animal", + "rdfs:domain": "animal", + "rdfs:range": "xsd:nonNegativeInteger", + "owl:functionalProperty": true, + "owl:minCardinality": 0, + "owl:maxCardinality": 1 + } + } +} +``` + +**Propriedades Suportadas:** +`uri`: URI completo da propriedade +`type`: Sempre `"owl:DatatypeProperty"` +`rdfs:label`: Array de rótulos com marcação de idioma +`rdfs:comment`: Descrição da propriedade +`rdfs:domain`: Identificador da classe que possui esta propriedade +`rdfs:range`: Tipo de dados XSD para os valores da propriedade +`owl:functionalProperty`: Booleano indicando no máximo um valor +`owl:minCardinality`: Número mínimo de valores (opcional) +`owl:maxCardinality`: Número máximo de valores (opcional) +`owl:cardinality`: Número exato de valores (opcional) + +### Tipos de Dados XSD Suportados + +Os seguintes tipos de dados XML Schema são suportados para intervalos de propriedades: + +`xsd:string` - Valores de texto +`xsd:integer` - Números inteiros +`xsd:nonNegativeInteger` - Inteiros não negativos +`xsd:float` - Números de ponto flutuante +`xsd:double` - Números de precisão dupla +`xsd:boolean` - Valores verdadeiro/falso +`xsd:dateTime` - Valores de data e hora +`xsd:date` - Valores de data +`xsd:anyURI` - Referências de URI + +### Suporte a Idiomas + +Rótulos e comentários suportam vários idiomas usando o formato de etiqueta de idioma W3C: + +```json +{ + "rdfs:label": [ + {"value": "Animal", "lang": "en"}, + {"value": "Tier", "lang": "de"}, + {"value": "Animal", "lang": "es"} + ] +} +``` + +## Exemplo de Ontologia + +Aqui está um exemplo completo de uma ontologia simples: + +```json +{ + "metadata": { + "name": "The natural world", + "description": "Ontology covering the natural order", + "version": "1.0.0", + "created": "2025-09-20T12:07:37.068Z", + "modified": "2025-09-20T12:12:20.725Z", + "creator": "current-user", + "namespace": "http://trustgraph.ai/ontologies/natural-world", + "imports": ["http://www.w3.org/2002/07/owl#"] + }, + "classes": { + "lifeform": { + "uri": "http://trustgraph.ai/ontologies/natural-world#lifeform", + "type": "owl:Class", + "rdfs:label": [{"value": "Lifeform", "lang": "en"}], + "rdfs:comment": "A living thing" + }, + "animal": { + "uri": "http://trustgraph.ai/ontologies/natural-world#animal", + "type": "owl:Class", + "rdfs:label": [{"value": "Animal", "lang": "en"}], + "rdfs:comment": "An animal", + "rdfs:subClassOf": "lifeform" + }, + "cat": { + "uri": "http://trustgraph.ai/ontologies/natural-world#cat", + "type": "owl:Class", + "rdfs:label": [{"value": "Cat", "lang": "en"}], + "rdfs:comment": "A cat", + "rdfs:subClassOf": "animal" + }, + "dog": { + "uri": "http://trustgraph.ai/ontologies/natural-world#dog", + "type": "owl:Class", + "rdfs:label": [{"value": "Dog", "lang": "en"}], + "rdfs:comment": "A dog", + "rdfs:subClassOf": "animal", + "owl:disjointWith": ["cat"] + } + }, + "objectProperties": {}, + "datatypeProperties": { + "number-of-legs": { + "uri": "http://trustgraph.ai/ontologies/natural-world#number-of-legs", + "type": "owl:DatatypeProperty", + "rdfs:label": [{"value": "number-of-legs", "lang": "en"}], + "rdfs:comment": "Count of number of legs of the animal", + "rdfs:range": "xsd:nonNegativeInteger", + "rdfs:domain": "animal" + } + } +} +``` + +## Regras de Validação + +### Validação Estrutural + +1. **Consistência de URIs**: Todos os URIs devem seguir o padrão `{namespace}#{identifier}` +2. **Hierarquia de Classes**: Não pode haver herança circular em `rdfs:subClassOf` +3. **Domínios/Intervalos de Propriedades**: Deve referenciar classes existentes ou tipos XSD válidos +4. **Classes Disjuntas**: Não podem ser subclasses umas das outras +5. **Propriedades Inversas**: Devem ser bidirecionais se especificadas + +### Validação Semântica + +1. **Identificadores Únicos**: Os identificadores de classe e propriedade devem ser únicos dentro de uma ontologia +2. **Etiquetas de Idioma**: Devem seguir o formato de etiqueta de idioma BCP 47 +3. **Restrições de Cardinalidade**: `minCardinality` ≤ `maxCardinality` quando ambos são especificados +4. **Propriedades Funcionais**: Não podem ter `maxCardinality` > 1 + +## Suporte a Formatos de Importação/Exportação + +Embora o formato interno seja JSON, o sistema suporta a conversão para/de formatos de ontologia padrão: + +**Turtle (.ttl)** - Serialização RDF compacta +**RDF/XML (.rdf, .owl)** - Formato padrão W3C +**OWL/XML (.owx)** - Formato XML específico para OWL +**JSON-LD (.jsonld)** - JSON para Dados Vinculados + +## Referências + +[OWL 2 Web Ontology Language](https://www.w3.org/TR/owl2-overview/) +[RDF Schema 1.1](https://www.w3.org/TR/rdf-schema/) +[XML Schema Datatypes](https://www.w3.org/TR/xmlschema-2/) +[BCP 47 Language Tags](https://tools.ietf.org/html/bcp47) \ No newline at end of file diff --git a/docs/tech-specs/ontology.tr.md b/docs/tech-specs/ontology.tr.md new file mode 100644 index 00000000..03c399f6 --- /dev/null +++ b/docs/tech-specs/ontology.tr.md @@ -0,0 +1,286 @@ +# Ontoloji Yapısı Teknik Özellikleri + +## Genel Bakış + +Bu özellik, TrustGraph sistemindeki ontolojilerin yapısını ve biçimini tanımlar. Ontolojiler, sınıfları, özellikleri ve ilişkileri tanımlayan resmi bilgi modelleri sağlar ve akıl yürütme ve çıkarım yeteneklerini destekler. Sistem, OWL'den ilham alan bir yapılandırma biçimi kullanır ve bu, OWL/RDFS kavramlarını geniş ölçüde temsil ederken aynı zamanda TrustGraph'ın gereksinimleri için optimize edilmiştir. + +**İsimlendirme Kuralları**: Bu proje, yılan_biçimi yerine tüm tanımlayıcılar (yapılandırma anahtarları, API uç noktaları, modül adları vb.) için kebab-case kullanır. + +## Hedefler + +**Sınıf ve Özellik Yönetimi**: OWL benzeri sınıfları, özellikleri, etki alanlarını, aralıkları ve tür kısıtlamalarını tanımlayın. +**Zengin Anlamsal Destek**: Etiketler, çoklu dil desteği ve resmi kısıtlamalar dahil olmak üzere kapsamlı RDFS/OWL özellikleri sağlayın. +**Çoklu Ontoloji Desteği**: Birden fazla ontolojinin birlikte var olmasına ve etkileşimde olmasına izin verin. +**Doğrulama ve Akıl Yürütme**: Ontolojilerin, tutarlılık kontrolü ve çıkarım desteği ile OWL benzeri standartlara uygun olduğundan emin olun. +**Standart Uyumluluğu**: İç optimizasyonu korurken standart formatlarda (Turtle, RDF/XML, OWL/XML) içe/dışa aktarma desteğini sağlayın. + +## Arka Plan + +TrustGraph, ontolojileri esnek bir anahtar-değer sisteminde yapılandırma öğeleri olarak saklar. Biçim OWL (Web Ontology Language) tarafından ilham alınmış olsa da, TrustGraph'ın belirli kullanım durumları için optimize edilmiştir ve tüm OWL özelliklerine kesin olarak uymamaktadır. + +TrustGraph'taki ontolojiler şunları sağlar: +Resmi nesne türlerinin ve özelliklerinin tanımlanması +Özellik etki alanlarının, aralıklarının ve tür kısıtlamalarının belirtilmesi +Mantıksal akıl yürütme ve çıkarım +Karmaşık ilişkiler ve kardinalite kısıtlamaları +Uluslararasılaştırma için çoklu dil desteği + +## Ontoloji Yapısı + +### Yapılandırma Depolama + +Ontolojiler, aşağıdaki kalıba sahip yapılandırma öğeleri olarak saklanır: +**Tür**: `ontology` +**Anahtar**: Benzersiz ontoloji tanımlayıcısı (örneğin, `natural-world`, `domain-model`) +**Değer**: JSON formatında eksiksiz ontoloji + +### JSON Yapısı + +Ontoloji JSON biçimi, dört ana bölümden oluşur: + +#### 1. Meta Veriler + +Ontoloji hakkında idari ve tanımlayıcı bilgiler içerir: + +```json +{ + "metadata": { + "name": "The natural world", + "description": "Ontology covering the natural order", + "version": "1.0.0", + "created": "2025-09-20T12:07:37.068Z", + "modified": "2025-09-20T12:12:20.725Z", + "creator": "current-user", + "namespace": "http://trustgraph.ai/ontologies/natural-world", + "imports": ["http://www.w3.org/2002/07/owl#"] + } +} +``` + +**Alanlar:** +`name`: Ontolojinin insan tarafından okunabilir adı +`description`: Ontolojinin amacının kısa açıklaması +`version`: Semantik sürüm numarası +`created`: Oluşturulma zamanının ISO 8601 zaman damgası +`modified`: Son değişiklik zamanının ISO 8601 zaman damgası +`creator`: Ontolojiyi oluşturan kullanıcı/sistemin kimliği +`namespace`: Ontoloji öğeleri için temel URI +`imports`: İçe aktarılan ontoloji URI'lerinin dizisi + +#### 2. Sınıflar + +Nesne türlerini ve hiyerarşik ilişkilerini tanımlar: + +```json +{ + "classes": { + "animal": { + "uri": "http://trustgraph.ai/ontologies/natural-world#animal", + "type": "owl:Class", + "rdfs:label": [{"value": "Animal", "lang": "en"}], + "rdfs:comment": "An animal", + "rdfs:subClassOf": "lifeform", + "owl:equivalentClass": ["creature"], + "owl:disjointWith": ["plant"], + "dcterms:identifier": "ANI-001" + } + } +} +``` + +**Desteklenen Özellikler:** +`uri`: Sınıfın tam URI'si +`type`: Her zaman `"owl:Class"` +`rdfs:label`: Dil etiketli etiketlerin dizisi +`rdfs:comment`: Sınıfın açıklaması +`rdfs:subClassOf`: Üst sınıf tanımlayıcısı (tekli miras) +`owl:equivalentClass`: Eşdeğer sınıf tanımlayıcılarının dizisi +`owl:disjointWith`: Ayrık sınıf tanımlayıcılarının dizisi +`dcterms:identifier`: İsteğe bağlı harici referans tanımlayıcısı + +#### 3. Nesne Özellikleri + +Örnekleri diğer örneklere bağlayan özellikler: + +```json +{ + "objectProperties": { + "has-parent": { + "uri": "http://trustgraph.ai/ontologies/natural-world#has-parent", + "type": "owl:ObjectProperty", + "rdfs:label": [{"value": "has parent", "lang": "en"}], + "rdfs:comment": "Links an animal to its parent", + "rdfs:domain": "animal", + "rdfs:range": "animal", + "owl:inverseOf": "parent-of", + "owl:functionalProperty": false + } + } +} +``` + +**Desteklenen Özellikler:** +`uri`: Özelliğin tam URI'si +`type`: Her zaman `"owl:ObjectProperty"` +`rdfs:label`: Dil etiketli etiketlerin dizisi +`rdfs:comment`: Özelliğin açıklaması +`rdfs:domain`: Bu özelliğe sahip sınıf tanımlayıcısı +`rdfs:range`: Özellik değerleri için sınıf tanımlayıcısı +`owl:inverseOf`: Ters özelliğin tanımlayıcısı +`owl:functionalProperty`: En fazla bir değer olduğunu gösteren boolean değeri +`owl:inverseFunctionalProperty`: Benzersiz tanımlayıcı özellikleri için boolean değeri + +#### 4. Veri Tipi Özellikleri + +Örnekleri, literal değerlere bağlayan özellikler: + +```json +{ + "datatypeProperties": { + "number-of-legs": { + "uri": "http://trustgraph.ai/ontologies/natural-world#number-of-legs", + "type": "owl:DatatypeProperty", + "rdfs:label": [{"value": "number of legs", "lang": "en"}], + "rdfs:comment": "Count of number of legs of the animal", + "rdfs:domain": "animal", + "rdfs:range": "xsd:nonNegativeInteger", + "owl:functionalProperty": true, + "owl:minCardinality": 0, + "owl:maxCardinality": 1 + } + } +} +``` + +**Desteklenen Özellikler:** +`uri`: Özelliğin tam URI'si +`type`: Her zaman `"owl:DatatypeProperty"` +`rdfs:label`: Dil etiketli etiketlerin dizisi +`rdfs:comment`: Özelliğin açıklaması +`rdfs:domain`: Bu özelliğe sahip sınıf tanımlayıcısı +`rdfs:range`: Özellik değerleri için XSD veri türü +`owl:functionalProperty`: En fazla bir değer olduğunu gösteren boolean değeri +`owl:minCardinality`: Minimum değer sayısı (isteğe bağlı) +`owl:maxCardinality`: Maksimum değer sayısı (isteğe bağlı) +`owl:cardinality`: Tam değer sayısı (isteğe bağlı) + +### Desteklenen XSD Veri Türleri + +Aşağıdaki XML Şema veri türleri, veri türü özellik aralıkları için desteklenmektedir: + +`xsd:string` - Metin değerleri +`xsd:integer` - Tamsayılar +`xsd:nonNegativeInteger` - Negatif olmayan tamsayılar +`xsd:float` - Ondalık sayılar +`xsd:double` - Çift hassasiyetli sayılar +`xsd:boolean` - Doğru/yanlış değerleri +`xsd:dateTime` - Tarih ve saat değerleri +`xsd:date` - Tarih değerleri +`xsd:anyURI` - URI referansları + +### Dil Desteği + +Etiketler ve yorumlar, W3C dil etiketi biçimini kullanarak çoklu dilleri destekler: + +```json +{ + "rdfs:label": [ + {"value": "Animal", "lang": "en"}, + {"value": "Tier", "lang": "de"}, + {"value": "Animal", "lang": "es"} + ] +} +``` + +## Örnek Ontoloji + +İşte basit bir ontolojinin eksiksiz bir örneği: + +```json +{ + "metadata": { + "name": "The natural world", + "description": "Ontology covering the natural order", + "version": "1.0.0", + "created": "2025-09-20T12:07:37.068Z", + "modified": "2025-09-20T12:12:20.725Z", + "creator": "current-user", + "namespace": "http://trustgraph.ai/ontologies/natural-world", + "imports": ["http://www.w3.org/2002/07/owl#"] + }, + "classes": { + "lifeform": { + "uri": "http://trustgraph.ai/ontologies/natural-world#lifeform", + "type": "owl:Class", + "rdfs:label": [{"value": "Lifeform", "lang": "en"}], + "rdfs:comment": "A living thing" + }, + "animal": { + "uri": "http://trustgraph.ai/ontologies/natural-world#animal", + "type": "owl:Class", + "rdfs:label": [{"value": "Animal", "lang": "en"}], + "rdfs:comment": "An animal", + "rdfs:subClassOf": "lifeform" + }, + "cat": { + "uri": "http://trustgraph.ai/ontologies/natural-world#cat", + "type": "owl:Class", + "rdfs:label": [{"value": "Cat", "lang": "en"}], + "rdfs:comment": "A cat", + "rdfs:subClassOf": "animal" + }, + "dog": { + "uri": "http://trustgraph.ai/ontologies/natural-world#dog", + "type": "owl:Class", + "rdfs:label": [{"value": "Dog", "lang": "en"}], + "rdfs:comment": "A dog", + "rdfs:subClassOf": "animal", + "owl:disjointWith": ["cat"] + } + }, + "objectProperties": {}, + "datatypeProperties": { + "number-of-legs": { + "uri": "http://trustgraph.ai/ontologies/natural-world#number-of-legs", + "type": "owl:DatatypeProperty", + "rdfs:label": [{"value": "number-of-legs", "lang": "en"}], + "rdfs:comment": "Count of number of legs of the animal", + "rdfs:range": "xsd:nonNegativeInteger", + "rdfs:domain": "animal" + } + } +} +``` + +## Doğrulama Kuralları + +### Yapısal Doğrulama + +1. **URI Tutarlılığı**: Tüm URI'ler `{namespace}#{identifier}` kalıbını takip etmelidir. +2. **Sınıf Hiyerarşisi**: `rdfs:subClassOf` içinde döngüsel miras ilişkisi olmamalıdır. +3. **Özellik Alanları/Aralıkları**: Mevcut sınıflara veya geçerli XSD türlerine başvurmalıdır. +4. **Ayrık Sınıflar**: Birbirinin alt sınıfı olamazlar. +5. **Ters Özellikler**: Belirtilmişse, çift yönlü olmalıdır. + +### Anlamsal Doğrulama + +1. **Benzersiz Tanımlayıcılar**: Sınıf ve özellik tanımlayıcıları, bir ontoloji içinde benzersiz olmalıdır. +2. **Dil Etiketleri**: BCP 47 dil etiketi formatını takip etmelidir. +3. **Kardinalite Kısıtlamaları**: Hem belirtilmişse, `minCardinality` ≤ `maxCardinality` olmalıdır. +4. **Fonksiyonel Özellikler**: `maxCardinality` > 1 olamaz. + +## İçe/Dışa Aktarma Formatı Desteği + +İç format JSON olmasına rağmen, sistem standart ontoloji formatlarına dönüştürmeyi destekler: + +**Turtle (.ttl)** - RDF'nin kompakt seri hale getirilmesi +**RDF/XML (.rdf, .owl)** - W3C standardı formatı +**OWL/XML (.owx)** - OWL'e özel XML formatı +**JSON-LD (.jsonld)** - Bağlı Veri için JSON + +## Referanslar + +[OWL 2 Web Ontology Language](https://www.w3.org/TR/owl2-overview/) +[RDF Schema 1.1](https://www.w3.org/TR/rdf-schema/) +[XML Schema Datatypes](https://www.w3.org/TR/xmlschema-2/) +[BCP 47 Language Tags](https://tools.ietf.org/html/bcp47) \ No newline at end of file diff --git a/docs/tech-specs/ontorag.ar.md b/docs/tech-specs/ontorag.ar.md new file mode 100644 index 00000000..8bc2c0de --- /dev/null +++ b/docs/tech-specs/ontorag.ar.md @@ -0,0 +1,1067 @@ +# المواصفات الفنية لنظام OntoRAG: استخراج المعرفة القائم على علم الأنطولوجيا والاستعلام. + +## نظرة عامة + +OntoRAG هو نظام لاستخراج المعرفة والاستعلام القائم على علم الأنطولوجيا يفرض اتساقًا دلاليًا صارمًا أثناء كل من استخراج ثلاثيات المعرفة من النصوص غير المنظمة والاستعلام عن الرسم البياني المعرفي الناتج. على غرار GraphRAG ولكن مع قيود الأنطولوجيا الرسمية، يضمن OntoRAG أن جميع الثلاثيات المستخرجة تتوافق مع الهياكل الأنطولوجية المحددة مسبقًا ويوفر قدرات استعلام واعية دلاليًا. + +يستخدم النظام مطابقة التشابه المتجهي لتحديد مجموعات فرعية ذات صلة من الأنطولوجيا ديناميكيًا لكل من عمليات الاستخراج والاستعلام، مما يتيح معالجة مركزة ومناسبة للسياق مع الحفاظ على الصحة الدلالية. + +**اسم الخدمة**: `kg-extract-ontology` + +## الأهداف + +**استخراج متوافق مع الأنطولوجيا**: التأكد من أن جميع الثلاثيات المستخرجة تتوافق بشكل صارم مع الأنطولوجيات المحملة. +**تحديد السياق الديناميكي**: استخدام التضمينات لتحديد مجموعات فرعية ذات صلة من الأنطولوجيا لكل جزء. +**الاتساق الدلالي**: الحفاظ على التسلسلات الهرمية للفئات، ونطاقات/مدى الخصائص، والقيود. +**معالجة فعالة**: استخدام مخازن متجهات في الذاكرة لمطابقة سريعة لعناصر الأنطولوجيا. +**هيكلة قابلة للتوسع**: دعم أنطولوجيات متعددة متزامنة ذات مجالات مختلفة. + +## الخلفية + +تعمل خدمات استخراج المعرفة الحالية (`kg-extract-definitions`، `kg-extract-relationships`) بدون قيود رسمية، مما قد يؤدي إلى إنتاج ثلاثيات غير متسقة أو غير متوافقة. يعالج OntoRAG ذلك عن طريق: + +1. تحميل أنطولوجيات رسمية تحدد الفئات والخصائص الصالحة. +2. استخدام التضمينات لمطابقة محتوى النص مع عناصر الأنطولوجيا ذات الصلة. +3. تقييد الاستخراج لإنتاج ثلاثيات متوافقة مع الأنطولوجيا فقط. +4. توفير التحقق الدلالي للمعرفة المستخرجة. + +يجمع هذا النهج بين مرونة الاستخراج العصبي ودقة تمثيل المعرفة الرسمي. + +## التصميم الفني + +### البنية + +يتكون نظام OntoRAG من المكونات التالية: + +``` +┌─────────────────┐ +│ Configuration │ +│ Service │ +└────────┬────────┘ + │ Ontologies + ▼ +┌─────────────────┐ ┌──────────────┐ +│ kg-extract- │────▶│ Embedding │ +│ ontology │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ │ + ▼ ▼ +┌─────────────────┐ ┌──────────────┐ +│ In-Memory │◀────│ Ontology │ +│ Vector Store │ │ Embedder │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Sentence │────▶│ Chunker │ +│ Splitter │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Ontology │────▶│ Vector │ +│ Selector │ │ Search │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Prompt │────▶│ Prompt │ +│ Constructor │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ +│ Triple Output │ +└─────────────────┘ +``` + +### تفاصيل المكون + +#### 1. مُحمِّل الأونتولوجيا + +**الغرض**: يسترجع ويحلل تكوينات الأونتولوجيا من خدمة التكوين باستخدام تحديثات تعتمد على الأحداث. + +**التنفيذ**: +يستخدم مُحمِّل الأونتولوجيا قائمة انتظار ConfigPush الخاصة بـ TrustGraph لتلقي تحديثات تكوين الأونتولوجيا التي تعتمد على الأحداث. عندما تتم إضافة عنصر تكوين من نوع "أونتولوجيا" أو تعديله، يتلقى المُحمِّل التحديث عبر قائمة انتظار config-update ويحلل هيكل JSON الذي يحتوي على البيانات الوصفية والفئات وخصائص الكائنات وخصائص أنواع البيانات. يتم تخزين هذه الأونتولوجيات التي تم تحليلها في الذاكرة ككائنات منظمة يمكن الوصول إليها بكفاءة أثناء عملية الاستخراج. + +**العمليات الرئيسية**: +الاشتراك في قائمة انتظار config-update لتكوينات من نوع الأونتولوجيا +تحليل هياكل الأونتولوجيا بتنسيق JSON إلى كائنات OntologyClass و OntologyProperty +التحقق من صحة هيكل الأونتولوجيا واتساقه +تخزين الأونتولوجيات التي تم تحليلها مؤقتًا في الذاكرة للوصول السريع +التعامل مع المعالجة الخاصة بكل تدفق باستخدام مخازن متجهة خاصة بالتدفق + +**موقع التنفيذ**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_loader.py` + +#### 2. مُضمِّن الأونتولوجيا + +**الغرض**: ينشئ تضمينات متجهة لجميع عناصر الأونتولوجيا لتمكين مطابقة التشابه الدلالي. + +**التنفيذ**: +يعالج مُضمِّن الأونتولوجيا كل عنصر في الأونتولوجيات التي تم تحميلها (الفئات وخصائص الكائنات وخصائص أنواع البيانات) وينشئ تضمينات متجهة باستخدام خدمة EmbeddingsClientSpec. لكل عنصر، يجمع بين معرف العنصر والتسميات والوصف (التعليق) لإنشاء تمثيل نصي. ثم يتم تحويل هذا النص إلى تضمين متجهي عالي الأبعاد يلتقط معناه الدلالي. يتم تخزين هذه التضمينات في مخزن متجهات FAISS في الذاكرة الخاص بكل تدفق مع بيانات وصفية حول نوع العنصر والأونتولوجيا المصدر والتعريف الكامل. يكتشف المُضمِّن تلقائيًا بُعد التضمين من الاستجابة الأولى للتضمين. + +**العمليات الرئيسية**: +إنشاء تمثيلات نصية من معرفات العناصر والتسميات والتعليقات +إنشاء تضمينات عبر EmbeddingsClientSpec (باستخدام asyncio.gather للمعالجة الدفعية) +تخزين التضمينات مع بيانات وصفية شاملة في مخزن متجهات FAISS +الفهرسة حسب الأونتولوجيا ونوع العنصر ومعرف العنصر للاسترجاع الفعال +الكشف التلقائي عن أبعاد التضمين لتهيئة مخزن المتجهات +التعامل مع نماذج التضمين الخاصة بكل تدفق مع مخازن متجهة مستقلة + +**موقع التنفيذ**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_embedder.py` + +#### 3. معالج النصوص (مقسم الجمل) + +**الغرض**: يقوم بتقسيم أجزاء النص إلى أجزاء دقيقة لتمكين مطابقة دقيقة للأونتولوجيا. + +**التنفيذ**: +يستخدم معالج النصوص NLTK لترميز الجملة ووسم أجزاء الكلام لتقسيم أجزاء النص الواردة إلى جمل. يتعامل مع توافق إصدارات NLTK عن طريق محاولة تنزيل `punkt_tab` و `averaged_perceptron_tagger_eng` مع الرجوع إلى الإصدارات الأقدم إذا لزم الأمر. يتم تقسيم كل جزء نصي إلى جمل فردية يمكن مطابقتها بشكل مستقل مع عناصر الأونتولوجيا. + +**العمليات الرئيسية**: +تقسيم النص إلى جمل باستخدام ترميز الجملة الخاص بـ NLTK +التعامل مع توافق إصدارات NLTK (punkt_tab مقابل punkt) +إنشاء كائنات TextSegment مع النص ومعلومات الموضع +دعم كل من الجمل الكاملة والأجزاء الفردية + +**موقع التنفيذ**: `trustgraph-flow/trustgraph/extract/kg/ontology/text_processor.py` + +#### 4. مُحدد الأونتولوجيا + +**الغرض**: يحدد المجموعة الفرعية الأكثر صلة من عناصر الأونتولوجيا للقطعة النصية الحالية. + +**التنفيذ**: +يقوم مُحدد الأونتولوجيا بإجراء مطابقة دلالية بين أجزاء النص وعناصر الأونتولوجيا باستخدام بحث تشابه متجهات FAISS. لكل جملة من قطعة النص، يقوم بإنشاء تضمين والبحث في مخزن المتجهات عن عناصر الأونتولوجيا الأكثر تشابهًا باستخدام تشابه جيب التمام مع حد عتبة قابل للتكوين (افتراضي 0.3). بعد جمع جميع العناصر ذات الصلة، يقوم بإجراء تحليل شامل للتبعيات: إذا تم تحديد فئة، يتم تضمين الفئات الأصلية؛ إذا تم تحديد خاصية، تتم إضافة الفئات النطاق والنطاق. بالإضافة إلى ذلك، لكل فئة محددة، فإنه يتضمن تلقائيًا **جميع الخصائص التي تشير إلى تلك الفئة** في نطاقها أو نطاقها. يضمن ذلك أن عملية الاستخراج لديها إمكانية الوصول إلى جميع خصائص العلاقة ذات الصلة. + +**العمليات الرئيسية**: +إنشاء تضمينات لكل جزء نصي (جمل) +إجراء بحث أقرب جار في مخزن المتجهات FAISS (top_k=10، threshold=0.3) +تطبيق حد التشابه لتصفية التطابقات الضعيفة +حل التبعيات (الفئات الأصلية، النطاقات، المجالات) +**إضافة تلقائيًا جميع الخصائص المتعلقة بالفئات المحددة** (مطابقة المجال/النطاق) +إنشاء مجموعة فرعية متماسكة من علم الأنطولوجيا مع جميع العلاقات المطلوبة +إزالة العناصر المكررة التي تظهر عدة مرات + +**موقع التنفيذ**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_selector.py` + +#### 5. بناء المطالبات (Prompt Construction) + +**الغرض**: إنشاء مطالبات منظمة توجه نموذج اللغة الكبير (LLM) لاستخراج فقط الثلاثيات المتوافقة مع علم الأنطولوجيا. + +**التنفيذ**: +تستخدم خدمة الاستخراج قالب Jinja2 يتم تحميله من `ontology-prompt.md` والذي يقوم بتنسيق مجموعة فرعية من علم الأنطولوجيا والنص لاستخراج LLM. يتكرر القالب ديناميكيًا عبر الفئات وخصائص الكائنات وخصائص البيانات باستخدام بناء جملة Jinja2، حيث يتم تقديم كل منها مع أوصافها، ومجالاتها، ونطاقاتها، وعلاقاتها الهرمية. تتضمن المطالبة قواعد صارمة لاستخدام عناصر علم الأنطولوجيا المقدمة فقط وتطلب تنسيق JSON للإخراج لسهولة التحليل. + +**العمليات الرئيسية**: +استخدام قالب Jinja2 مع حلقات عبر عناصر علم الأنطولوجيا +تنسيق الفئات مع علاقات الأبوة (subclass_of) والتعليقات +تنسيق الخصائص مع قيود المجال/النطاق والتعليقات +تضمين قواعد استخراج صريحة ومتطلبات تنسيق الإخراج +استدعاء خدمة المطالبة باستخدام معرف القالب "extract-with-ontologies" + +**موقع القالب**: `ontology-prompt.md` +**موقع التنفيذ**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` (طريقة build_extraction_variables) + +#### 6. خدمة الاستخراج الرئيسية + +**الغرض**: تنسيق جميع المكونات لأداء استخراج شامل قائم على علم الأنطولوجيا. + +**التنفيذ**: +خدمة الاستخراج الرئيسية (KgExtractOntology) هي الطبقة التي تدير سير عمل الاستخراج بأكمله. إنها تستخدم نمط TrustGraph's FlowProcessor مع تهيئة المكونات الخاصة بكل تدفق. عندما يصل تحديث لتكوين علم الأنطولوجيا، فإنها تقوم بتهيئة أو تحديث المكونات الخاصة بالتدفق (محمل علم الأنطولوجيا، والمُضمّن، ومعالج النصوص، والمحدد). عندما يصل جزء نص للمعالجة، فإنها تنسق المسار: تقسيم النص إلى أجزاء، والعثور على عناصر علم الأنطولوجيا ذات الصلة من خلال البحث عن المتجهات، وإنشاء مطالبة مقيدة، واستدعاء خدمة المطالبة، وتحليل الاستجابة والتحقق من صحتها، وإنشاء ثلاثيات تعريف علم الأنطولوجيا، وإخراج كل من ثلاثيات المحتوى وسياقات الكيانات. + +**مسار الاستخراج**: +1. استقبال جزء نص عبر قائمة الانتظار chunks-input +2. تهيئة مكونات التدفق إذا لزم الأمر (في أول جزء أو عند تحديث التكوين) +3. تقسيم النص إلى جمل باستخدام NLTK +4. البحث في مخزن المتجهات FAISS للعثور على مفاهيم علم الأنطولوجيا ذات الصلة +5. بناء مجموعة فرعية من علم الأنطولوجيا مع إضافة تلقائي للخصائص +6. إنشاء متغيرات مطالبة من قالب Jinja2 +7. استدعاء خدمة المطالبة باستخدام قالب extract-with-ontologies +8. تحليل استجابة JSON إلى ثلاثيات منظمة +9. التحقق من صحة الثلاثيات وتوسيع معرفات الموارد الموحدة (URIs) إلى معرفات موارد موحدة كاملة لعلم الأنطولوجيا +10. إنشاء ثلاثيات تعريف علم الأنطولوجيا (الفئات والخصائص مع التسميات والتعليقات والمجالات والنطاقات) +11. بناء سياقات الكيانات من جميع الثلاثيات +12. الإخراج إلى قوائم الانتظار triples و entity-contexts + +**الميزات الرئيسية**: +مخازن متجهات خاصة بكل تدفق تدعم نماذج تضمين مختلفة +تحديثات علم الأنطولوجيا المستندة إلى الأحداث عبر قائمة الانتظار config-update +توسيع تلقائي لمعرفات الموارد الموحدة باستخدام معرفات موارد موحدة لعلم الأنطولوجيا +إضافة عناصر علم الأنطولوجيا إلى الرسم البياني للمعرفة مع بيانات التعريف الكاملة +تتضمن سياقات الكيانات عناصر المحتوى وعناصر علم الأنطولوجيا + +**موقع التنفيذ**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` + +### التكوين + +تستخدم الخدمة نهج التكوين القياسي لـ TrustGraph مع وسيطات سطر الأوامر: + +```bash +kg-extract-ontology \ + --id kg-extract-ontology \ + --pulsar-host localhost:6650 \ + --input-queue chunks \ + --config-input-queue config-update \ + --output-queue triples \ + --entity-contexts-output-queue entity-contexts +``` + +**المعلمات الأساسية للتكوين**: +`similarity_threshold`: 0.3 (افتراضي، يمكن تكوينه في الكود) +`top_k`: 10 (عدد عناصر الأونطولوجيا التي يتم استرجاعها لكل جزء) +`vector_store`: فهرس FAISS FlatIP لكل تدفق مع أبعاد يتم اكتشافها تلقائيًا +`text_processor`: NLTK مع تجزئة الجمل punkt_tab +`prompt_template`: "extract-with-ontologies" (قالب Jinja2) + +**تكوين الأونطولوجيا**: +يتم تحميل الأونطولوجيات ديناميكيًا عبر قائمة انتظار التحديثات (config-update) من النوع "ontology". + +### تدفق البيانات + +1. **مرحلة التهيئة** (لكل تدفق): + استقبال تكوين الأونطولوجيا عبر قائمة انتظار التحديثات. + تحليل كائن JSON للأونطولوجيا إلى كائنات OntologyClass و OntologyProperty. + إنشاء تضمينات لجميع عناصر الأونطولوجيا باستخدام EmbeddingsClientSpec. + تخزين التضمينات في مخزن متجه FAISS الخاص بكل تدفق. + اكتشاف أبعاد التضمين تلقائيًا من الاستجابة الأولى. + +2. **مرحلة الاستخراج** (لكل جزء): + استقبال جزء من قائمة انتظار chunks-input. + تقسيم الجزء إلى جمل باستخدام NLTK. + حساب تضمينات لكل جملة. + البحث في مخزن المتجهات FAISS عن عناصر الأونطولوجيا ذات الصلة. + إنشاء مجموعة فرعية من الأونطولوجيا مع تضمين تلقائي للخصائص. + إنشاء متغيرات قالب Jinja2 مع النص والأونطولوجيا. + استدعاء خدمة المطالبة باستخدام قالب extract-with-ontologies. + تحليل استجابة JSON والتحقق من صحة الثلاثيات. + توسيع الروابط باستخدام روابط الأونطولوجيا. + إنشاء ثلاثيات تعريف الأونطولوجيا. + إنشاء سياقات الكيانات من جميع الثلاثيات. + الإخراج إلى قوائم انتظار triples و entity-contexts. + +### مخزن المتجهات في الذاكرة + +**الغرض**: يوفر بحث سريع قائم على الذاكرة عن طريق تشابه للعثور على تطابقات لعناصر الأونطولوجيا. + +**التنفيذ: FAISS** + +يستخدم النظام **FAISS (Facebook AI Similarity Search)** مع IndexFlatIP للبحث الدقيق عن التشابه بناءً على الجيب التمامي. الميزات الرئيسية: + +**IndexFlatIP**: بحث دقيق عن التشابه بناءً على الجيب التمامي باستخدام الضرب الداخلي. +**الاكتشاف التلقائي**: يتم تحديد البعد من استجابة التضمين الأولى. +**مخازن خاصة بكل تدفق**: يحتوي كل تدفق على مخزن متجه مستقل لنماذج تضمين مختلفة. +**التطبيع**: يتم تطبيع جميع المتجهات قبل الفهرسة. +**عمليات الدفعات**: إضافة دفعات فعالة للتحميل الأولي للأونطولوجيا. + +**موقع التنفيذ**: `trustgraph-flow/trustgraph/extract/kg/ontology/vector_store.py` + +### خوارزمية اختيار المجموعة الفرعية من الأونطولوجيا + +**الغرض**: يختار ديناميكيًا الجزء ذي الصلة الأدنى لكل جزء نصي. + +**خطوات الخوارزمية التفصيلية**: + +1. **تقسيم النص**: + تقسيم الجزء المدخل إلى جمل باستخدام اكتشاف الجملة الخاص بمعالجة اللغة الطبيعية. + استخراج العبارات الاسمية وعبارات الأفعال والكيانات المسماة من كل جملة. + إنشاء هيكل هرمي من الأجزاء مع الحفاظ على السياق. + +2. **إنشاء التضمينات**: + إنشاء تضمينات متجهة لكل جزء نصي (جمل وعبارات). + استخدم نفس نموذج التضمين المستخدم لعناصر الأونطولوجيا. + تخزين التضمينات للأجزاء المتكررة لتحسين الأداء. + +3. **بحث عن التشابه**: + لكل تضمين جزء نصي، ابحث في مخزن المتجهات. + استرجع أفضل k (مثل 10) من عناصر الأونطولوجيا الأكثر تشابهًا. + تطبيق عتبة التشابه (مثل 0.7) لتصفية التطابقات الضعيفة. + تجميع النتائج عبر جميع الأجزاء، مع تتبع ترددات التطابقات. + +4. **حل التبعيات**: + لكل فئة محددة، قم بتضمين جميع الفئات الأصلية بشكل متكرر حتى الجذر. + لكل خاصية محددة، قم بتضمين الفئات الخاصة بالنطاق والنطاق. + بالنسبة للخصائص العكسية، تأكد من تضمين كلا الاتجاهين. + أضف الفئات المكافئة إذا كانت موجودة في الأونطولوجيا. + +5. **إنشاء المجموعة الفرعية**: + إزالة العناصر المكررة مع الحفاظ على العلاقات. + تنظيمها في فئات وخصائص كائن وخصائص بيانات. + تأكد من الحفاظ على جميع القيود والعلاقات. + إنشاء أونطولوجيا مصغرة مكتفية بذاتها وصالحة وكاملة. + +**شرح تفصيلي**: +بالنظر إلى النص: "The brown dog chased the white cat up the tree." +الأجزاء: ["brown dog", "white cat", "tree", "chased"] +العناصر المتطابقة: [dog (class), cat (class), animal (parent), chases (property)] +التبعيات: [animal (parent of dog and cat), lifeform (parent of animal)] +المجموعة الفرعية النهائية: أونطولوجيا مصغرة كاملة مع تسلسل هرمي للحيوانات وعلاقة المطاردة. + +### التحقق من صحة الثلاثيات + +**الغرض**: يضمن أن جميع الثلاثيات المستخرجة تتوافق بشكل صارم مع قيود الأونطولوجيا. + +**خوارزمية التحقق**: + +1. **التحقق من الفئة (Class Validation)**: + التحقق من أن الكيانات هي مثيلات للفئات المحددة في مجموعة الأنطولوجيا. + بالنسبة لخصائص الكائنات، التحقق من أن الكائنات هي أيضًا مثيلات صالحة للفئات. + التحقق من أسماء الفئات مقابل قاموس الفئات في الأنطولوجيا. + التعامل مع التسلسلات الهرمية للفئات - تعتبر مثيلات الفئات الفرعية صالحة لقيود الفئة الأصل. + +2. **التحقق من الخاصية (Property Validation)**: + التأكد من أن الرأس (predicate) يتوافق مع الخصائص في مجموعة الأنطولوجيا. + التمييز بين خصائص الكائنات (من كيان إلى كيان) وخصائص البيانات (من كيان إلى حرفي). + التحقق من أن أسماء الخصائص تتطابق تمامًا (مع الأخذ في الاعتبار مساحة الاسم إذا كانت موجودة). + +3. **التحقق من النطاق/المدى (Domain/Range Checking)**: + لكل خاصية مستخدمة كرأس، استرجاع النطاق والمدى الخاص بها. + التحقق من أن نوع الكيان يطابق أو يرث من نطاق الخاصية. + التحقق من أن نوع الكائن يطابق أو يرث من مدى الخاصية. + بالنسبة لخصائص البيانات، التحقق من أن الكائن هو حرفي من النوع XSD الصحيح. + +4. **التحقق من التعددية (Cardinality Validation)**: + تتبع عدد مرات استخدام الخاصية لكل كيان. + التحقق من الحد الأدنى للتعددية - التأكد من وجود الخصائص المطلوبة. + التحقق من الحد الأقصى للتعددية - التأكد من عدم استخدام الخاصية مرات عديدة جدًا. + بالنسبة للخصائص الوظيفية، التأكد من وجود قيمة واحدة على الأكثر لكل كيان. + +5. **التحقق من نوع البيانات (Datatype Validation)**: + تحليل القيم الحرفية وفقًا لأنواع XSD المعلنة الخاصة بها. + التحقق من أن الأعداد الصحيحة هي أرقام صالحة، وأن التواريخ منسقة بشكل صحيح، وما إلى ذلك. + التحقق من أنماط السلاسل النصية إذا تم تعريف قيود regex. + التأكد من أن عناوين URI ذات تنسيق صحيح لأنواع xsd:anyURI. + +**مثال على التحقق (Validation Example)**: +ثلاثية: ("Buddy", "has-owner", "John") +التحقق من أن "Buddy" مصنف على أنه فئة يمكن أن تحتوي على خاصية "has-owner". +التحقق من وجود "has-owner" في الأنطولوجيا. +التحقق من قيد النطاق: يجب أن يكون نوع الكيان هو "Pet" أو فئة فرعية. +التحقق من قيد المدى: يجب أن يكون نوع الكائن هو "Person" أو فئة فرعية. +إذا كان الأمر صالحًا، قم بإضافته إلى الإخراج؛ إذا كان غير صالح، قم بتسجيل الانتهاك وتجاهله. + +## اعتبارات الأداء (Performance Considerations) + +### استراتيجيات التحسين (Optimisation Strategies) + +1. **التخزين المؤقت للتضمين (Embedding Caching)**: تخزين التضمينات لأجزاء النص المستخدمة بشكل متكرر. +2. **المعالجة الدفعية (Batch Processing)**: معالجة أجزاء متعددة بالتوازي. +3. **فهرسة مخزن المتجهات (Vector Store Indexing)**: استخدم خوارزميات أقرب جار تقريبي للأنطولوجيات الكبيرة. +4. **تحسين المطالبة (Prompt Optimisation)**: قلل من حجم المطالبة عن طريق تضمين عناصر الأنطولوجيا الأساسية فقط. +5. **تخزين نتائج مؤقت (Result Caching)**: تخزين نتائج الاستخراج لقطع متطابقة. + +### قابلية التوسع (Scalability) + +**التوسع الأفقي (Horizontal Scaling)**: مثيلات مستخرجة متعددة مع ذاكرة تخزين مؤقت للأنطولوجيا مشتركة. +**تقسيم الأنطولوجيا (Ontology Partitioning)**: تقسيم الأنطولوجيات الكبيرة حسب المجال. +**المعالجة المتدفقة (Streaming Processing)**: معالجة الأجزاء أثناء وصولها دون تجميعها. +**إدارة الذاكرة (Memory Management)**: تنظيف دوري للتضمينات غير المستخدمة. + +## معالجة الأخطاء (Error Handling) + +### سيناريوهات الفشل (Failure Scenarios) + +1. **الأنطولوجيات المفقودة (Missing Ontologies)**: العودة إلى الاستخراج غير المقيد. +2. **فشل خدمة التضمين (Embedding Service Failure)**: استخدم التضمينات المخزنة مؤقتًا أو تخطى المطابقة الدلالية. +3. **انتهاء مهلة خدمة المطالبة (Prompt Service Timeout)**: أعد المحاولة باستخدام تأخير متزايد. +4. **تنسيق ثلاثي غير صالح (Invalid Triple Format)**: سجل وتجاهل الثلاثيات المشوهة. +5. **عدم اتساق الأنطولوجيا (Ontology Inconsistencies)**: الإبلاغ عن التعارضات واستخدام العناصر الصالحة الأكثر تحديدًا. + +### المراقبة (Monitoring) + +المقاييس الرئيسية التي يجب تتبعها: + +وقت تحميل الأنطولوجيا واستهلاك الذاكرة. +زمن انتقال إنشاء التضمين. +أداء البحث عن المتجهات. +وقت استجابة خدمة المطالبة. +دقة استخراج الثلاثيات. +معدل توافق الأنطولوجيا. + +## مسار الترحيل (Migration Path) + +### من المستخرجات الحالية (From Existing Extractors) + +1. **التشغيل بالتوازي (Parallel Operation)**: قم بتشغيله جنبًا إلى جنب مع المستخرجات الحالية في البداية. +2. **النشر التدريجي (Gradual Rollout)**: ابدأ بأنواع مستندات محددة. +3. **مقارنة الجودة (Quality Comparison)**: قارن جودة الإخراج مع المستخرجات الحالية. +4. **الترحيل الكامل (Full Migration)**: استبدل المستخرجات الحالية بمجرد التحقق من الجودة. + +### تطوير الأنطولوجيا (Ontology Development) + +1. **البدء من الموجود (Bootstrap from Existing)**: قم بإنشاء أنطولوجيات أولية من المعرفة الحالية. +2. **التحسين التكراري (Iterative Refinement)**: قم بتحسينها بناءً على أنماط الاستخراج. +3. **مراجعة الخبراء (Domain Expert Review)**: التحقق من صحتها مع خبراء الموضوع. +4. **التحسين المستمر (Continuous Improvement)**: قم بتحديثها بناءً على ملاحظات الاستخراج. + +## خدمة الاستعلام الحساسة للأنطولوجيا (Ontology-Sensitive Query Service) + +### نظرة عامة (Overview) + +توفر خدمة الاستعلام الحساسة للأنطولوجيا مسارات استعلام متعددة لدعم أنواع مختلفة من قواعد البيانات. + +**مكونات الخدمة**: +`onto-query-sparql`: يحول اللغة الطبيعية إلى SPARQL لقاعدة بيانات Cassandra. +`sparql-cassandra`: طبقة استعلام SPARQL لقاعدة بيانات Cassandra باستخدام rdflib. +`onto-query-cypher`: يحول اللغة الطبيعية إلى Cypher لقواعد بيانات الرسوم البيانية. +`cypher-executor`: تنفيذ استعلامات Cypher لـ Neo4j/Memgraph/FalkorDB. + +### العمارة + +``` + ┌─────────────────┐ + │ User Query │ + └────────┬────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Question │────▶│ Sentence │ + │ Analyser │ │ Splitter │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Ontology │────▶│ Vector │ + │ Matcher │ │ Store │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Backend Router │ + └────────┬────────┘ + │ + ┌───────────┴───────────┐ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ onto-query- │ │ onto-query- │ + │ sparql │ │ cypher │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ SPARQL │ │ Cypher │ + │ Generator │ │ Generator │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ sparql- │ │ cypher- │ + │ cassandra │ │ executor │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ Cassandra │ │ Neo4j/Memgraph/ │ + │ │ │ FalkorDB │ + └────────┬────────┘ └────────┬────────┘ + │ │ + └────────────┬───────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Answer │────▶│ Prompt │ + │ Generator │ │ Service │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Final Answer │ + └─────────────────┘ +``` + +### معالجة الاستعلامات (Query Processing Pipeline) + +#### 1. محلل الأسئلة (Question Analyser) + +**الغرض**: يقوم بتفكيك أسئلة المستخدم إلى مكونات دلالية لمطابقة الأنطولوجيا. + +**وصف الخوارزمية**: +يقوم محلل الأسئلة بتحليل السؤال باللغة الطبيعية وتقسيمه إلى أجزاء ذات معنى باستخدام نفس طريقة تقسيم الجمل المستخدمة في مسار الاستخراج. يحدد الكيانات والعلاقات والقيود الرئيسية المذكورة في السؤال. يتم تحليل كل جزء لتحديد نوع السؤال (حقيقي، تجميعي، مقارنة، إلخ) والتنسيق المتوقع للإجابة. يساعد هذا التقسيم في تحديد الأجزاء الأكثر صلة من الأنطولوجيا للإجابة على السؤال. + +**العمليات الرئيسية**: +تقسيم السؤال إلى جمل وعبارات +تحديد نوع السؤال والنية +استخراج الكيانات والعلاقات المذكورة +اكتشاف القيود والمرشحات في السؤال +تحديد التنسيق المتوقع للإجابة + +#### 2. مُطابق الأنطولوجيا للاستعلامات (Ontology Matcher for Queries) + +**الغرض**: يحدد مجموعة الأنطولوجيا ذات الصلة اللازمة للإجابة على السؤال. + +**وصف الخوارزمية**: +مشابه لمُحدد الأنطولوجيا في مسار الاستخراج، ولكنه مُحسَّن للإجابة على الأسئلة. يقوم المُطابق بإنشاء تضمينات لأجزاء السؤال ويبحث في مستودع المتجهات عن عناصر الأنطولوجيا ذات الصلة. ومع ذلك، فإنه يركز على إيجاد المفاهيم التي ستكون مفيدة لبناء الاستعلامات بدلاً من الاستخراج. يقوم بتوسيع التحديد ليشمل الخصائص ذات الصلة التي قد يتم استكشافها أثناء استكشاف الرسم البياني، حتى لو لم يتم ذكرها صراحةً في السؤال. على سبيل المثال، إذا تم طرح سؤال حول "الموظفين"، فقد يتضمن خصائص مثل "يعمل لدى" و "يدير" و "يقدم تقارير إلى" والتي يمكن أن تكون ذات صلة للعثور على معلومات الموظفين. + +**استراتيجية المطابقة**: +إنشاء تضمينات لأجزاء السؤال +العثور على مفاهيم الأنطولوجيا المذكورة بشكل مباشر +تضمين الخصائص التي تربط الفئات المذكورة +إضافة خصائص عكسية ومرتبطة للاستكشاف +تضمين الفئات الأبوية/الفرعية للاستعلامات الهرمية +بناء قسم الأنطولوجيا الموجه نحو الاستعلام + +#### 3. موجه الواجهة الخلفية (Backend Router) + +**الغرض**: يوجه الاستعلامات إلى مسار الاستعلام الخاص بالواجهة الخلفية المناسب بناءً على التكوين. + +**وصف الخوارزمية**: +يقوم موجه الواجهة الخلفية بفحص تكوين النظام لتحديد الواجهة الخلفية للرسم البياني النشطة (Cassandra أو Cypher-based). يوجه السؤال وقسم الأنطولوجيا إلى خدمة إنشاء الاستعلامات المناسبة. يمكن للموجه أيضًا دعم موازنة التحميل عبر واجهات خلفية متعددة أو آليات احتياطية إذا كانت الواجهة الخلفية الأساسية غير متاحة. + +**منطق التوجيه**: +التحقق من نوع الواجهة الخلفية المُكوَّن من إعدادات النظام +التوجيه إلى `onto-query-sparql` لواجهات خلفية Cassandra +التوجيه إلى `onto-query-cypher` لواجهات خلفية Neo4j/Memgraph/FalkorDB +دعم تكوينات متعددة الواجهات الخلفية مع توزيع الاستعلامات +التعامل مع سيناريوهات التعافي من الأعطال وموازنة التحميل + +#### 4. إنشاء استعلام SPARQL (`onto-query-sparql`) + +**الغرض**: يحول أسئلة اللغة الطبيعية إلى استعلامات SPARQL لتنفيذها على Cassandra. + +**وصف الخوارزمية**: +يأخذ مُنشئ استعلام SPARQL السؤال وقسم الأنطولوجيا وينشئ استعلام SPARQL مُحسَّنًا للتنفيذ على الواجهة الخلفية Cassandra. يستخدم خدمة المطالبة بقالب مُخصص لـ SPARQL والذي يتضمن دلالات RDF/OWL. يفهم المُنشئ أنماط SPARQL مثل مسارات الخصائص والعبارات الاختيارية والمرشحات التي يمكن أن تترجم بكفاءة إلى عمليات Cassandra. + +**قالب مطالبة إنشاء SPARQL**: +``` +Generate a SPARQL query for the following question using the provided ontology. + +ONTOLOGY CLASSES: +{classes} + +ONTOLOGY PROPERTIES: +{properties} + +RULES: +- Use proper RDF/OWL semantics +- Include relevant prefixes +- Use property paths for hierarchical queries +- Add FILTER clauses for constraints +- Optimise for Cassandra backend + +QUESTION: {question} + +SPARQL QUERY: +``` + +#### 5. توليد استعلامات Cypher (`onto-query-cypher`) + +**الغرض**: تحويل الأسئلة بلغة طبيعية إلى استعلامات Cypher لقواعد البيانات الرسومية. + +**وصف الخوارزمية**: +يقوم مُولِّد استعلامات Cypher بإنشاء استعلامات Cypher أصلية مُحسَّنة لـ Neo4j و Memgraph و FalkorDB. فهو يربط فئات علم الوجود بتسميات العقد والخصائص بعلاقات، باستخدام بناء جملة مطابقة الأنماط الخاص بـ Cypher. يتضمن المولد تحسينات خاصة بـ Cypher مثل تلميحات اتجاه العلاقة واستخدام الفهارس وتلميحات تخطيط الاستعلام. + +**قالب المطالبة لتوليد Cypher**: +``` +Generate a Cypher query for the following question using the provided ontology. + +NODE LABELS (from classes): +{classes} + +RELATIONSHIP TYPES (from properties): +{properties} + +RULES: +- Use MATCH patterns for graph traversal +- Include WHERE clauses for filters +- Use aggregation functions when needed +- Optimise for graph database performance +- Consider index hints for large datasets + +QUESTION: {question} + +CYPHER QUERY: +``` + +#### 6. محرك الاستعلامات SPARQL-Cassandra (`sparql-cassandra`) + +**الغرض**: ينفذ استعلامات SPARQL على Cassandra باستخدام مكتبة Python rdflib. + +**وصف الخوارزمية**: +يقوم محرك SPARQL-Cassandra بتنفيذ معالج SPARQL باستخدام مكتبة rdflib الخاصة بـ Python مع مخزن خلفي مخصص لـ Cassandra. يقوم بترجمة أنماط الرسم البياني SPARQL إلى استعلامات CQL المناسبة لـ Cassandra، مع معالجة عمليات الربط والتصفية والتجميع. يحتفظ المحرك بخريطة من RDF إلى Cassandra تحافظ على البنية الدلالية مع تحسينها لتخزين Cassandra القائم على نماذج الأعمدة. + +**ميزات التنفيذ**: +تطبيق واجهة rdflib Store لـ Cassandra. +دعم استعلامات SPARQL 1.1 مع الأنماط الشائعة. +ترجمة فعالة لأنماط الثلاثيات إلى CQL. +دعم مسارات الخصائص والاستعلامات الهرمية. +بث النتائج لمجموعات البيانات الكبيرة. +تجميع الاتصالات وتخزين الاستعلامات مؤقتًا. + +**مثال للترجمة**: +```sparql +SELECT ?animal WHERE { + ?animal rdf:type :Animal . + ?animal :hasOwner "John" . +} +``` +يترجم إلى استعلامات Cassandra مُحسّنة تستفيد من الفهارس ومفاتيح التقسيم. + +#### 7. مُنفّذ استعلامات Cypher (`cypher-executor`) + +**الغرض**: ينفذ استعلامات Cypher ضد Neo4j و Memgraph و FalkorDB. + +**وصف الخوارزمية**: +يوفر مُنفّذ Cypher واجهة موحدة لتنفيذ استعلامات Cypher عبر قواعد بيانات الرسوم البيانية المختلفة. يتعامل مع بروتوكولات الاتصال الخاصة بقاعدة البيانات، وتلميحات تحسين الاستعلام، وتوحيد تنسيق النتائج. يتضمن المُنفّذ منطق إعادة المحاولة، وتجميع الاتصالات، وإدارة المعاملات المناسبة لكل نوع قاعدة بيانات. + +**دعم قواعد بيانات متعددة**: +**Neo4j**: بروتوكول Bolt، ووظائف المعاملات، وتلميحات الفهرسة. +**Memgraph**: بروتوكول مخصص، ونتائج متدفقة، واستعلامات تحليلية. +**FalkorDB**: تكييف بروتوكول Redis، وتحسينات الذاكرة. + +**ميزات التنفيذ**: +إدارة اتصالات مستقلة عن قاعدة البيانات. +التحقق من صحة الاستعلام وفحص بناء الجملة. +فرض حدود المهلة والموارد. +تقسيم النتائج وتدفقها. +مراقبة الأداء لكل نوع قاعدة بيانات. +التبديل التلقائي بين مثيلات قاعدة البيانات. + +#### 8. مُولّد الإجابات + +**الغرض**: يجمع إجابة بلغة طبيعية من نتائج الاستعلام. + +**وصف الخوارزمية**: +يأخذ مُولّد الإجابات النتائج المنظمة للاستعلام والسؤال الأصلي، ثم يستخدم خدمة المطالبة لإنشاء إجابة شاملة. على عكس الاستجابات القائمة على القوالب البسيطة، فإنه يستخدم نموذج لغة كبير (LLM) لتفسير بيانات الرسم البياني في سياق السؤال، والتعامل مع العلاقات المعقدة، والتجميعات، والاستدلالات. يمكن للمولد شرح منطقه من خلال الرجوع إلى هيكل علم الوجود والعبارات الثلاثية المحددة المستخرجة من الرسم البياني. + +**عملية توليد الإجابات**: +تنسيق نتائج الاستعلام في سياق منظم. +تضمين تعريفات علم الوجود ذات الصلة من أجل الوضوح. +إنشاء مطالبة مع السؤال والنتائج. +إنشاء إجابة بلغة طبيعية عبر نموذج لغة كبير. +التحقق من صحة الإجابة مقابل نية الاستعلام. +إضافة اقتباسات إلى كيانات الرسم البياني المحددة إذا لزم الأمر. + +### التكامل مع الخدمات الحالية + +#### العلاقة مع GraphRAG + +**تكميلية**: توفر onto-query دقة دلالية بينما توفر GraphRAG تغطية واسعة. +**بنية تحتية مشتركة**: يستخدم كلاهما نفس الرسم البياني للمعرفة وخدمات المطالبة. +**توجيه الاستعلامات**: يمكن للنظام توجيه الاستعلامات إلى الخدمة الأكثر ملاءمة بناءً على نوع السؤال. +**الوضع الهجين**: يمكن الجمع بين كلا النهجين للحصول على إجابات شاملة. + +#### العلاقة مع استخراج OntoRAG + +**علم الوجود المشترك**: يستخدم نفس تكوينات علم الوجود التي يتم تحميلها بواسطة kg-extract-ontology. +**مخزن المتجهات المشترك**: يعيد استخدام التضمينات الموجودة في الذاكرة من خدمة الاستخراج. +**دلالات متسقة**: تعمل الاستعلامات على الرسوم البيانية التي تم إنشاؤها بنفس القيود الدلالية. + +### أمثلة الاستعلامات + +#### المثال 1: استعلام بسيط عن الكيان +**السؤال**: "ما هي الحيوانات التي تعتبر ثدييات؟" +**تطابق علم الوجود**: [حيوان، ثديي، subClassOf] +**الاستعلام الذي تم إنشاؤه**: +```cypher +MATCH (a:animal)-[:subClassOf*]->(m:mammal) +RETURN a.name +``` + +#### مثال 2: استعلام عن العلاقة +**السؤال**: "ما هي المستندات التي كتبها جون سميث؟" +**مطابقة علم الوجود**: [مستند، شخص، له-مؤلف] +**الاستعلام الناتج**: +```cypher +MATCH (d:document)-[:has-author]->(p:person {name: "John Smith"}) +RETURN d.title, d.date +``` + +#### مثال 3: استعلام التجميع +**السؤال**: "كم عدد أرجل القطط؟" +**مطابقة علم المفاهيم**: [قطة، عدد الأرجل (خاصية بيانات)] +**الاستعلام الناتج**: +```cypher +MATCH (c:cat) +RETURN c.name, c.number_of_legs +``` + +### التكوين + +```yaml +onto-query: + embedding_model: "text-embedding-3-small" + vector_store: + shared_with_extractor: true # Reuse kg-extract-ontology's store + query_builder: + model: "gpt-4" + temperature: 0.1 + max_query_length: 1000 + graph_executor: + timeout: 30000 # ms + max_results: 1000 + answer_generator: + model: "gpt-4" + temperature: 0.3 + max_tokens: 500 +``` + +### التحسينات في الأداء + +#### تحسين الاستعلام + +**تقليم علم الأنطولوجيا**: قم بتضمين عناصر علم الأنطولوجيا الضرورية فقط في المطالبات. +**تخزين مؤقت للاستعلامات**: قم بتخزين الأسئلة المتكررة والاستعلامات الخاصة بها مؤقتًا. +**تخزين مؤقت للنتائج**: قم بتخزين النتائج للاستعلامات المتطابقة ضمن إطار زمني. +**المعالجة الدفعية**: تعامل مع أسئلة متعددة ذات صلة في عبور رسم بياني واحد. + +#### اعتبارات قابلية التوسع + +**التنفيذ الموزع**: قم بتوازي الاستعلامات الفرعية عبر أقسام الرسم البياني. +**النتائج التدريجية**: قم بتدفق النتائج لمجموعات البيانات الكبيرة. +**موازنة التحميل**: وزّع حمل الاستعلام عبر مثيلات خدمة متعددة. +**مجموعات الموارد**: قم بإدارة مجموعات الاتصال بقواعد بيانات الرسم البياني. + +### معالجة الأخطاء + +#### سيناريوهات الفشل + +1. **توليد استعلام غير صالح**: التراجع إلى GraphRAG أو البحث عن الكلمات الرئيسية البسيطة. +2. **عدم تطابق علم الأنطولوجيا**: قم بتوسيع البحث ليشمل مجموعة فرعية أوسع من علم الأنطولوجيا. +3. **انتهاء مهلة الاستعلام**: قم بتبسيط الاستعلام أو زيادة المهلة. +4. **نتائج فارغة**: اقترح إعادة صياغة الاستعلام أو أسئلة ذات صلة. +5. **فشل خدمة LLM**: استخدم الاستعلامات المخزنة مؤقتًا أو الاستجابات المستندة إلى القوالب. + +### مقاييس المراقبة + +توزيع تعقيد الأسئلة. +أحجام أقسام علم الأنطولوجيا. +معدل نجاح توليد الاستعلام. +وقت تنفيذ استعلام الرسم البياني. +درجات جودة الإجابة. +معدلات الإصابة في ذاكرة التخزين المؤقت. +ترددات الأخطاء حسب النوع. + +## التحسينات المستقبلية + +1. **تعلم علم الأنطولوجيا**: قم بتوسيع علم الأنطولوجيا تلقائيًا بناءً على أنماط الاستخراج. +2. **تسجيل الثقة**: قم بتعيين درجات ثقة للثلاثيات المستخرجة. +3. **توليد الشرح**: قم بتوفير التفسير لعملية استخراج الثلاثيات. +4. **التعلم النشط**: اطلب التحقق البشري للاستخراج غير المؤكد. + +## اعتبارات الأمان + +1. **منع حقن المطالبات**: قم بتنظيف نص الكتلة قبل إنشاء المطالبة. +2. **حدود الموارد**: حد من استخدام الذاكرة لمخزن المتجهات. +3. **تحديد المعدل**: حد من طلبات الاستخراج لكل عميل. +4. **تسجيل التدقيق**: تتبع جميع طلبات الاستخراج والنتائج. + +## استراتيجية الاختبار + +### اختبار الوحدة + +مُحمِّل علم الأنطولوجيا بتنسيقات مختلفة. +توليد المتجهات وتخزينها. +خوارزميات تقسيم الجمل. +حسابات التشابه المتجهي. +تحليل الثلاثيات والتحقق من صحتها. + +### اختبار التكامل + +مسار استخراج شامل. +تكامل خدمة التكوين. +تفاعل خدمة المطالبة. +معالجة الاستخراج المتزامن. + +### اختبار الأداء + +التعامل مع علم الأنطولوجيا الكبيرة (1000+ فئة). +معالجة دفعية عالية الحجم. +استخدام الذاكرة تحت الحمل. +معايير زمن الوصول. + +## خطة التسليم + +### نظرة عامة + +سيتم تسليم نظام OntoRAG في أربع مراحل رئيسية، حيث توفر كل مرحلة قيمة متزايدة مع بناء النظام بأكمله. تركز الخطة على إنشاء إمكانات الاستخراج الأساسية أولاً، ثم إضافة وظائف الاستعلام، متبوعة بالتحسينات والميزات المتقدمة. + +### المرحلة 1: الأساس والاستخراج الأساسي + +**الهدف**: إنشاء مسار استخراج أساسي مدفوع بعلم الأنطولوجيا مع مطابقة بسيطة للمتجهات. + +#### الخطوة 1.1: أساس إدارة علم الأنطولوجيا +تنفيذ مُحمِّل تكوين علم الأنطولوجيا (`OntologyLoader`). +تحليل بنى JSON الخاصة بعلم الأنطولوجيا والتحقق من صحتها. +إنشاء تخزين علم الأنطولوجيا في الذاكرة وأنماط الوصول. +تنفيذ آلية تحديث علم الأنطولوجيا. + +**معايير النجاح**: +تحميل وتحليل تكوينات علم الأنطولوجيا بنجاح. +التحقق من صحة بنية علم الأنطولوجيا واتساقها. +التعامل مع العديد من علم الأنطولوجيا المتزامنة. + +#### الخطوة 1.2: تنفيذ مستودع المتجهات +تنفيذ مستودع متجهات بسيط يعتمد على NumPy كنموذج أولي أولي. +إضافة تطبيق مستودع متجهات FAISS. +إنشاء تجريد واجهة مستودع المتجهات. +تنفيذ البحث عن التشابه مع تحديد العتبات القابلة للتكوين. + +**معايير النجاح**: +تخزين واسترجاع التضمينات بكفاءة. +إجراء بحث عن التشابه مع زمن انتقال أقل من 100 مللي ثانية. +دعم كل من الواجهات الخلفية NumPy و FAISS. + +#### الخطوة 1.3: مسار تضمين علم المفاهيم. +التكامل مع خدمة التضمين. +تنفيذ المكون `OntologyEmbedder`. +إنشاء تضمينات لجميع عناصر علم المفاهيم. +تخزين التضمينات مع البيانات الوصفية في مخزن المتجهات. + +**معايير النجاح**: +إنشاء تضمينات للفئات والخصائص. +تخزين التضمينات مع البيانات الوصفية المناسبة. +إعادة بناء التضمينات عند تحديث علم المفاهيم. + +#### الخطوة 1.4: مكونات معالجة النصوص. +تنفيذ أداة تقسيم الجمل باستخدام NLTK/spaCy. +استخراج العبارات والكيانات المسماة. +إنشاء تسلسل هرمي لشرائح النصوص. +إنشاء تضمينات لشرائح النصوص. + +**معايير النجاح**: +تقسيم النصوص بدقة إلى جمل. +استخراج عبارات ذات معنى. +الحفاظ على علاقات السياق. + +#### الخطوة 1.5: خوارزمية اختيار علم المفاهيم. +تنفيذ مطابقة التشابه بين النصوص وعلم المفاهيم. +بناء حل لتبعيات عناصر علم المفاهيم. +إنشاء مجموعات فرعية متماسكة من علم المفاهيم. +تحسين أداء إنشاء المجموعة الفرعية. + +**معايير النجاح**: +تحديد عناصر علم المفاهيم ذات الصلة بدقة >80%. +تضمين جميع التبعيات اللازمة. +إنشاء مجموعات فرعية في <500 مللي ثانية. + +#### الخطوة 1.6: خدمة الاستخراج الأساسية. +تنفيذ بناء المطالبات للاستخراج. +التكامل مع خدمة المطالبات. +تحليل والتحقق من صحة استجابات الثلاثيات. +إنشاء نقطة نهاية الخدمة `kg-extract-ontology`. + +**معايير النجاح**: +استخراج ثلاثيات متوافقة مع علم المفاهيم. +التحقق من صحة جميع الثلاثيات مقابل علم المفاهيم. +التعامل مع أخطاء الاستخراج بأمان. + +### المرحلة 2: تنفيذ نظام الاستعلام. + +**الهدف**: إضافة إمكانات استعلام واعية بعلم المفاهيم مع دعم واجهات خلفية متعددة. + +#### الخطوة 2.1: مكونات أساسية للاستعلام. +تنفيذ محلل الأسئلة. +إنشاء مُطابق لعلم المفاهيم للاستعلامات. +تكييف بحث المتجهات لسياق الاستعلام. +بناء مكون توجيه الواجهة الخلفية. + +**معايير النجاح**: +تحليل الأسئلة إلى مكونات دلالية. +مطابقة الأسئلة مع عناصر علم المفاهيم ذات الصلة. +توجيه الاستعلامات إلى الواجهة الخلفية المناسبة. + +#### الخطوة 2.2: تنفيذ مسار SPARQL. +تنفيذ الخدمة `onto-query-sparql`. +إنشاء مُولد استعلامات SPARQL باستخدام LLM. +تطوير قوالب المطالبات لإنشاء SPARQL. +التحقق من صحة بناء جملة SPARQL الذي تم إنشاؤه. + +**معايير النجاح**: +إنشاء استعلامات SPARQL صالحة. +استخدام أنماط SPARQL المناسبة. +التعامل مع أنواع الاستعلامات المعقدة. + +#### الخطوة 2.3: محرك SPARQL-Cassandra. +تنفيذ واجهة تخزين rdflib لـ Cassandra. +إنشاء مترجم استعلامات CQL. +تحسين مطابقة أنماط الثلاثيات. +التعامل مع تنسيق نتائج SPARQL. + +**معايير النجاح**: +تنفيذ استعلامات SPARQL على Cassandra. +دعم أنماط SPARQL الشائعة. +إرجاع النتائج بالتنسيق القياسي. + +#### الخطوة 2.4: تنفيذ مسار Cypher. +تنفيذ الخدمة `onto-query-cypher`. +إنشاء مُولد استعلامات Cypher باستخدام LLM. +تطوير قوالب المطالبات لإنشاء Cypher. +التحقق من صحة بناء جملة Cypher الذي تم إنشاؤه. + +**معايير النجاح**: +إنشاء استعلامات Cypher صالحة. +استخدام أنماط الرسم البياني المناسبة. +دعم Neo4j و Memgraph و FalkorDB. + +#### الخطوة 2.5: منفذ Cypher. +تنفيذ مُنفِّذ Cypher متعدد قواعد البيانات. +دعم بروتوكول Bolt (Neo4j/Memgraph). +دعم بروتوكول Redis (FalkorDB). +التعامل مع التطبيع (Normalization) للنتائج. + +**معايير النجاح**: +تنفيذ Cypher على جميع قواعد البيانات المستهدفة. +التعامل مع الاختلافات الخاصة بقواعد البيانات. +الحفاظ على كفاءة مجموعات الاتصال (Connection Pools). + +#### الخطوة 2.6: توليد الإجابات. +تنفيذ مكون توليد الإجابات. +إنشاء مطالبات (Prompts) لتوليف الإجابات. +تنسيق نتائج الاستعلامات للاستهلاك بواسطة نماذج اللغة الكبيرة (LLM). +توليد إجابات بلغة طبيعية. + +**معايير النجاح**: +توليد إجابات دقيقة من نتائج الاستعلامات. +الحفاظ على السياق من السؤال الأصلي. +تقديم استجابات واضحة وموجزة. + +### المرحلة 3: التحسين والمرونة. + +**الهدف**: تحسين الأداء، وإضافة التخزين المؤقت (Caching)، وتحسين معالجة الأخطاء، وتعزيز الموثوقية. + +#### الخطوة 3.1: تحسين الأداء. +تنفيذ تخزين مؤقت للتضمينات (Embeddings). +إضافة تخزين مؤقت لنتائج الاستعلامات. +تحسين البحث عن المتجهات باستخدام فهارس FAISS IVF. +تنفيذ معالجة الدُفعات (Batch Processing) للتضمينات. + +**معايير النجاح**: +تقليل متوسط زمن الاستجابة للاستعلام بنسبة 50٪. +دعم 10 أضعاف عدد الطلبات المتزامنة. +الحفاظ على أوقات استجابة أقل من ثانية واحدة. + +#### الخطوة 3.2: معالجة متقدمة للأخطاء. +تنفيذ استعادة شاملة للأخطاء. +إضافة آليات احتياطية بين مسارات الاستعلام. +إنشاء منطق إعادة المحاولة مع تأخير أسي (Exponential Backoff). +تحسين تسجيل الأخطاء والتشخيص. + +**معايير النجاح**: +التعامل بأمان مع جميع سيناريوهات الفشل. +التبديل التلقائي بين الواجهات الخلفية (Backends). +تقديم تقارير تفصيلية عن الأخطاء لتصحيح الأخطاء. + +#### الخطوة 3.3: المراقبة وقابلية الملاحظة (Observability). +إضافة جمع مقاييس الأداء. +تنفيذ تتبع الاستعلامات. +إنشاء نقاط فحص صحة (Health Check Endpoints). +إضافة مراقبة استخدام الموارد. + +**معايير النجاح**: +تتبع جميع مؤشرات الأداء الرئيسية. +تحديد الاختناقات بسرعة. +مراقبة صحة النظام في الوقت الفعلي. + +#### الخطوة 3.4: إدارة التكوين (Configuration). +تنفيذ تحديثات ديناميكية للتكوين. +إضافة التحقق من صحة التكوين. +إنشاء قوالب تكوين. +دعم الإعدادات الخاصة بالبيئة. + +**معايير النجاح**: +تحديث التكوين دون إعادة التشغيل. +التحقق من صحة جميع تغييرات التكوين. +دعم بيئات نشر متعددة. + +### المرحلة 4: الميزات المتقدمة. + +**الهدف**: إضافة قدرات متطورة للنشر في بيئة الإنتاج وتعزيز الوظائف. + +#### الخطوة 4.1: دعم متعدد الأبعاد (Multi-Ontology). +تنفيذ منطق اختيار الأبعاد. +دعم الاستعلامات عبر الأبعاد. +التعامل مع إصدارات الأبعاد. +إنشاء قدرات دمج الأبعاد. + +**معايير النجاح**: +الاستعلام عبر أبعاد متعددة. +التعامل مع تعارضات الأبعاد. +دعم تطور الأبعاد. + +#### الخطوة 4.2: توجيه استعلامات ذكي. +تنفيذ التوجيه بناءً على الأداء +إضافة تحليل لتعقيد الاستعلام +إنشاء خوارزميات توجيه تكيفية +دعم اختبار A/B لمسارات التوجيه + +**معايير النجاح**: +توجيه الاستعلامات بشكل مثالي +التعلم من أداء الاستعلام +تحسين التوجيه بمرور الوقت + +#### الخطوة 4.3: ميزات الاستخراج المتقدمة +إضافة تقييم مستوى الثقة للمجموعات الثلاثية +تنفيذ توليد الشروحات +إنشاء حلقات ردود فعل للتحسين +دعم التعلم التدريجي + +**معايير النجاح**: +توفير درجات الثقة +شرح قرارات الاستخراج +تحسين الدقة باستمرار + +#### الخطوة 4.4: تعزيز الإنتاج +إضافة تحديد المعدل +تنفيذ المصادقة/التفويض +إنشاء أتمتة النشر +إضافة النسخ الاحتياطي والاستعادة + +**معايير النجاح**: +أمان جاهز للإنتاج +مسار نشر آلي +قدرة على التعافي من الكوارث + +### مراحل التسليم + +1. **المرحلة الأولى** (نهاية المرحلة 1): استخراج قائم على علم الوجود ويعمل بشكل أساسي +2. **المرحلة الثانية** (نهاية المرحلة 2): نظام استعلام كامل مع مسارات SPARQL و Cypher +3. **المرحلة الثالثة** (نهاية المرحلة 3): نظام مُحسَّن وموثوق به وجاهز للمرحلة التجريبية +4. **المرحلة الرابعة** (نهاية المرحلة 4): نظام جاهز للإنتاج مع ميزات متقدمة + +### تخفيف المخاطر + +#### المخاطر الفنية +**قابلية توسع مخزن المتجهات**: ابدأ بـ NumPy، وانتقل تدريجيًا إلى FAISS +**دقة توليد الاستعلامات**: تنفيذ آليات التحقق والحلول البديلة +**توافق الواجهة الخلفية**: الاختبار بشكل مكثف مع كل نوع قاعدة بيانات +**عقبات الأداء**: التحليل المبكر والمتكرر، والتحسين بشكل تكراري + +#### المخاطر التشغيلية +**جودة علم الوجود**: تنفيذ التحقق من الصحة والاتساق +**تبعيات الخدمة**: إضافة قواطع الدائرة والحلول البديلة +**قيود الموارد**: المراقبة وتعيين الحدود المناسبة +**اتساق البيانات**: تنفيذ معالجة المعاملات المناسبة + +### مقاييس النجاح + +#### مقاييس نجاح المرحلة الأولى +دقة الاستخراج: >90% من التوافق مع علم الوجود +سرعة المعالجة: <1 ثانية لكل جزء +وقت تحميل علم الوجود: <10 ثوانٍ +زمن استجابة البحث عن المتجهات: <100 مللي ثانية + +#### مقاييس نجاح المرحلة الثانية +معدل نجاح الاستعلام: >95% +زمن استجابة الاستعلام: <2 ثانية من البداية إلى النهاية +توافق الواجهة الخلفية: 100% لقواعد البيانات المستهدفة +دقة الإجابة: >85% بناءً على البيانات المتاحة + +#### مقاييس نجاح المرحلة الثالثة +وقت تشغيل النظام: >99.9% +معدل التعافي من الأخطاء: >95% +معدل الوصول إلى ذاكرة التخزين المؤقت: >60% +عدد المستخدمين المتزامنين: >100 + +#### مقاييس نجاح المرحلة الرابعة +الاستعلامات متعددة علم الوجود: مدعومة بالكامل +تحسين التوجيه: تقليل زمن الوصول بنسبة 30% +دقة تقييم مستوى الثقة: >90% +نشر الإنتاج: تحديثات بدون توقف + +## المراجع + +[OWL 2 Web Ontology Language](https://www.w3.org/TR/owl2-overview/) +[GraphRAG Architecture](https://github.com/microsoft/graphrag) +[Sentence Transformers](https://www.sbert.net/) +[FAISS Vector Search](https://github.com/facebookresearch/faiss) +[spaCy NLP Library](https://spacy.io/) +[rdflib Documentation](https://rdflib.readthedocs.io/) +[Neo4j Bolt Protocol](https://neo4j.com/docs/bolt/current/) diff --git a/docs/tech-specs/ontorag.es.md b/docs/tech-specs/ontorag.es.md new file mode 100644 index 00000000..7e53ea05 --- /dev/null +++ b/docs/tech-specs/ontorag.es.md @@ -0,0 +1,1067 @@ +# OntoRAG: Especificación Técnica de Extracción y Consulta de Conocimiento Basada en Ontologías + +## Resumen + +OntoRAG es un sistema de extracción y consulta de conocimiento impulsado por ontologías que impone una coherencia semántica estricta tanto durante la extracción de triples de conocimiento de texto no estructurado como durante la consulta del grafo de conocimiento resultante. Similar a GraphRAG, pero con restricciones de ontología formales, OntoRAG garantiza que todos los triples extraídos cumplan con estructuras ontológicas predefinidas y proporciona capacidades de consulta con conciencia semántica. + +El sistema utiliza la coincidencia de similitud vectorial para seleccionar dinámicamente subconjuntos de ontología relevantes tanto para las operaciones de extracción como de consulta, lo que permite un procesamiento enfocado y contextualmente apropiado al tiempo que se mantiene la validez semántica. + +**Nombre del Servicio**: `kg-extract-ontology` + +## Objetivos + +**Extracción Conforme a la Ontología**: Asegurar que todos los triples extraídos cumplan estrictamente con las ontologías cargadas. +**Selección de Contexto Dinámico**: Utilizar incrustaciones para seleccionar subconjuntos de ontología relevantes para cada fragmento. +**Coherencia Semántica**: Mantener jerarquías de clases, dominios/rangos de propiedades y restricciones. +**Procesamiento Eficiente**: Utilizar almacenes vectoriales en memoria para una coincidencia rápida de elementos de la ontología. +**Arquitectura Escalable**: Soporte para múltiples ontologías concurrentes con diferentes dominios. + +## Antecedentes + +Los servicios actuales de extracción de conocimiento (`kg-extract-definitions`, `kg-extract-relationships`) operan sin restricciones formales, lo que podría generar triples inconsistentes o incompatibles. OntoRAG aborda esto mediante: + +1. Carga de ontologías formales que definen clases y propiedades válidas. +2. Utilización de incrustaciones para hacer coincidir el contenido de texto con elementos de ontología relevantes. +3. Restricción de la extracción para producir solo triples conformes a la ontología. +4. Provisión de validación semántica del conocimiento extraído. + +Este enfoque combina la flexibilidad de la extracción neuronal con la rigurosidad de la representación formal del conocimiento. + +## Diseño Técnico + +### Arquitectura + +El sistema OntoRAG consta de los siguientes componentes: + +``` +┌─────────────────┐ +│ Configuration │ +│ Service │ +└────────┬────────┘ + │ Ontologies + ▼ +┌─────────────────┐ ┌──────────────┐ +│ kg-extract- │────▶│ Embedding │ +│ ontology │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ │ + ▼ ▼ +┌─────────────────┐ ┌──────────────┐ +│ In-Memory │◀────│ Ontology │ +│ Vector Store │ │ Embedder │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Sentence │────▶│ Chunker │ +│ Splitter │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Ontology │────▶│ Vector │ +│ Selector │ │ Search │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Prompt │────▶│ Prompt │ +│ Constructor │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ +│ Triple Output │ +└─────────────────┘ +``` + +### Detalles del Componente + +#### 1. Carga de Ontologías + +**Propósito**: Recupera y analiza las configuraciones de ontologías desde el servicio de configuración utilizando actualizaciones basadas en eventos. + +**Implementación**: +El cargador de ontologías utiliza la cola ConfigPush de TrustGraph para recibir actualizaciones de configuración de ontologías basadas en eventos. Cuando se agrega o modifica un elemento de configuración de tipo "ontología", el cargador recibe la actualización a través de la cola config-update y analiza la estructura JSON que contiene metadatos, clases, propiedades de objeto y propiedades de tipo de datos. Estas ontologías analizadas se almacenan en la memoria como objetos estructurados que se pueden acceder de forma eficiente durante el proceso de extracción. + +**Operaciones Clave**: +Suscribirse a la cola config-update para configuraciones de tipo ontología +Analizar estructuras JSON de ontologías en objetos OntologyClass y OntologyProperty +Validar la estructura y la coherencia de la ontología +Almacenar en caché las ontologías analizadas en la memoria para un acceso rápido +Manejar el procesamiento por flujo con almacenes de vectores específicos del flujo + +**Ubicación de la Implementación**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_loader.py` + +#### 2. Incrustador de Ontologías + +**Propósito**: Crea incrustaciones vectoriales para todos los elementos de la ontología para habilitar la coincidencia de similitud semántica. + +**Implementación**: +El incrustador de ontologías procesa cada elemento en las ontologías cargadas (clases, propiedades de objeto y propiedades de tipo de datos) y genera incrustaciones vectoriales utilizando el servicio EmbeddingsClientSpec. Para cada elemento, combina el identificador del elemento, las etiquetas y la descripción (comentario) para crear una representación de texto. Este texto se convierte luego en una incrustación vectorial de alta dimensión que captura su significado semántico. Estas incrustaciones se almacenan en un almacén de vectores FAISS en la memoria, específico de cada flujo, junto con metadatos sobre el tipo de elemento, la ontología de origen y la definición completa. El incrustador detecta automáticamente la dimensión de la incrustación a partir de la primera respuesta de la incrustación. + +**Operaciones Clave**: +Crear representaciones de texto a partir de ID de elementos, etiquetas y comentarios +Generar incrustaciones a través de EmbeddingsClientSpec (utilizando asyncio.gather para el procesamiento por lotes) +Almacenar incrustaciones con metadatos completos en el almacén de vectores FAISS +Indexar por ontología, tipo de elemento y ID de elemento para una recuperación eficiente +Detectar automáticamente las dimensiones de la incrustación para la inicialización del almacén de vectores +Manejar modelos de incrustación específicos del flujo con almacenes de vectores independientes + +**Ubicación de la Implementación**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_embedder.py` + +#### 3. Procesador de Texto (Divisor de Oraciones) + +**Propósito**: Descompone los fragmentos de texto en segmentos granulares para una coincidencia precisa de ontologías. + +**Implementación**: +El procesador de texto utiliza NLTK para la tokenización de oraciones y el etiquetado POS para dividir los fragmentos de texto entrantes en oraciones. Maneja la compatibilidad de la versión de NLTK intentando descargar `punkt_tab` y `averaged_perceptron_tagger_eng`, con retrocesos a versiones anteriores si es necesario. Cada fragmento de texto se divide en oraciones individuales que se pueden hacer coincidir de forma independiente con los elementos de la ontología. + +**Operaciones Clave**: +Dividir el texto en oraciones utilizando la tokenización de oraciones de NLTK +Manejar la compatibilidad de la versión de NLTK (punkt_tab vs punkt) +Crear objetos TextSegment con texto e información de posición +Soporte tanto para oraciones completas como para fragmentos individuales + +**Ubicación de la Implementación**: `trustgraph-flow/trustgraph/extract/kg/ontology/text_processor.py` + +#### 4. Selector de Ontologías + +**Propósito**: Identifica el subconjunto más relevante de elementos de la ontología para el fragmento de texto actual. + +**Implementación**: +El selector de ontologías realiza una coincidencia semántica entre los segmentos de texto y los elementos de la ontología utilizando la búsqueda de similitud vectorial FAISS. Para cada oración del fragmento de texto, genera una incrustación y busca en el almacén de vectores los elementos de la ontología más similares utilizando la similitud coseno con un umbral configurable (por defecto 0.3). Después de recopilar todos los elementos relevantes, realiza una resolución de dependencias integral: si se selecciona una clase, se incluyen sus clases padre; si se selecciona una propiedad, se agregan sus clases de dominio y rango. Además, para cada clase seleccionada, incluye automáticamente **todas las propiedades que hacen referencia a esa clase** en su dominio o rango. Esto asegura que la extracción tenga acceso a todas las propiedades relevantes de la relación. + +**Operaciones Clave**: +Generar incrustaciones para cada segmento de texto (oraciones) +Realizar una búsqueda de vecinos más cercanos en el almacén vectorial FAISS (top_k=10, threshold=0.3) +Aplicar un umbral de similitud para filtrar coincidencias débiles +Resolver dependencias (clases padre, dominios, rangos) +**Incluir automáticamente todas las propiedades relacionadas con las clases seleccionadas** (coincidencia de dominio/rango) +Construir un subconjunto de ontología coherente con todas las relaciones requeridas +Eliminar elementos duplicados que aparecen varias veces + +**Ubicación de la Implementación**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_selector.py` + +#### 5. Construcción de la Consulta (Prompt) + +**Propósito**: Crea consultas estructuradas que guían al LLM para extraer solo triples conformes a la ontología. + +**Implementación**: +El servicio de extracción utiliza una plantilla Jinja2 cargada desde `ontology-prompt.md` que formatea el subconjunto de la ontología y el texto para la extracción del LLM. La plantilla itera dinámicamente sobre clases, propiedades de objeto y propiedades de tipo de datos utilizando la sintaxis de Jinja2, presentando cada una con sus descripciones, dominios, rangos y relaciones jerárquicas. La consulta incluye reglas estrictas sobre el uso únicamente de los elementos de la ontología proporcionados y solicita un formato de salida JSON para un análisis coherente. + +**Operaciones Clave**: +Utilizar una plantilla Jinja2 con bucles sobre los elementos de la ontología +Formatear clases con relaciones padre (subclass_of) y comentarios +Formatear propiedades con restricciones de dominio/rango y comentarios +Incluir reglas de extracción explícitas y requisitos de formato de salida +Llamar al servicio de consulta con el ID de la plantilla "extract-with-ontologies" + +**Ubicación de la Plantilla**: `ontology-prompt.md` +**Ubicación de la Implementación**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` (método build_extraction_variables) + +#### 6. Servicio de Extracción Principal + +**Propósito**: Coordina todos los componentes para realizar la extracción de triples basada en la ontología de extremo a extremo. + +**Implementación**: +El Servicio de Extracción Principal (KgExtractOntology) es la capa de orquestación que gestiona el flujo de trabajo completo de extracción. Utiliza el patrón FlowProcessor de TrustGraph con inicialización de componentes específicos del flujo. Cuando llega una actualización de la configuración de la ontología, inicializa o actualiza los componentes específicos del flujo (cargador de ontología, incrustador, procesador de texto, selector). Cuando llega un fragmento de texto para su procesamiento, coordina la canalización: divide el texto en segmentos, encuentra elementos de ontología relevantes mediante búsqueda vectorial, construye una consulta restringida, llama al servicio de consulta, analiza y valida la respuesta, genera triples de definición de ontología y emite tanto triples de contenido como contextos de entidades. + +**Canalización de Extracción**: +1. Recibir un fragmento de texto a través de la cola chunks-input +2. Inicializar los componentes del flujo si es necesario (en el primer fragmento o en la actualización de la configuración) +3. Dividir el texto en oraciones utilizando NLTK +4. Buscar en el almacén vectorial FAISS para encontrar conceptos de ontología relevantes +5. Construir un subconjunto de ontología con inclusión automática de propiedades +6. Construir variables de consulta Jinja2 +7. Llamar al servicio de consulta con la plantilla extract-with-ontologies +8. Analizar la respuesta JSON en triples estructurados +9. Validar los triples y expandir los URIs a URIs completos de la ontología +10. Generar triples de definición de ontología (clases y propiedades con etiquetas/comentarios/dominios/rangos) +11. Construir contextos de entidades a partir de todos los triples +12. Emitir a las colas de triples y contextos de entidades + +**Características Clave**: +Almacenes vectoriales específicos del flujo que admiten diferentes modelos de incrustación +Actualizaciones de ontología basadas en eventos a través de la cola config-update +Expansión automática de URIs utilizando URIs de ontología +Elementos de ontología añadidos al grafo de conocimiento con metadatos completos +Los contextos de entidades incluyen tanto elementos de contenido como de ontología + +**Ubicación de la Implementación**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` + +### Configuración + +El servicio utiliza el enfoque de configuración estándar de TrustGraph con argumentos de línea de comandos: + +```bash +kg-extract-ontology \ + --id kg-extract-ontology \ + --pulsar-host localhost:6650 \ + --input-queue chunks \ + --config-input-queue config-update \ + --output-queue triples \ + --entity-contexts-output-queue entity-contexts +``` + +**Parámetros de Configuración Clave**: +`similarity_threshold`: 0.3 (predeterminado, configurable en el código) +`top_k`: 10 (número de elementos de la ontología a recuperar por segmento) +`vector_store`: Índice FAISS FlatIP por flujo con detección automática de dimensiones +`text_processor`: NLTK con tokenización de oraciones punkt_tab +`prompt_template`: "extract-with-ontologies" (plantilla Jinja2) + +**Configuración de la Ontología**: +Las ontologías se cargan dinámicamente a través de la cola de actualización de configuración con el tipo "ontology". + +### Flujo de Datos + +1. **Fase de Inicialización** (por flujo): + Recibir la configuración de la ontología a través de la cola de actualización de configuración + Analizar el JSON de la ontología en objetos OntologyClass y OntologyProperty + Generar incrustaciones para todos los elementos de la ontología utilizando EmbeddingsClientSpec + Almacenar las incrustaciones en el almacén de vectores FAISS específico de cada flujo + Detectar automáticamente las dimensiones de la incrustación a partir de la primera respuesta + +2. **Fase de Extracción** (por fragmento): + Recibir un fragmento de la cola chunks-input + Dividir el fragmento en oraciones utilizando NLTK + Calcular las incrustaciones para cada oración + Buscar en el almacén de vectores FAISS los elementos de la ontología relevantes + Construir un subconjunto de la ontología con inclusión automática de propiedades + Construir variables de plantilla Jinja2 con texto y ontología + Llamar al servicio de solicitud con la plantilla extract-with-ontologías + Analizar la respuesta JSON y validar las triples + Expandir los URIs utilizando los URIs de la ontología + Generar triples de definición de ontología + Construir contextos de entidades a partir de todas las triples + Emitir a las colas de triples y entity-contexts + +### Almacén de Vectores en Memoria + +**Propósito**: Proporciona una búsqueda de similitud rápida y basada en memoria para la coincidencia de elementos de la ontología. + +**Implementación: FAISS** + +El sistema utiliza **FAISS (Facebook AI Similarity Search)** con IndexFlatIP para la búsqueda de similitud coseno exacta. Características clave: + +**IndexFlatIP**: Búsqueda de similitud coseno exacta utilizando el producto interno +**Detección automática**: La dimensión se determina a partir de la primera respuesta de incrustación +**Almacenes por flujo**: Cada flujo tiene un almacén de vectores independiente para diferentes modelos de incrustación +**Normalización**: Todos los vectores se normalizan antes de la indexación +**Operaciones por lotes**: Adición por lotes eficiente para la carga inicial de la ontología + +**Ubicación de la Implementación**: `trustgraph-flow/trustgraph/extract/kg/ontology/vector_store.py` + +### Algoritmo de Selección de Subconjunto de Ontología + +**Propósito**: Selecciona dinámicamente la porción relevante mínima de la ontología para cada fragmento de texto. + +**Pasos Detallados del Algoritmo**: + +1. **Segmentación de Texto**: + Dividir el fragmento de entrada en oraciones utilizando la detección de oraciones de NLP + Extraer frases nominales, frases verbales y entidades nombradas de cada oración + Crear una estructura jerárquica de segmentos que preserve el contexto + +2. **Generación de Incrustaciones**: + Generar incrustaciones vectoriales para cada segmento de texto (oraciones y frases) + Utilizar el mismo modelo de incrustación que se utiliza para los elementos de la ontología + Almacenar en caché las incrustaciones para los segmentos repetidos para mejorar el rendimiento + +3. **Búsqueda de Similitud**: + Para cada incrustación de segmento de texto, buscar en el almacén de vectores + Recuperar los k elementos de la ontología más similares (por ejemplo, 10) + Aplicar un umbral de similitud (por ejemplo, 0.7) para filtrar las coincidencias débiles + Agregar los resultados en todos los segmentos, rastreando las frecuencias de coincidencia + +4. **Resolución de Dependencias**: + Para cada clase seleccionada, incluir recursivamente todas las clases padre hasta la raíz + Para cada propiedad seleccionada, incluir las clases de dominio y rango + Para las propiedades inversas, asegurarse de incluir ambas direcciones + Agregar clases equivalentes si existen en la ontología + +5. **Construcción del Subconjunto**: + Desduplicar los elementos recopilados mientras se preservan las relaciones + Organizar en clases, propiedades de objeto y propiedades de tipo de datos + Asegurarse de que todas las restricciones y relaciones se preserven + Crear una mini-ontología autocontenida que sea válida y completa + +**Ejemplo de Demostración**: +Dado el texto: "The brown dog chased the white cat up the tree." +Segmentos: ["brown dog", "white cat", "tree", "chased"] +Elementos coincidentes: [dog (class), cat (class), animal (parent), chases (property)] +Dependencias: [animal (parent of dog and cat), lifeform (parent of animal)] +Subconjunto final: Mini-ontología completa con la jerarquía de animales y la relación de persecución + +### Validación de Triples + +**Propósito**: Asegura que todas las triples extraídas cumplan estrictamente con las restricciones de la ontología. + +**Algoritmo de Validación**: + +1. **Validación de Clases**: + Verificar que los sujetos sean instancias de clases definidas en el subconjunto de la ontología. + Para las propiedades de objeto, verificar que los objetos también sean instancias de clases válidas. + Comprobar los nombres de las clases contra el diccionario de clases de la ontología. + Manejar las jerarquías de clases: las instancias de subclases son válidas para las restricciones de la clase principal. + +2. **Validación de Propiedades**: + Confirmar que los predicados corresponden a las propiedades del subconjunto de la ontología. + Distinguir entre propiedades de objeto (entidad a entidad) y propiedades de tipo de datos (entidad a literal). + Verificar que los nombres de las propiedades coincidan exactamente (considerando el espacio de nombres si está presente). + +3. **Comprobación de Dominio/Rango**: + Para cada propiedad utilizada como predicado, recuperar su dominio y rango. + Verificar que el tipo del sujeto coincida o herede del dominio de la propiedad. + Verificar que el tipo del objeto coincida o herede del rango de la propiedad. + Para las propiedades de tipo de datos, verificar que el objeto sea un literal del tipo XSD correcto. + +4. **Validación de Cardinalidad**: + Registrar los recuentos de uso de la propiedad por sujeto. + Comprobar la cardinalidad mínima: asegurarse de que las propiedades requeridas estén presentes. + Comprobar la cardinalidad máxima: asegurarse de que la propiedad no se utilice demasiadas veces. + Para las propiedades funcionales, asegurarse de que haya como máximo un valor por sujeto. + +5. **Validación de Tipos de Datos**: + Analizar los valores literales según sus tipos XSD declarados. + Validar que los enteros sean números válidos, que las fechas tengan un formato correcto, etc. + Comprobar los patrones de cadena si se definen restricciones de expresión regular. + Asegurarse de que las URIs estén bien formadas para los tipos xsd:anyURI. + +**Ejemplo de Validación**: +Triple: ("Buddy", "tiene-dueño", "John") +Comprobar que "Buddy" esté tipado como una clase que puede tener la propiedad "tiene-dueño". +Comprobar que "tiene-dueño" exista en la ontología. +Verificar la restricción de dominio: el sujeto debe ser de tipo "Mascota" o subclase. +Verificar la restricción de rango: el objeto debe ser de tipo "Persona" o subclase. +Si es válido, agregar a la salida; si no es válido, registrar la violación y omitir. + +## Consideraciones de Rendimiento + +### Estrategias de Optimización + +1. **Caché de Incrustaciones**: Almacenar en caché las incrustaciones para segmentos de texto utilizados con frecuencia. +2. **Procesamiento por Lotes**: Procesar múltiples segmentos en paralelo. +3. **Indexación de Almacenes Vectoriales**: Utilizar algoritmos de vecinos más cercanos aproximados para ontologías grandes. +4. **Optimización de Indicaciones**: Minimizar el tamaño de la indicación incluyendo solo los elementos esenciales de la ontología. +5. **Caché de Resultados**: Almacenar en caché los resultados de la extracción para fragmentos idénticos. + +### Escalabilidad + +**Escalabilidad Horizontal**: Múltiples instancias del extractor con un caché de ontología compartido. +**Partición de Ontologías**: Dividir ontologías grandes por dominio. +**Procesamiento por Transmisión**: Procesar fragmentos a medida que llegan sin agruparlos. +**Gestión de Memoria**: Limpieza periódica de incrustaciones no utilizadas. + +## Manejo de Errores + +### Escenarios de Fallo + +1. **Ontologías Faltantes**: Recurrir a la extracción sin restricciones. +2. **Fallo del Servicio de Incrustaciones**: Utilizar incrustaciones almacenadas en caché o omitir la coincidencia semántica. +3. **Tiempo de Espera del Servicio de Indicaciones**: Reintentar con retroceso exponencial. +4. **Formato de Triple Inválido**: Registrar y omitir triples mal formados. +5. **Inconsistencias de la Ontología**: Informar de conflictos y utilizar los elementos válidos más específicos. + +### Monitorización + +Métricas clave a seguir: + +Tiempo de carga de la ontología y uso de memoria. +Latencia de generación de incrustaciones. +Rendimiento de la búsqueda vectorial. +Tiempo de respuesta del servicio de indicaciones. +Precisión de la extracción de triples. +Tasa de conformidad de la ontología. + +## Ruta de Migración + +### Desde Extractores Existentes + +1. **Operación Paralela**: Ejecutar junto con los extractores existentes inicialmente. +2. **Implementación Gradual**: Comenzar con tipos de documentos específicos. +3. **Comparación de Calidad**: Comparar la calidad de la salida con los extractores existentes. +4. **Migración Completa**: Reemplazar los extractores existentes una vez que se haya verificado la calidad. + +### Desarrollo de Ontologías + +1. **Generación Inicial desde Conocimiento Existente**: Generar ontologías iniciales a partir de conocimiento existente. +2. **Refinamiento Iterativo**: Refinar basándose en patrones de extracción. +3. **Revisión por Expertos en la Materia**: Validar con expertos en la materia. +4. **Mejora Continua**: Actualizar basándose en la retroalimentación de la extracción. + +## Servicio de Consulta Sensible a la Ontología + +### Descripción General + +El servicio de consulta sensible a la ontología proporciona múltiples rutas de consulta para admitir diferentes almacenes de grafos de backend. Aprovecha el conocimiento de la ontología para una respuesta a preguntas precisa y semánticamente consciente en diferentes almacenes de grafos, tanto Cassandra (a través de SPARQL) como almacenes de grafos basados en Cypher (Neo4j, Memgraph, FalkorDB). + +**Componentes del Servicio**: +`onto-query-sparql`: Convierte el lenguaje natural a SPARQL para Cassandra. +`sparql-cassandra`: Capa de consulta SPARQL para Cassandra que utiliza rdflib. +`onto-query-cypher`: Convierte el lenguaje natural a Cypher para bases de datos de grafos. +`cypher-executor`: Ejecución de consultas Cypher para Neo4j/Memgraph/FalkorDB. + +### Arquitectura + +``` + ┌─────────────────┐ + │ User Query │ + └────────┬────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Question │────▶│ Sentence │ + │ Analyser │ │ Splitter │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Ontology │────▶│ Vector │ + │ Matcher │ │ Store │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Backend Router │ + └────────┬────────┘ + │ + ┌───────────┴───────────┐ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ onto-query- │ │ onto-query- │ + │ sparql │ │ cypher │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ SPARQL │ │ Cypher │ + │ Generator │ │ Generator │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ sparql- │ │ cypher- │ + │ cassandra │ │ executor │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ Cassandra │ │ Neo4j/Memgraph/ │ + │ │ │ FalkorDB │ + └────────┬────────┘ └────────┬────────┘ + │ │ + └────────────┬───────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Answer │────▶│ Prompt │ + │ Generator │ │ Service │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Final Answer │ + └─────────────────┘ +``` + +### Query Processing Pipeline + +#### 1. Question Analyser + +**Purpose**: Decomposes user questions into semantic components for ontology matching. + +**Algorithm Description**: +The Question Analyser takes the incoming natural language question and breaks it down into meaningful segments using the same sentence splitting approach as the extraction pipeline. It identifies key entities, relationships, and constraints mentioned in the question. Each segment is analysed for question type (factual, aggregation, comparison, etc.) and the expected answer format. This decomposition helps identify which parts of the ontology are most relevant for answering the question. + +**Key Operations**: +Split question into sentences and phrases +Identify question type and intent +Extract mentioned entities and relationships +Detect constraints and filters in the question +Determine expected answer format + +#### 2. Ontology Matcher for Queries + +**Purpose**: Identifies the relevant ontology subset needed to answer the question. + +**Algorithm Description**: +Similar to the extraction pipeline's Ontology Selector, but optimised for question answering. The matcher generates embeddings for question segments and searches the vector store for relevant ontology elements. However, it focuses on finding concepts that would be useful for query construction rather than extraction. It expands the selection to include related properties that might be traversed during graph exploration, even if not explicitly mentioned in the question. For example, if asked about "employees," it might include properties like "works-for," "manages," and "reports-to" that could be relevant for finding employee information. + +**Matching Strategy**: +Embed question segments +Find directly mentioned ontology concepts +Include properties that connect mentioned classes +Add inverse and related properties for traversal +Include parent/child classes for hierarchical queries +Build query-focused ontology partition + +#### 3. Backend Router + +**Purpose**: Routes queries to the appropriate backend-specific query path based on configuration. + +**Algorithm Description**: +The Backend Router examines the system configuration to determine which graph backend is active (Cassandra or Cypher-based). It routes the question and ontology partition to the appropriate query generation service. The router can also support load balancing across multiple backends or fallback mechanisms if the primary backend is unavailable. + +**Routing Logic**: +Check configured backend type from system settings +Route to `onto-query-sparql` for Cassandra backends +Route to `onto-query-cypher` for Neo4j/Memgraph/FalkorDB +Support multi-backend configurations with query distribution +Handle failover and load balancing scenarios + +#### 4. SPARQL Query Generation (`onto-query-sparql`) + +**Purpose**: Converts natural language questions to SPARQL queries for Cassandra execution. + +**Algorithm Description**: +The SPARQL query generator takes the question and ontology partition and constructs a SPARQL query optimised for execution against the Cassandra backend. It uses the prompt service with a SPARQL-specific template that includes RDF/OWL semantics. The generator understands SPARQL patterns like property paths, optional clauses, and filters that can efficiently translate to Cassandra operations. + +**SPARQL Generation Prompt Template**: +``` +Generate a SPARQL query for the following question using the provided ontology. + +ONTOLOGY CLASSES: +{classes} + +ONTOLOGY PROPERTIES: +{properties} + +RULES: +- Use proper RDF/OWL semantics +- Include relevant prefixes +- Use property paths for hierarchical queries +- Add FILTER clauses for constraints +- Optimise for Cassandra backend + +QUESTION: {question} + +SPARQL QUERY: +``` + +#### 5. Generación de Consultas Cypher (`onto-query-cypher`) + +**Propósito**: Convierte preguntas en lenguaje natural en consultas Cypher para bases de datos de grafos. + +**Descripción del Algoritmo**: +El generador de consultas Cypher crea consultas Cypher nativas optimizadas para Neo4j, Memgraph y FalkorDB. Mapea clases de ontología a etiquetas de nodos y propiedades a relaciones, utilizando la sintaxis de coincidencia de patrones de Cypher. El generador incluye optimizaciones específicas de Cypher, como sugerencias de dirección de relación, uso de índices y sugerencias de planificación de consultas. + +**Plantilla de Indicación para la Generación de Cypher**: +``` +Generate a Cypher query for the following question using the provided ontology. + +NODE LABELS (from classes): +{classes} + +RELATIONSHIP TYPES (from properties): +{properties} + +RULES: +- Use MATCH patterns for graph traversal +- Include WHERE clauses for filters +- Use aggregation functions when needed +- Optimise for graph database performance +- Consider index hints for large datasets + +QUESTION: {question} + +CYPHER QUERY: +``` + +#### 6. Motor de Consulta SPARQL-Cassandra (`sparql-cassandra`) + +**Propósito**: Ejecuta consultas SPARQL contra Cassandra utilizando Python rdflib. + +**Descripción del Algoritmo**: +El motor SPARQL-Cassandra implementa un procesador SPARQL utilizando la biblioteca rdflib de Python con un almacenamiento backend personalizado para Cassandra. Traduce los patrones de grafo SPARQL en consultas CQL de Cassandra apropiadas, manejando uniones, filtros y agregaciones. El motor mantiene un mapeo de RDF a Cassandra que preserva la estructura semántica al tiempo que optimiza para el modelo de almacenamiento de familias de columnas de Cassandra. + +**Características de la Implementación**: +Implementación de la interfaz de almacenamiento rdflib para Cassandra +Soporte para consultas SPARQL 1.1 con patrones comunes +Traducción eficiente de patrones de triple a CQL +Soporte para rutas de propiedades y consultas jerárquicas +Transmisión de resultados para conjuntos de datos grandes +Agrupación de conexiones y almacenamiento en caché de consultas + +**Ejemplo de Traducción**: +```sparql +SELECT ?animal WHERE { + ?animal rdf:type :Animal . + ?animal :hasOwner "John" . +} +``` +Traduce a consultas optimizadas de Cassandra que aprovechan los índices y las claves de partición. + +#### 7. Ejecutor de Consultas Cypher (`cypher-executor`) + +**Propósito**: Ejecuta consultas Cypher contra Neo4j, Memgraph y FalkorDB. + +**Descripción del Algoritmo**: +El ejecutor de Cypher proporciona una interfaz unificada para ejecutar consultas Cypher en diferentes bases de datos de grafos. Maneja protocolos de conexión específicos de la base de datos, sugerencias de optimización de consultas y normalización del formato de resultados. El ejecutor incluye lógica de reintento, agrupación de conexiones y gestión de transacciones adecuadas para cada tipo de base de datos. + +**Soporte para Múltiples Bases de Datos**: +**Neo4j**: Protocolo Bolt, funciones de transacción, sugerencias de índice +**Memgraph**: Protocolo personalizado, resultados de transmisión, consultas analíticas +**FalkorDB**: Adaptación del protocolo Redis, optimizaciones en memoria + +**Características de Ejecución**: +Gestión de conexiones independiente de la base de datos +Validación de consultas y verificación de sintaxis +Aplicación de límites de tiempo y recursos +Paginación y transmisión de resultados +Monitoreo de rendimiento por tipo de base de datos +Conmutación por error automática entre instancias de base de datos + +#### 8. Generador de Respuestas + +**Propósito**: Sintetiza una respuesta en lenguaje natural a partir de los resultados de la consulta. + +**Descripción del Algoritmo**: +El Generador de Respuestas toma los resultados de la consulta estructurados y la pregunta original, y luego utiliza el servicio de prompts para generar una respuesta completa. A diferencia de las respuestas simples basadas en plantillas, utiliza un LLM para interpretar los datos del grafo en el contexto de la pregunta, manejando relaciones complejas, agregaciones y inferencias. El generador puede explicar su razonamiento haciendo referencia a la estructura de la ontología y a los triples específicos recuperados del grafo. + +**Proceso de Generación de Respuestas**: +Formatea los resultados de la consulta en un contexto estructurado +Incluye definiciones de ontología relevantes para mayor claridad +Construye un prompt con la pregunta y los resultados +Genera una respuesta en lenguaje natural mediante un LLM +Valida la respuesta con respecto a la intención de la consulta +Agrega citas a entidades específicas del grafo si es necesario + +### Integración con Servicios Existentes + +#### Relación con GraphRAG + +**Complementario**: onto-query proporciona precisión semántica mientras que GraphRAG proporciona una cobertura amplia +**Infraestructura Compartida**: Ambos utilizan el mismo grafo de conocimiento y servicios de prompts +**Enrutamiento de Consultas**: El sistema puede enrutar las consultas al servicio más apropiado según el tipo de pregunta +**Modo Híbrido**: Puede combinar ambos enfoques para obtener respuestas completas + +#### Relación con OntoRAG Extraction + +**Ontologías Compartidas**: Utiliza las mismas configuraciones de ontología cargadas por kg-extract-ontology +**Almacén de Vectores Compartido**: Reutiliza los embeddings en memoria del servicio de extracción +**Semántica Consistente**: Las consultas operan en grafos construidos con las mismas restricciones ontológicas + +### Ejemplos de Consultas + +#### Ejemplo 1: Consulta Simple de Entidad +**Pregunta**: "¿Qué animales son mamíferos?" +**Coincidencia de Ontología**: [animal, mammal, subClassOf] +**Consulta Generada**: +```cypher +MATCH (a:animal)-[:subClassOf*]->(m:mammal) +RETURN a.name +``` + +#### Ejemplo 2: Consulta de Relación +**Pregunta**: "¿Qué documentos fueron escritos por John Smith?" +**Correspondencia con la Ontología**: [documento, persona, tiene-autor] +**Consulta Generada**: +```cypher +MATCH (d:document)-[:has-author]->(p:person {name: "John Smith"}) +RETURN d.title, d.date +``` + +#### Ejemplo 3: Consulta de agregación +**Pregunta**: "¿Cuántas patas tienen los gatos?" +**Coincidencia con la ontología**: [gato, número-de-patas (propiedad de tipo de dato)] +**Consulta generada**: +```cypher +MATCH (c:cat) +RETURN c.name, c.number_of_legs +``` + +### Configuración + +```yaml +onto-query: + embedding_model: "text-embedding-3-small" + vector_store: + shared_with_extractor: true # Reuse kg-extract-ontology's store + query_builder: + model: "gpt-4" + temperature: 0.1 + max_query_length: 1000 + graph_executor: + timeout: 30000 # ms + max_results: 1000 + answer_generator: + model: "gpt-4" + temperature: 0.3 + max_tokens: 500 +``` + +### Optimizaciones de rendimiento + +#### Optimización de consultas + +**Poda de la ontología**: Incluir solo los elementos de la ontología necesarios en las indicaciones. +**Caché de consultas**: Almacenar en caché las preguntas frecuentes y sus consultas. +**Caché de resultados**: Almacenar los resultados para consultas idénticas dentro de un intervalo de tiempo. +**Procesamiento por lotes**: Manejar múltiples preguntas relacionadas en una sola exploración del grafo. + +#### Consideraciones de escalabilidad + +**Ejecución distribuida**: Paralelizar subconsultas en particiones del grafo. +**Resultados incrementales**: Transmitir los resultados para conjuntos de datos grandes. +**Equilibrio de carga**: Distribuir la carga de las consultas entre múltiples instancias de servicio. +**Grupos de recursos**: Administrar grupos de conexiones a bases de datos de grafos. + +### Manejo de errores + +#### Escenarios de fallo + +1. **Generación de consultas inválidas**: Revertir a GraphRAG o a una búsqueda simple por palabras clave. +2. **Desajuste de la ontología**: Ampliar la búsqueda a un subconjunto más amplio de la ontología. +3. **Tiempo de espera de la consulta**: Simplificar la consulta o aumentar el tiempo de espera. +4. **Resultados vacíos**: Sugerir la reformulación de la consulta o preguntas relacionadas. +5. **Fallo del servicio LLM**: Utilizar consultas almacenadas en caché o respuestas basadas en plantillas. + +### Métricas de monitoreo + +Distribución de la complejidad de las preguntas. +Tamaños de las particiones de la ontología. +Tasa de éxito de la generación de consultas. +Tiempo de ejecución de las consultas al grafo. +Puntuaciones de calidad de las respuestas. +Tasas de aciertos de la caché. +Frecuencias de error por tipo. + +## Mejoras futuras + +1. **Aprendizaje de la ontología**: Extender automáticamente las ontologías basándose en patrones de extracción. +2. **Puntuación de confianza**: Asignar puntuaciones de confianza a las triples extraídas. +3. **Generación de explicaciones**: Proporcionar la justificación para la extracción de triples. +4. **Aprendizaje activo**: Solicitar la validación humana para las extracciones inciertas. + +## Consideraciones de seguridad + +1. **Prevención de la inyección de indicaciones**: Sanitizar el texto de los fragmentos antes de construir la indicación. +2. **Límites de recursos**: Limitar el uso de memoria para el almacén de vectores. +3. **Limitación de velocidad**: Limitar las solicitudes de extracción por cliente. +4. **Registro de auditoría**: Registrar todas las solicitudes y resultados de extracción. + +## Estrategia de pruebas + +### Pruebas unitarias + +Carga de ontología con varios formatos. +Generación y almacenamiento de incrustaciones. +Algoritmos de división de oraciones. +Cálculos de similitud vectorial. +Análisis y validación de triples. + +### Pruebas de integración + +Canalización de extracción de extremo a extremo. +Integración del servicio de configuración. +Interacción con el servicio de indicaciones. +Manejo de extracción concurrente. + +### Pruebas de rendimiento + +Manejo de ontologías grandes (1000+ clases). +Procesamiento de gran volumen de fragmentos. +Uso de memoria bajo carga. +Referencias de latencia. + +## Plan de entrega + +### Resumen + +El sistema OntoRAG se entregará en cuatro fases principales, con cada fase proporcionando valor incremental mientras se construye hacia el sistema completo. El plan se centra en establecer primero las capacidades básicas de extracción, luego agregar la funcionalidad de consulta, seguida de optimizaciones y funciones avanzadas. + +### Fase 1: Fundación y extracción central + +**Objetivo**: Establecer la canalización básica de extracción impulsada por la ontología con el simple emparejamiento de vectores. + +#### Paso 1.1: Fundación de la gestión de la ontología +Implementar el cargador de configuración de la ontología (`OntologyLoader`). +Analizar y validar las estructuras JSON de la ontología. +Crear un almacenamiento de ontología en memoria y patrones de acceso. +Implementar un mecanismo de actualización de la ontología. + +**Criterios de éxito**: +Cargar y analizar correctamente las configuraciones de la ontología. +Validar la estructura y la coherencia de la ontología. +Manejar múltiples ontologías concurrentes. + +#### Paso 1.2: Implementación del almacén de vectores +Implementar un almacén de vectores simple basado en NumPy como prototipo inicial. +Agregar la implementación del almacén de vectores FAISS. +Crear una abstracción de interfaz para el almacén de vectores. +Implementar la búsqueda de similitud con umbrales configurables. + +**Criterios de Éxito**: +Almacenar y recuperar incrustaciones de manera eficiente +Realizar búsquedas de similitud con una latencia menor a 100 ms +Soporte para backends NumPy y FAISS + +#### Paso 1.3: Canal de Incrustación de Ontologías +Integración con el servicio de incrustación +Implementar componente `OntologyEmbedder` +Generar incrustaciones para todos los elementos de la ontología +Almacenar las incrustaciones con metadatos en el almacén de vectores + +**Criterios de Éxito**: +Generar incrustaciones para clases y propiedades +Almacenar las incrustaciones con los metadatos correctos +Reconstruir las incrustaciones al actualizar la ontología + +#### Paso 1.4: Componentes de Procesamiento de Texto +Implementar un divisor de oraciones utilizando NLTK/spaCy +Extraer frases y entidades nombradas +Crear una jerarquía de segmentos de texto +Generar incrustaciones para los segmentos de texto + +**Criterios de Éxito**: +Dividir el texto en oraciones de forma precisa +Extraer frases significativas +Mantener las relaciones de contexto + +#### Paso 1.5: Algoritmo de Selección de Ontología +Implementar la coincidencia de similitud entre el texto y la ontología +Construir la resolución de dependencias para los elementos de la ontología +Crear subconjuntos coherentes mínimos de la ontología +Optimizar el rendimiento de la generación de subconjuntos + +**Criterios de Éxito**: +Seleccionar elementos de la ontología relevantes con una precisión >80% +Incluir todas las dependencias necesarias +Generar subconjuntos en <500 ms + +#### Paso 1.6: Servicio de Extracción Básico +Implementar la construcción de indicaciones para la extracción +Integración con el servicio de indicaciones +Analizar y validar las respuestas de triple +Crear un punto final de servicio `kg-extract-ontology` + +**Criterios de Éxito**: +Extraer triples conformes a la ontología +Validar todos los triples contra la ontología +Manejar los errores de extracción de forma elegante + +### Fase 2: Implementación del Sistema de Consulta + +**Objetivo**: Agregar capacidades de consulta con conocimiento de la ontología con soporte para múltiples backends. + +#### Paso 2.1: Componentes Fundamentales de la Consulta +Implementar el analizador de preguntas +Crear un comparador de ontologías para las consultas +Adaptar la búsqueda vectorial al contexto de la consulta +Construir el componente de enrutamiento de backends + +**Criterios de Éxito**: +Analizar las preguntas en componentes semánticos +Hacer coincidir las preguntas con los elementos de ontología relevantes +Enrutar las consultas al backend apropiado + +#### Paso 2.2: Implementación de la Ruta SPARQL +Implementar el servicio `onto-query-sparql` +Crear un generador de consultas SPARQL utilizando LLM +Desarrollar plantillas de indicaciones para la generación de SPARQL +Validar la sintaxis SPARQL generada + +**Criterios de Éxito**: +Generar consultas SPARQL válidas +Utilizar patrones SPARQL apropiados +Manejar tipos de consultas complejos + +#### Paso 2.3: Motor SPARQL-Cassandra +Implementar la interfaz de almacenamiento rdflib para Cassandra +Crear un traductor de consultas CQL +Optimizar la coincidencia de patrones de triple +Manejar el formato de resultados de SPARQL + +**Criterios de Éxito**: +Ejecutar consultas SPARQL en Cassandra +Soporte para patrones SPARQL comunes +Devolver resultados en formato estándar + +#### Paso 2.4: Implementación de la Ruta Cypher +Implementar el servicio `onto-query-cypher` +Crear un generador de consultas Cypher utilizando LLM +Desarrollar plantillas de indicaciones para la generación de Cypher +Validar la sintaxis Cypher generada + +**Criterios de Éxito**: +Generar consultas Cypher válidas +Utilizar patrones de grafos apropiados +Soporte para Neo4j, Memgraph, FalkorDB + +#### Paso 2.5: Ejecutor de Cypher +Implement multi-database Cypher executor +Support Bolt protocol (Neo4j/Memgraph) +Support Redis protocol (FalkorDB) +Handle result normalization + +**Success Criteria**: +Execute Cypher on all target databases +Handle database-specific differences +Maintain connection pools efficiently + +#### Step 2.6: Answer Generation +Implement answer generator component +Create prompts for answer synthesis +Format query results for LLM consumption +Generate natural language answers + +**Success Criteria**: +Generate accurate answers from query results +Maintain context from original question +Provide clear, concise responses + +### Phase 3: Optimization and Robustness + +**Goal**: Optimize performance, add caching, improve error handling, and enhance reliability. + +#### Step 3.1: Performance Optimization +Implement embedding caching +Add query result caching +Optimize vector search with FAISS IVF indexes +Implement batch processing for embeddings + +**Success Criteria**: +Reduce average query latency by 50% +Support 10x more concurrent requests +Maintain sub-second response times + +#### Step 3.2: Advanced Error Handling +Implement comprehensive error recovery +Add fallback mechanisms between query paths +Create retry logic with exponential backoff +Improve error logging and diagnostics + +**Success Criteria**: +Gracefully handle all failure scenarios +Automatic failover between backends +Detailed error reporting for debugging + +#### Step 3.3: Monitoring and Observability +Add performance metrics collection +Implement query tracing +Create health check endpoints +Add resource usage monitoring + +**Success Criteria**: +Track all key performance indicators +Identify bottlenecks quickly +Monitor system health in real-time + +#### Step 3.4: Configuration Management +Implement dynamic configuration updates +Add configuration validation +Create configuration templates +Support environment-specific settings + +**Success Criteria**: +Update configuration without restart +Validate all configuration changes +Support multiple deployment environments + +### Phase 4: Advanced Features + +**Goal**: Add sophisticated capabilities for production deployment and enhanced functionality. + +#### Step 4.1: Multi-Ontology Support +Implement ontology selection logic +Support cross-ontology queries +Handle ontology versioning +Create ontology merge capabilities + +**Success Criteria**: +Query across multiple ontologies +Handle ontology conflicts +Support ontology evolution + +#### Step 4.2: Intelligent Query Routing +Implementar enrutamiento basado en el rendimiento +Agregar análisis de complejidad de la consulta +Crear algoritmos de enrutamiento adaptativos +Compatibilizar pruebas A/B para rutas + +**Criterios de éxito**: +Enrutar las consultas de forma óptima +Aprender del rendimiento de las consultas +Mejorar el enrutamiento con el tiempo + +#### Paso 4.3: Características Avanzadas de Extracción +Agregar puntuación de confianza para las triples +Implementar generación de explicaciones +Crear bucles de retroalimentación para la mejora +Compatibilizar aprendizaje incremental + +**Criterios de éxito**: +Proporcionar puntuaciones de confianza +Explicar las decisiones de extracción +Mejorar continuamente la precisión + +#### Paso 4.4: Endurecimiento para Producción +Agregar limitación de velocidad +Implementar autenticación/autorización +Crear automatización de implementación +Agregar copia de seguridad y recuperación + +**Criterios de éxito**: +Seguridad lista para producción +Canal de implementación automatizado +Capacidad de recuperación ante desastres + +### Hitos de Entrega + +1. **Hito 1** (Fin de la Fase 1): Extracción básica basada en la ontología en funcionamiento +2. **Hito 2** (Fin de la Fase 2): Sistema de consulta completo con rutas SPARQL y Cypher +3. **Hito 3** (Fin de la Fase 3): Sistema optimizado y robusto listo para la etapa de pruebas +4. **Hito 4** (Fin de la Fase 4): Sistema listo para producción con características avanzadas + +### Mitigación de Riesgos + +#### Riesgos Técnicos +**Escalabilidad del Almacén de Vectores**: Comenzar con NumPy, migrar gradualmente a FAISS +**Precisión de la Generación de Consultas**: Implementar mecanismos de validación y respaldo +**Compatibilidad con el Backend**: Probar exhaustivamente con cada tipo de base de datos +**Cuellos de Botella de Rendimiento**: Perfil temprano y con frecuencia, optimizar de forma iterativa + +#### Riesgos Operacionales +**Calidad de la Ontología**: Implementar validación y verificación de la consistencia +**Dependencias del Servicio**: Agregar interruptores de circuito y mecanismos de respaldo +**Restricciones de Recursos**: Monitorear y establecer límites apropiados +**Consistencia de Datos**: Implementar un manejo adecuado de transacciones + +### Métricas de Éxito + +#### Métricas de Éxito de la Fase 1 +Precisión de la extracción: >90% de conformidad con la ontología +Velocidad de procesamiento: <1 segundo por fragmento +Tiempo de carga de la ontología: <10 segundos +Latencia de búsqueda de vectores: <100 ms + +#### Métricas de Éxito de la Fase 2 +Tasa de éxito de las consultas: >95% +Latencia de la consulta: <2 segundos de extremo a extremo +Compatibilidad con el backend: 100% para las bases de datos objetivo +Precisión de la respuesta: >85% según los datos disponibles + +#### Métricas de Éxito de la Fase 3 +Tiempo de actividad del sistema: >99.9% +Tasa de recuperación de errores: >95% +Tasa de aciertos en caché: >60% +Usuarios concurrentes: >100 + +#### Métricas de Éxito de la Fase 4 +Consultas multi-ontología: Totalmente compatibles +Optimización del enrutamiento: Reducción de la latencia del 30% +Precisión de la puntuación de confianza: >90% +Implementación en producción: Actualizaciones sin tiempo de inactividad + +## Referencias + +[OWL 2 Web Ontology Language](https://www.w3.org/TR/owl2-overview/) +[GraphRAG Architecture](https://github.com/microsoft/graphrag) +[Sentence Transformers](https://www.sbert.net/) +[FAISS Vector Search](https://github.com/facebookresearch/faiss) +[spaCy NLP Library](https://spacy.io/) +[rdflib Documentation](https://rdflib.readthedocs.io/) +[Neo4j Bolt Protocol](https://neo4j.com/docs/bolt/current/) diff --git a/docs/tech-specs/ontorag.he.md b/docs/tech-specs/ontorag.he.md new file mode 100644 index 00000000..47fdc64a --- /dev/null +++ b/docs/tech-specs/ontorag.he.md @@ -0,0 +1,1067 @@ +# OntoRAG: מפרט טכני לחילוץ ידע מבוסס אונטולוגיה ושליפת שאילתות + +## סקירה כללית + +OntoRAG היא מערכת לחילוץ ידע ושליפת שאילתות המונעת על ידי אונטולוגיה, המאכפת עקביות סמנטית קפדנית במהלך חילוץ משולשים של ידע מטקסט לא מובנה וכן במהלך שליפת שאילתות מגרף הידע המתקבל. בדומה ל-GraphRAG, אך עם אילוצי אונטולוגיה פורמליים, OntoRAG מבטיחה שכל המשולשים החילוצים תואמים למבנים אונטולוגיים מוגדרים מראש ומספקת יכולות שליפת שאילתות מודעות לסמנטיקה. + +המערכת משתמשת בהתאמת דמיון וקטורי כדי לבחור דינמית תת-קבוצות רלוונטיות של אונטולוגיות הן עבור פעולות חילוץ והן עבור פעולות שליפה, ומאפשרת עיבוד ממוקד ומתאים להקשר תוך שמירה על תוקף סמנטי. + +**שם השירות**: `kg-extract-ontology` + +## מטרות + +**חילוץ התואם לאונטולוגיה**: להבטיח שכל המשולשים החילוצים תואמים באופן קפדני לאונטולוגיות הטעונות. +**בחירת הקשר דינמית**: להשתמש בהטבעות כדי לבחור תת-קבוצות רלוונטיות של אונטולוגיות עבור כל מקטע. +**עקביות סמנטית**: לשמור על היררכיות מחלקות, תחומים/טווחים של תכונות ואילוצים. +**עיבוד יעיל**: להשתמש במאגרי וקטורים בזיכרון עבור התאמת אלמנטים של אונטולוגיה מהירה. +**ארכיטקטורה ניתנת להרחבה**: לתמוך במספר אונטולוגיות מקבילות עם תחומים שונים. + +## רקע + +שירותי חילוץ ידע נוכחיים (`kg-extract-definitions`, `kg-extract-relationships`) פועלים ללא אילוצים פורמליים, מה שעלול לגרום ליצירת משולשים לא עקביים או לא תואמים. OntoRAG פותרת בעיה זו על ידי: + +1. טעינת אונטולוגיות פורמליות המגדירות מחלקות ותכונות חוקיות. +2. שימוש בהטבעות כדי להתאים תוכן טקסטואלי לאלמנטים רלוונטיים של אונטולוגיה. +3. הגבלת החילוץ ליצירת משולשים התואמים לאונטולוגיה בלבד. +4. מתן אימות סמנטי של ידע חילוץ. + +גישה זו משלבת את הגמישות של חילוץ עצבי עם הדיוק של ייצוג ידע פורמלי. + +## עיצוב טכני + +### ארכיטקטורה + +מערכת OntoRAG מורכבת מהרכיבים הבאים: + +``` +┌─────────────────┐ +│ Configuration │ +│ Service │ +└────────┬────────┘ + │ Ontologies + ▼ +┌─────────────────┐ ┌──────────────┐ +│ kg-extract- │────▶│ Embedding │ +│ ontology │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ │ + ▼ ▼ +┌─────────────────┐ ┌──────────────┐ +│ In-Memory │◀────│ Ontology │ +│ Vector Store │ │ Embedder │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Sentence │────▶│ Chunker │ +│ Splitter │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Ontology │────▶│ Vector │ +│ Selector │ │ Search │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Prompt │────▶│ Prompt │ +│ Constructor │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ +│ Triple Output │ +└─────────────────┘ +``` + +### פרטי רכיב + +#### 1. טוען אונטולוגיות + +**מטרה**: שולף ומנתח תצורות אונטולוגיות משירות התצורה באמצעות עדכונים מבוססי אירועים. + +**יישום**: +טוען האונטולוגיות משתמש בתור ConfigPush של TrustGraph כדי לקבל עדכוני תצורת אונטולוגיות מבוססי אירועים. כאשר רכיב תצורה מסוג "אונטולוגיה" נוסף או משתנה, הטוען מקבל את העדכון דרך תור config-update ומנתח את מבנה ה-JSON המכיל מטא-נתונים, מחלקות, מאפייני אובייקטים ומאפייני טיפוס נתונים. האונטולוגיות המנותחות מאוחסנות בזיכרון כאובייקטים מובנים שניתן לגשת אליהם ביעילות במהלך תהליך החילוץ. + +**פעולות מרכזיות**: +להירשם לתור config-update עבור תצורות מסוג אונטולוגיה +לנתח מבני אונטולוגיה מסוג JSON לאובייקטים של OntologyClass ו-OntologyProperty +לאמת את מבנה האונטולוגיה ועקביותה +לשמור אונטולוגיות מנותחות בזיכרון לגישה מהירה +לטפל בעיבוד פר-פלואו עם מאגרי וקטורים ספציפיים ל-פלואו + +**מיקום יישום**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_loader.py` + +#### 2. משובץ אונטולוגיות + +**מטרה**: יוצר הטמעות וקטוריות עבור כל רכיבי האונטולוגיה כדי לאפשר התאמת דמיון סמנטי. + +**יישום**: +משובץ האונטולוגיות מעבד כל רכיב באונטולוגיות הטעונות ויוצר הטמעות וקטוריות באמצעות שירות EmbeddingsClientSpec. עבור כל רכיב, הוא משלב את מזהה הרכיב, התוויות והתיאור (הערה) כדי ליצור ייצוג טקסטואלי. טקסט זה מומר לאחר מכן להטמעת וקטור ממדית גבוהה הלוכדת את המשמעות הסמנטית שלו. הטמעות אלה מאוחסנות במאגר וקטורים FAISS בזיכרון, פר-פלואו, יחד עם מטא-נתונים על סוג הרכיב, האונטולוגיה המקורית וההגדרה המלאה. המשובץ מזהה באופן אוטומטי את ממד ההטמעה מהתגובה הראשונה להטמעה. + +**פעולות מרכזיות**: +ליצור ייצוגים טקסטואליים ממזהי רכיבים, תוויות והערות +ליצור הטמעות באמצעות EmbeddingsClientSpec (תוך שימוש ב-asyncio.gather לעיבוד באצווה) +לאחסן הטמעות עם מטא-נתונים מקיפים במאגר וקטורים FAISS +לאנדקס לפי אונטולוגיה, סוג רכיב ומזהה רכיב לשליפה יעילה +לזהות באופן אוטומטי את ממדי ההטמעה לאתחול מאגר הווקטורים +לטפל במודלי הטמעה פר-פלואו עם מאגרי וקטורים עצמאיים + +**מיקום יישום**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_embedder.py` + +#### 3. מעבד טקסט (מפצל משפטים) + +**מטרה**: מפרק מקטעי טקסט לפלחי משנה מפורטים לצורך התאמת אונטולוגיות מדויקת. + +**יישום**: +מעבד הטקסט משתמש ב-NLTK לטוקניזציה של משפטים וסימון חלקי דיבור כדי לחלק מקטעי טקסט נכנסים למשפטים. הוא מטפל בתאימות גרסאות של NLTK על ידי ניסיון להוריד את `punkt_tab` ו-`averaged_perceptron_tagger_eng`, עם מעבר לגרסאות ישנות יותר במידת הצורך. כל מקטע טקסט מחולק למשפטים בודדים שניתן להתאים אליהם באופן עצמאי לרכיבי אונטולוגיה. + +**פעולות מרכזיות**: +לחלק טקסט למשפטים באמצעות טוקניזציה של משפטים של NLTK +לטפל בתאימות גרסאות של NLTK (punkt_tab לעומת punkt) +ליצור אובייקטים של TextSegment עם טקסט ומידע על מיקום +לתמוך הן במשפטים שלמים והן במקטעים בודדים + +**מיקום יישום**: `trustgraph-flow/trustgraph/extract/kg/ontology/text_processor.py` + +#### 4. בורר אונטולוגיות + +**מטרה**: מזהה את תת-הקבוצה הרלוונטית ביותר של רכיבי אונטולוגיה עבור מקטע הטקסט הנוכחי. + +**יישום**: +בורר האונטולוגיות מבצע התאמה סמנטית בין פלחי טקסט ורכיבי אונטולוגיה באמצעות חיפוש דמיון וקטורי של FAISS. עבור כל משפט ממקטע הטקסט, הוא יוצר הטמעה ומחפש במאגר הווקטורים את רכיבי האונטולוגיה הדומים ביותר באמצעות דמיון קוסינוס עם סף הניתן להגדרה (ברירת מחדל 0.3). לאחר איסוף כל הרכיבים הרלוונטיים, הוא מבצע פתרון תלות מקיף: אם נבחרה מחלקה, מחלקות האב שלה כלולות; אם נבחר מאפיין, מחלקות הדומיין והטווח שלו מתווספות. בנוסף, עבור כל מחלקה שנבחרה, הוא כולל באופן אוטומטי **את כל המאפיינים המתייחסים למחלקה זו** בתחום או בטווח שלה. זה מבטיח שלחילוץ יש גישה לכל מאפייני היחס הרלוונטיים. + +**פעולות מפתח**: +יצירת הטמעות עבור כל מקטע טקסט (משפטים) +ביצוע חיפוש של שכנים הקרובים ביותר בבנק וקטורים FAISS (top_k=10, threshold=0.3) +החלת סף דמיון כדי לסנן התאמות חלשות +פתרון תלויות (מחלקות הורים, תחומים, טווחים) +**הכללת כל המאפיינים הקשורים למחלקות שנבחרו באופן אוטומטי** (התאמת תחום/טווח) +יצירת תת-אונטולוגיה קוהרנטית עם כל היחסים הנדרשים +הסרת אלמנטים כפולים המופיעים מספר פעמים + +**מיקום יישום**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_selector.py` + +#### 5. בניית הנחיה (Prompt) + +**מטרה**: יוצר הנחיות מובנות המכוונות את מודל השפה הגדול (LLM) לחלץ רק משולשות התואמים לאונטולוגיה. + +**יישום**: +שירות החילוץ משתמש בתבנית Jinja2 שנטענת מ-`ontology-prompt.md` אשר מעצבת את תת-האונטולוגיה ואת הטקסט לחילוץ על ידי מודל השפה הגדול. התבנית חוזרת באופן דינמי על מחלקות, מאפייני אובייקט ומאפייני נתוני טיפוס תוך שימוש בתחביר Jinja2, ומציגה כל אחד עם התיאורים, התחומים, הטווחים והיחסים ההיררכיים שלהם. ההנחיה כוללת כללים קפדניים לגבי שימוש רק באלמנטים של האונטולוגיה המסופקת ומבקשת פורמט פלט JSON לצורך ניתוח עקבי. + +**פעולות מפתח**: +שימוש בתבנית Jinja2 עם לולאות על אלמנטים של אונטולוגיה +עיצוב מחלקות עם יחסי הורה (subclass_of) והערות +עיצוב מאפיינים עם אילוצי תחום/טווח והערות +הכללת כללי חילוץ מפורשים ודרישות פורמט פלט +קריאה לשירות ההנחיה עם מזהה התבנית "extract-with-ontologies" + +**מיקום התבנית**: `ontology-prompt.md` +**מיקום יישום**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` (שיטת build_extraction_variables) + +#### 6. שירות החילוץ הראשי + +**מטרה**: מתאם את כל הרכיבים לביצוע חילוץ משולשות מבוסס אונטולוגיה מקצה לקצה. + +**יישום**: +שירות החילוץ הראשי (KgExtractOntology) הוא שכבת הארגון המנהלת את זרימת העבודה שלמה. הוא משתמש בדפוס FlowProcessor של TrustGraph עם אתחול רכיבים ספציפיים לכל זרימה. כאשר מגיעה עדכון תצורה של אונטולוגיה, הוא מאתחל או מעדכן את הרכיבים הספציפיים לזרימה (טוען אונטולוגיה, ממיר, מעבד טקסט, בוחר). כאשר מגיע מקטע טקסט לעיבוד, הוא מתאם את הצינור: חלוקת הטקסט למקטעים, מציאת אלמנטי אונטולוגיה רלוונטיים באמצעות חיפוש וקטורי, בניית הנחיה מוגבלת, קריאה לשירות ההנחיה, ניתוח ותיקוף של התגובה, יצירת משולשות הגדרת אונטולוגיה, ופליטה הן של משולשות תוכן והן של הקשרים של ישויות. + +**צינור חילוץ**: +1. קבלת מקטע טקסט דרך תור chunks-input +2. אתחול רכיבי זרימה אם יש צורך (במקטע הראשון או בעדכון תצורה) +3. חלוקת הטקסט למשפטים באמצעות NLTK +4. חיפוש בבנק וקטורים FAISS כדי למצוא מושגי אונטולוגיה רלוונטיים +5. בניית תת-אונטולוגיה עם הכללה אוטומטית של מאפיינים +6. בניית משתני תבנית Jinja2 +7. קריאה לשירות ההנחיה עם תבנית extract-with-ontologies +8. ניתוח תגובת JSON למשולשות מובנים +9. תיקוף משולשות והרחבת URIs ל-URIs מלאים של אונטולוגיה +10. יצירת משולשות הגדרת אונטולוגיה (מחלקות ומאפיינים עם תויות/הערות/תחומים/טווחים) +11. בניית הקשרים של ישויות מכל המשולשות +12. פליטה לתורים של משולשות והקשרים של ישויות + +**תכונות מפתח**: +בנקי וקטורים ספציפיים לכל זרימה התומכים במודלי הטמעה שונים +עדכוני אונטולוגיה מונעי אירועים דרך תור config-update +הרחבת URI אוטומטית באמצעות URIs של אונטולוגיה +אלמנטים של אונטולוגיה מוספים לגרף ידע עם מטא-נתונים מלאים +הקשרים של ישויות כוללים הן אלמנטים של תוכן והן אלמנטים של אונטולוגיה + +**מיקום יישום**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` + +### תצורה + +השירות משתמש בגישה הסטנדרטית של TrustGraph לתצורה עם ארגומנטים של שורת הפקודה: + +```bash +kg-extract-ontology \ + --id kg-extract-ontology \ + --pulsar-host localhost:6650 \ + --input-queue chunks \ + --config-input-queue config-update \ + --output-queue triples \ + --entity-contexts-output-queue entity-contexts +``` + +**פרמטרי תצורה מרכזיים**: +`similarity_threshold`: 0.3 (ברירת מחדל, ניתן להגדרה בקוד) +`top_k`: 10 (מספר רכיבי אונטולוגיה לשליפה לכל מקטע) +`vector_store`: FAISS IndexFlatIP עם זיהוי אוטומטי של ממדים לכל זרימה +`text_processor`: NLTK עם טוקניזציה של משפטים punkt_tab +`prompt_template`: "extract-with-ontologies" (תבנית Jinja2) + +**תצורת אונטולוגיה**: +אונטולוגיות נטענות באופן דינמי באמצעות תור ההודעות config-update עם סוג "ontology". + +### זרימת נתונים + +1. **שלב אתחול** (לכל זרימה): + קבלת תצורת אונטולוגיה באמצעות תור ההודעות config-update + ניתוח JSON של האונטולוגיה לאובייקטים של OntologyClass ו-OntologyProperty + יצירת הטמעות עבור כל רכיבי אונטולוגיה באמצעות EmbeddingsClientSpec + אחסון הטמעות בתוך מאגר וקטורים FAISS ספציפי לכל זרימה + זיהוי אוטומטי של ממדי ההטמעה מהתגובה הראשונה + +2. **שלב חילוץ** (לכל מקטע): + קבלת מקטע מתור הקלט chunks-input + חלוקת המקטע למשפטים באמצעות NLTK + חישוב הטמעות עבור כל משפט + חיפוש במאגר הווקטורים FAISS עבור רכיבי אונטולוגיה רלוונטיים + בניית תת-אונטולוגיה עם הכללת מאפיינים אוטומטית + יצירת משתנים לתבנית Jinja2 עם טקסט ואונטולוגיה + הפעלת שירות שאילתות עם תבנית extract-with-ontologies + ניתוח תגובת JSON ואימות של שלשות + הרחבת URIs באמצעות URIs של אונטולוגיה + יצירת שלשות הגדרת אונטולוגיה + בניית הקשרים של ישויות מכל השלשות + פליטה לתורים triples ו-entity-contexts + +### מאגר וקטורים בזיכרון + +**מטרה**: מספק חיפוש מהיר של דמיון המבוסס על זיכרון, לציפוף של התאמת רכיבי אונטולוגיה. + +**יישום: FAISS** + +המערכת משתמשת ב-**FAISS (Facebook AI Similarity Search)** עם IndexFlatIP לחיפוש מדויק של דמיון קוסינוס. תכונות עיקריות: + +**IndexFlatIP**: חיפוש מדויק של דמיון קוסינוס באמצעות מכפלה פנימית +**זיהוי אוטומטי**: ממד נקבע מהתגובת ההטמעה הראשונה +**מאגרים ספציפיים לזרימה**: לכל זרימה יש מאגר וקטורים עצמאי עבור מודלים שונים של הטמעה +**נרמול**: כל הווקטורים מנורמלים לפני אינדוקס +**פעולות באצווה**: הוספה יעילה באצווה לטעינת אונטולוגיה ראשונית + +**מיקום יישום**: `trustgraph-flow/trustgraph/extract/kg/ontology/vector_store.py` + +### אלגוריתם בחירת תת-אונטולוגיה + +**מטרה**: בוחר באופן דינמי את החלק הרלוונטי המינימלי של האונטולוגיה עבור כל מקטע טקסט. + +**שלבי אלגוריתם מפורטים**: + +1. **פילוח טקסט**: + חלוקת המקטע הקלט למשפטים באמצעות זיהוי משפטים של NLP + חילוץ צירופי שמות עצם, צירופי פעלים וישויות בעלות שם מכל משפט + יצירת מבנה היררכי של מקטעים תוך שמירה על הקשר + +2. **יצירת הטמעות**: + יצירת הטמעות וקטוריות עבור כל מקטע טקסט (משפטים וצירופים) + שימוש באותו מודל הטמעה כמו זה המשמש עבור רכיבי אונטולוגיה + שמירת הטמעות עבור מקטעים חוזרים כדי לשפר את הביצועים + +3. **חיפוש דמיון**: + עבור כל הטמעת מקטע טקסט, חיפוש במאגר הווקטורים + אחזור rכיבי אונטולוגיה הדומים ביותר (לדוגמה, 10) + החלת סף דמיון (לדוגמה, 0.7) כדי לסנן התאמות חלשות + צבירת תוצאות על פני כל המקטעים, תוך מעקב אחר תדירות התאמות + +4. **פתרון תלות**: + עבור כל מחלקה שנבחרה, הכללה רקורסיבית של כל מחלקות האב עד לשורש + עבור כל מאפיין שנבחר, הכללת מחלקות הדומיין והטווח שלו + עבור מאפיינים הפוכים, ודאו ששני הכיוונים כלולים + הוספת מחלקות שוות ערך אם הן קיימות באונטולוגיה + +5. **בניית תת-קבוצה**: + הסרת כפילויות של רכיבים שנאספו תוך שמירה על יחסים + ארגון למחלקות, מאפיינים אובייקטיים ומאפיינים של טיפוסי נתונים + ודאו שכל האילוצים והיחסים נשמרים + יצירת מיני-אונטולוגיה עצמאית שתקפה ושלמה + +**דוגמה להמחשה**: +בהינתן טקסט: "The brown dog chased the white cat up the tree." +מקטעים: ["brown dog", "white cat", "tree", "chased"] +רכיבים תואמים: [dog (class), cat (class), animal (parent), chases (property)] +תלויות: [animal (parent of dog and cat), lifeform (parent of animal)] +תת-קבוצה סופית: מיני-אונטולוגיה שלמה עם היררכיית animal ויחס chase + +### אימות שלשות + +**מטרה**: מבטיח שכל שלשות החילוץ תואמות באופן קפדני לאילוצי האונטולוגיה. + +**אלגוריתם אימות**: +פלט חוזה (יש לעקוב אחר הפורמט בדיוק). +1. **בדיקת תקינות מחלקה**: + ודאו שהנושאים הם מופעים של מחלקות המוגדרות בתת-אונטולוגיה. + עבור מאפיינים אובייקטים, ודאו שהאובייקטים הם גם מופעים חוקיים של מחלקות. + בדקו שמות מחלקות מול מילון המחלקות של האונטולוגיה. + התייחסו להירוארכיות מחלקות - מופעים של תת-מחלקות תקפים עבור אילוצי מחלקת האב. + +2. **בדיקת תקינות מאפיינים**: + ודאו שהפרדיקטים תואמים למאפיינים בתת-אונטולוגיה. + הבדילו בין מאפייני אובייקטים (מקישורים בין ישויות) ומאפייני טיפוס נתונים (מקישורים בין ישות לליטרל). + ודאו ששמות המאפיינים תואמים בדיוק (תוך התחשבות בשם המרחב אם קיים). + +3. **בדיקת תחום/טווח**: + עבור כל מאפיין המשמש כפרדיקט, אחזרו את התחום והטווח שלו. + ודאו שסוג הנושא תואם או יורש מסוג התחום של המאפיין. + ודאו שסוג האובייקט תואם או יורש מסוג הטווח של המאפיין. + עבור מאפייני טיפוס נתונים, ודאו שהאובייקט הוא ליטרל מסוג XSD הנכון. + +4. **בדיקת קרדינליות**: + עקבו אחר ספירת השימוש במאפיינים לכל נושא. + בדקו קרדינליות מינימלית - ודאו שמאפיינים נדרשים קיימים. + בדקו קרדינליות מקסימלית - ודאו שמאפיין לא משמש יותר מדי פעמים. + עבור מאפיינים פונקציונליים, ודאו שיש לכל היותר ערך אחד לכל נושא. + +5. **בדיקת טיפוס נתונים**: + נתחו ערכי ליטרל בהתאם לטיפוסי XSD המוצהרים שלהם. + ודאו שמספרים שלמים הם מספרים חוקיים, תאריכים מעוצבים כראוי וכו'. + בדקו תבניות מחרוזות אם מוגדרים אילוצי regex. + ודאו שכתובות URI מעוצבות כראוי עבור טיפוסי xsd:anyURI. + +**דוגמה לבדיקה**: +טריפל: ("Buddy", "has-owner", "John") +בדקו ש-"Buddy" מסווג כמחלקה שיכולה להיות בעלת מאפיין "has-owner". +בדקו ש-"has-owner" קיים באונטולוגיה. +ודאו אילוץ תחום: הנושא חייב להיות מסוג "Pet" או תת-מחלקה. +ודאו אילוץ טווח: האובייקט חייב להיות מסוג "Person" או תת-מחלקה. +אם תקף, הוסיפו לפלט; אם לא תקף, רשמו הפרה ודלגו. + +## שיקולי ביצועים + +### אסטרטגיות אופטימיזציה + +1. **מטמון הטבעות**: שמרו הטבעות עבור פלחים טקסטואליים בשימוש תכוף. +2. **עיבוד באצווה**: עבדו על מספר פלחים במקביל. +3. **אינדקס אחסון וקטורים**: השתמשו באלגוריתמים של שכנים קרובים ביותר משוערים עבור אונטולוגיות גדולות. +4. **אופטימיזציית שאילתות**: צמצמו את גודל השאילתה על ידי הכללת רק אלמנטים חיוניים של האונטולוגיה. +5. **מטמון תוצאות**: שמרו תוצאות חילוץ עבור מקטעים זהים. + +### יכולת הרחבה + +**הרחבה אופקית**: מספר מופעים של תוכנת חילוץ עם מטמון אונטולוגיה משותף. +**חלוקת אונטולוגיה**: חלקו אונטולוגיות גדולות לפי תחום. +**עיבוד סטרימינג**: עבדו על מקטעים כשהם מגיעים מבלי לבצע אצווה. +**ניהול זיכרון**: ניקוי תקופתי של הטבעות לא בשימוש. + +## טיפול בשגיאות + +### תרחישי כשל + +1. **אונטולוגיות חסרות**: חזרו לחילוץ לא מוגבל. +2. **כשל בשירות הטבעות**: השתמשו בהטבעות שמורות או דלגו על התאמה סמנטית. +3. **חריגה של זמן תגובה של שירות השאילתות**: נסו שוב עם השהייה אקספוננציאלית. +4. **פורמט טריפל לא חוקי**: רשמו ודלגו על טריפלים מעוותים. +5. **אי-עקביות באונטולוגיה**: דווחו על סתירות והשתמשו באלמנטים חוקיים הספציפיים ביותר. + +### ניטור + +מדדים מרכזיים למעקב: + +זמן טעינה ושימוש בזיכרון של האונטולוגיה. +השהייה ביצירת הטבעות. +ביצועי חיפוש וקטורי. +זמן תגובה של שירות השאילתות. +דיוק חילוץ טריפלים. +שיעור התאמה לאונטולוגיה. + +## נתיב מעבר + +### מתוכנות חילוץ קיימות + +1. **פעולה מקבילה**: הפעילו במקביל לתוכנות החילוץ הקיימות בתחילה. +2. **פריסה הדרגתית**: התחילו עם סוגי מסמכים ספציפיים. +3. **השוואת איכות**: השוו את איכות הפלט לתוכנות החילוץ הקיימות. +4. **מעבר מלא**: החליפו את תוכנות החילוץ הקיימות לאחר אימות האיכות. + +### פיתוח אונטולוגיה + +1. **התחילו מקיים**: צרו אונטולוגיות ראשוניות מידע קיים. +2. **שיפור איטרטיבי**: שפרו בהתבסס על תבניות חילוץ. +3. **סקירה של מומחי תחום**: ודאו עם מומחי תחום. +4. **השתמשו ב-LLM**: השתמשו במודלים גדולים של שפה כדי ליצור אונטולוגיות. +**השתמשו ב-RAG**: השתמשו בשליפה מבוססת אחזור כדי לשפר את התוצאות. +**השתמשו ב-Agent**: השתמשו בסוכנים כדי לבצע משימות. +**השתמשו ב-Tool**: השתמשו בכלים כדי לשפר את הפרודוקטיביות. +**השתמשו ב-Memory**: השתמשו בזיכרון כדי לשפר את ההקשר. +**השתמשו ב-Output**: השתמשו בפלט כדי לשפר את התוצאות. + + +**רכיבי השירות**: +`onto-query-sparql`: ממיר שפה טבעית לשאילתות SPARQL עבור Cassandra. +`sparql-cassandra`: שכבת שאילתות SPARQL עבור Cassandra באמצעות rdflib. +`onto-query-cypher`: ממיר שפה טבעית לשאילתות Cypher עבור מסדי נתונים גרפיים. +`cypher-executor`: ביצוע שאילתות Cypher עבור Neo4j/Memgraph/FalkorDB. + +### ארכיטקטורה + +``` + ┌─────────────────┐ + │ User Query │ + └────────┬────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Question │────▶│ Sentence │ + │ Analyser │ │ Splitter │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Ontology │────▶│ Vector │ + │ Matcher │ │ Store │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Backend Router │ + └────────┬────────┘ + │ + ┌───────────┴───────────┐ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ onto-query- │ │ onto-query- │ + │ sparql │ │ cypher │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ SPARQL │ │ Cypher │ + │ Generator │ │ Generator │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ sparql- │ │ cypher- │ + │ cassandra │ │ executor │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ Cassandra │ │ Neo4j/Memgraph/ │ + │ │ │ FalkorDB │ + └────────┬────────┘ └────────┬────────┘ + │ │ + └────────────┬───────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Answer │────▶│ Prompt │ + │ Generator │ │ Service │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Final Answer │ + └─────────────────┘ +``` + +### צינור עיבוד שאילתות + +#### 1. מנתח שאלות + +**מטרה**: מפרק שאלות משתמש לרכיבים סמנטיים לצורך התאמה לאונטולוגיה. + +**תיאור אלגוריתם**: +מנתח השאלות לוקח את השאלה בשפה טבעית ומפרק אותה לפלחי משמעות באמצעות אותה גישת חלוקת משפטים כמו צינור החילוץ. הוא מזהה ישויות, קשרים ואילוצים מרכזיים המוזכרים בשאלה. כל פלח נתח עבור סוג השאלה (עובדתית, אגרגציה, השוואה וכו') ופורמט התשובה הצפוי. פירוק זה עוזר לזהות אילו חלקים של האונטולוגיה רלוונטיים ביותר למענה על השאלה. + +**פעולות מרכזיות**: +חלוקת השאלה למשפטים ולביטויים +זיהוי סוג השאלה והכוונתה +חילוץ ישויות ויחסים המוזכרים +זיהוי אילוצים וסינונים בשאלה +קביעת פורמט התשובה הצפוי + +#### 2. מותאם אונטולוגיות לשאילתות + +**מטרה**: מזהה את תת-האונטולוגיה הרלוונטית הדרושה כדי לענות על השאלה. + +**תיאור אלגוריתם**: +דומה לבחירת האונטולוגיה בצינור החילוץ, אך מותאם לשאלות ותשובות. המתאם מייצר הטבעות עבור פלחי שאלה ומחפש במאגר הווקטורים אלמנטים רלוונטיים באונטולוגיה. עם זאת, הוא מתמקד במציאת מושגים שיכולים להיות שימושיים ליצירת שאילתות, ולא לחילוץ. הוא מרחיב את הבחירה כדי לכלול מאפיינים קשורים שניתן לעבור דרכם במהלך חקר הגרף, גם אם הם אינם מוזכרים במפורש בשאלה. לדוגמה, אם נשאל על "עובדים", הוא עשוי לכלול מאפיינים כמו "עובד עבור", "מנהל" ו"מדווח ל" שיכולים להיות רלוונטיים למציאת מידע על עובדים. + +**אסטרטגיית התאמה**: +הטבעת פלחי שאלה +מציאת מושגי אונטולוגיה המוזכרים ישירות +הכללת מאפיינים המחברים בין מחלקות המוזכרות +הוספת מאפיינים הפוכים וקשורים לניווט +הכללת מחלקות הורה/ילד לשאילתות היררכיות +יצירת מחיצת אונטולוגיה ממוקדת שאילתות + +#### 3. מנתב רקע + +**מטרה**: מנתב שאילתות לנתיב השאילתות הספציפי המתאים לרקע בהתבסס על תצורה. + +**תיאור אלגוריתם**: +מנתב הרקע בודק את תצורת המערכת כדי לקבוע איזה רקע גרף פעיל (Cassandra או מבוסס Cypher). הוא מנתב את השאלה ומחיצת האונטולוגיה לשירות יצירת השאילתות המתאים. המנתב יכול גם לתמוך באיזון עומסים בין רקעים מרובים או במנגנוני גיבוי אם הרקע הראשי אינו זמין. + +**לוגיקת ניתוב**: +בדיקת סוג הרקע המוגדר בהגדרות המערכת +ניתוב ל-`onto-query-sparql` עבור רקעי Cassandra +ניתוב ל-`onto-query-cypher` עבור Neo4j/Memgraph/FalkorDB +תמיכה בתצורות מרובות רקעים עם הפצת שאילתות +טיפול בתרחישי גיבוי ואיזון עומסים + +#### 4. יצירת שאילתות SPARQL (`onto-query-sparql`) + +**מטרה**: ממיר שאלות בשפה טבעית לשאילתות SPARQL לביצוע ב-Cassandra. + +**תיאור אלגוריתם**: +מחולל שאילתות ה-SPARQL לוקח את השאלה ואת מחיצת האונטולוגיה ויוצר שאילתת SPARQL המותאמת לביצוע על הרקע של Cassandra. הוא משתמש בשירות ה-prompt עם תבנית ספציפית ל-SPARQL הכוללת סמנטיקה של RDF/OWL. המחולל מבין תבניות SPARQL כמו נתיבי מאפיינים, סעיפים אופציונליים וסינונים שיכולים לתרגם ביעילות לפעולות Cassandra. + +**תבנית prompt ליצירת SPARQL**: +``` +Generate a SPARQL query for the following question using the provided ontology. + +ONTOLOGY CLASSES: +{classes} + +ONTOLOGY PROPERTIES: +{properties} + +RULES: +- Use proper RDF/OWL semantics +- Include relevant prefixes +- Use property paths for hierarchical queries +- Add FILTER clauses for constraints +- Optimise for Cassandra backend + +QUESTION: {question} + +SPARQL QUERY: +``` + +#### 5. יצירת שאילתות Cypher (`onto-query-cypher`) + +**מטרה**: ממירה שאלות בשפה טבעית לשאילתות Cypher עבור מסדי נתונים גרפיים. + +**תיאור האלגוריתם**: +יוצר השאילתות Cypher מייצר שאילתות Cypher מקומיות המותאמות ל-Neo4j, Memgraph ו-FalkorDB. הוא ממפה מחלקות אונטולוגיה לתגיות צמתים ומאפיינים ליחסים, תוך שימוש בתחביר התאמת תבניות של Cypher. היוצר כולל אופטימיזציות ספציפיות ל-Cypher כגון רמזים לכיוון יחסים, שימוש באינדקסים ורמזים לתכנון שאילתות. + +**תבנית הנחיה ליצירת Cypher**: +``` +Generate a Cypher query for the following question using the provided ontology. + +NODE LABELS (from classes): +{classes} + +RELATIONSHIP TYPES (from properties): +{properties} + +RULES: +- Use MATCH patterns for graph traversal +- Include WHERE clauses for filters +- Use aggregation functions when needed +- Optimise for graph database performance +- Consider index hints for large datasets + +QUESTION: {question} + +CYPHER QUERY: +``` + +#### 6. מנוע שאילתות SPARQL-Cassandra (`sparql-cassandra`) + +**מטרה**: מבצע שאילתות SPARQL נגד Cassandra באמצעות ספריית rdflib של Python. + +**תיאור האלגוריתם**: +מנוע ה-SPARQL-Cassandra מיישם מעבד SPARQL באמצעות ספריית rdflib של Python עם אחסון מותאם אישית ב-Cassandra. הוא מתרגם תבניות גרף SPARQL לשאילתות CQL מתאימות של Cassandra, תוך טיפול בחיבורים, פילטרים ואגרגציות. המנוע שומר על מיפוי מ-RDF ל-Cassandra המשמר את המבנה הסמנטי תוך אופטימיזציה עבור מודל האחסון של משפחות עמודות של Cassandra. + +**מאפייני יישום**: +יישום ממשק rdflib Store עבור Cassandra +תמיכה בשאילתות SPARQL 1.1 עם תבניות נפוצות +תרגום יעיל של תבניות משולשות ל-CQL +תמיכה בנתיבי מאפיינים ובשאילתות היררכיות +הזרמת תוצאות עבור מערכי נתונים גדולים +בריכת חיבורים ומטמון שאילתות + +**דוגמה לתרגום**: +```sparql +SELECT ?animal WHERE { + ?animal rdf:type :Animal . + ?animal :hasOwner "John" . +} +``` +מתרגם לשאילתות Cassandra מותאמות אופטימלית תוך שימוש באינדקסים ומפתחות מחיצה. + +#### 7. מפעיל שאילתות Cypher (`cypher-executor`) + +**מטרה**: מריץ שאילתות Cypher נגד Neo4j, Memgraph ו-FalkorDB. + +**תיאור האלגוריתם**: +מפעיל ה-Cypher מספק ממשק אחיד להרצת שאילתות Cypher על פני מסדי נתונים גרפיים שונים. הוא מטפל בפרוטוקולי חיבור ספציפיים למסד הנתונים, רמזי אופטימיזציה לשאילתות ושינוי פורמט תוצאות. המפעיל כולל מנגנון ניסיון חוזר, ניהול חיבורים וניהול טרנזקציות המתאימים לכל סוג מסד נתונים. + +**תמיכה במספר מסדי נתונים**: +**Neo4j**: פרוטוקול Bolt, פונקציות טרנזקציה, רמזי אינדקס +**Memgraph**: פרוטוקול מותאם אישית, זרימת תוצאות, שאילתות אנליטיות +**FalkorDB**: התאמת פרוטוקול Redis, אופטימיזציות בזיכרון + +**תכונות ביצוע**: +ניהול חיבורים שאינו תלוי במסד הנתונים +אימות שאילתות ובדיקת תחביר +אכיפת מגבלות זמן ומשאבים +דף תוצאות וזרימת תוצאות +ניטור ביצועים לפי סוג מסד נתונים +מעבר אוטומטי בין מופעי מסד נתונים + +#### 8. מחולל תשובות + +**מטרה**: יוצר תשובה בשפה טבעית מתוצאות שאילתות. + +**תיאור האלגוריתם**: +מחולל התשובות לוקח את תוצאות השאילתות המובנות ואת השאלה המקורית, ולאחר מכן משתמש בשירות ה-prompt כדי ליצור תשובה מקיפה. בניגוד לתגובות פשוטות המבוססות על תבניות, הוא משתמש ב-LLM כדי לפרש את נתוני הגרף בהקשר של השאלה, תוך טיפול ביחסים מורכבים, אגרגציות והסקת מסקנות. המחולל יכול להסביר את הנימוקים שלו על ידי התייחסות למבנה האונטולוגיה ולטרפלים הספציפיים שנשלפו מהגרף. + +**תהליך יצירת תשובות**: +עיצוב תוצאות שאילתות להקשר מובנה +הכללת הגדרות אונטולוגיה רלוונטיות לצורך בהירות +יצירת prompt עם שאלה ותוצאות +יצירת תשובה בשפה טבעית באמצעות LLM +אימות התשובה מול כוונת השאלה +הוספת ציטוטים לישויות גרף ספציפיות במידת הצורך + +### אינטגרציה עם שירותים קיימים + +#### יחס עם GraphRAG + +**משלימים**: onto-query מספק דיוק סמנטי בעוד ש-GraphRAG מספק כיסוי רחב +**תשתית משותפת**: שניהם משתמשים באותו גרף ידע ובשירותי prompt +**ניתוב שאילתות**: המערכת יכולה לנתב שאילתות לשירות המתאים ביותר בהתאם לסוג השאלה +**מצב היברידי**: ניתן לשלב את שתי הגישות ליצירת תשובות מקיפות + +#### יחס עם OntoRAG Extraction + +**אונטולוגיות משותפות**: משתמש באותות תצורת האונטולוגיה שנטענו על ידי kg-extract-ontology +**מאגר וקטורים משותף**: משתמש בהטמעות בזיכרון משירות החילוץ +**סמנטיקה עקבית**: השאילתות פועלות על גרפים שנבנו עם אותן מגבלות אונטולוגיות + +### דוגמאות לשאילתות + +#### דוגמה 1: שאילתת ישות פשוטה +**שאלה**: "אילו בעלי חיים הם יונקים?" +**התאמת אונטולוגיה**: [animal, mammal, subClassOf] +**שאילתה שנוצרה**: +```cypher +MATCH (a:animal)-[:subClassOf*]->(m:mammal) +RETURN a.name +``` + +#### דוגמה 2: שאילתת קשר +**שאלה**: "אילו מסמכים נכתבו על ידי ג'ון סמית'?" +**התאמה לאונטולוגיה**: [document, person, has-author] +**שאילתה שנוצרה**: +```cypher +MATCH (d:document)-[:has-author]->(p:person {name: "John Smith"}) +RETURN d.title, d.date +``` + +#### דוגמה 3: שאילתת אגרגציה +**שאלה**: "כמה רגליים יש לחתולים?" +**התאמה לאונטולוגיה**: [חתול, מספר-רגליים (מאפיין נתונים)] +**שאילתה שנוצרה**: +```cypher +MATCH (c:cat) +RETURN c.name, c.number_of_legs +``` + +### הגדרות + +```yaml +onto-query: + embedding_model: "text-embedding-3-small" + vector_store: + shared_with_extractor: true # Reuse kg-extract-ontology's store + query_builder: + model: "gpt-4" + temperature: 0.1 + max_query_length: 1000 + graph_executor: + timeout: 30000 # ms + max_results: 1000 + answer_generator: + model: "gpt-4" + temperature: 0.3 + max_tokens: 500 +``` + +### אופטימיזציות ביצועים + +#### אופטימיזציית שאילתות + +**גיזום אונטולוגיה**: כלול רק רכיבי אונטולוגיה נחוצים בפרומפטים +**מטמון שאילתות**: שמור שאילתות נפוצות ותשובותיהן +**מטמון תוצאות**: שמור תוצאות עבור שאילתות זהות בתוך חלון זמן +**עיבוד באצווה**: טפל במספר שאלות קשורות בביצוע מעבר גרף יחיד + +#### שיקולי סקיילביליות + +**ביצוע מבוזר**: חלק תת-שאילתות בין מחיצות גרף +**תוצאות מצטברות**: הזרם תוצאות עבור מערכי נתונים גדולים +**איזון עומסים**: חלק את עומס השאילתות בין מופעים רבים של שירות +**בריכות משאבים**: נהל בריכות חיבורים למסדי נתונים גרפיים + +### טיפול בשגיאות + +#### תרחישי כשל + +1. **יצירת שאילתה לא חוקית**: חזור ל-GraphRAG או לחיפוש מילות מפתח פשוט +2. **אי התאמת אונטולוגיה**: הרחב את החיפוש לתת-אונטולוגיה רחבה יותר +3. **זמן קצוב של שאילתה**: פשט את השאילתה או הגדל את זמן הקצוב +4. **תוצאות ריקות**: הצע ניסוח מחדש של השאילתה או שאלות קשורות +5. **כשל בשירות LLM**: השתמש בשאילתות שמורות או בתגובות מבוססות תבניות + +### מדדי ניטור + +התפלגות מורכבות של שאלות +גדלי מחיצות אונטולוגיה +שיעור הצלחה של יצירת שאילתות +זמן ביצוע שאילתות גרפיות +ציוני איכות תשובות +שיעורי פגיעה במטמון +תדירויות שגיאות לפי סוג + +## שיפורים עתידיים + +1. **למידת אונטולוגיה**: הרחב באופן אוטומטי אונטולוגיות בהתבסס על דפוסי חילוץ +4. **הקצאת ציוני אמון**: הקצה ציוני אמון לטרפלים שחולצו +3. **יצירת הסברים**: ספק הסבר לניתוח טריפלים +4. **למידה פעילה**: בקש אימות אנושי לחילוצים לא ודאיים + +## שיקולי אבטחה + +1. **מניעת הזרקת פרומפטים**: נקה טקסט של חלקים לפני בניית פרומפט +2. **מגבלות משאבים**: הגבל את השימוש בזיכרון עבור מאגר וקטורים +3. **הגבלת קצב**: הגבל בקשות חילוץ לכל לקוח +4. **רישום ביקורת**: עקוב אחר כל בקשות חילוץ ותוצאות + +## אסטרטגיית בדיקה + +### בדיקות יחידה + +טוען אונטולוגיה עם פורמטים שונים +יצירת ואחסון וקטורים +אלגוריתמים לחלוקת משפטים +חישובים של דמיון וקטורי +ניתוח ותיקוף טריפלים + +### בדיקות אינטגרציה + +צינור חילוץ מקצה לקצה +אינטגרציה עם שירות תצורה +אינטראקציה עם שירות פרומפטים +טיפול בו-זמני בחילוץ + +### בדיקות ביצועים + +טיפול באונטולוגיות גדולות (1000+ מחלקות) +עיבוד נפח גבוה של חלקים +שימוש בזיכרון תחת עומס +מדדי השהייה + +## תוכנית הפצה + +### סקירה כללית + +מערכת OntoRAG תופץ בארבע פאזות עיקריות, כאשר כל פאזה מספקת ערך מצטבר תוך בניית המערכת השלמה. התוכנית מתמקדת בהקמת יכולות חילוץ בסיסיות תחילה, ולאחר מכן הוספת פונקציונליות שאילתות, ולאחר מכן אופטימיזציות ותכונות מתקדמות. + +### פאזה 1: יסודות וחילוץ ליבה + +**מטרה**: הקמת צינור חילוץ מונחה אונטולוגיה בסיסי עם התאמת וקטורים פשוטה. + +#### שלב 1.1: יסודות ניהול אונטולוגיה +יישום טוען תצורה של אונטולוגיה (`OntologyLoader`) +ניתוח ותיקוף מבני JSON של אונטולוגיה +יצירת אחסון אונטולוגיה בזיכרון ודפוסי גישה +יישום מנגנון רענון אונטולוגיה + +**קריטריוני הצלחה**: +טעינה וניתוח מוצלחים של תצורות אונטולוגיה +אימות מבנה אונטולוגיה ועקביות +טיפול במספר אונטולוגיות בו-זמנית + +#### שלב 1.2: יישום מאגר וקטורים +יישום מאגר וקטורים פשוט מבוסס NumPy כפרוטוטייפ ראשוני +הוספת יישום מאגר וקטורים FAISS +יצירת הפשטת ממשק למאגר וקטורים +יישום חיפוש דמיון עם ספים הניתנים לתצורה + +**קריטריוני הצלחה**: +אחסון ושליפה של הטמעות בצורה יעילה +ביצוע חיפוש דמיון עם השהייה של פחות מ-100ms +תמיכה גם ב-NumPy וגם ב-FAISS + +#### שלב 1.3: צינור הטמעת אונטולוגיה +שילוב עם שירות הטמעות +יישום רכיב `OntologyEmbedder` +יצירת הטמעות עבור כל רכיבי האונטולוגיה +אחסון הטמעות עם מטא-דאטה ב-vector store + +**קריטריוני הצלחה**: +יצירת הטמעות עבור מחלקות ומאפיינים +אחסון הטמעות עם מטא-דאטה מתאים +בנייה מחדש של הטמעות בעת עדכוני אונטולוגיה + +#### שלב 1.4: רכיבי עיבוד טקסט +יישום מפצל משפטים באמצעות NLTK/spaCy +חילוץ ביטויים וישויות שמניות +יצירת היררכיה של פלחי טקסט +יצירת הטמעות עבור פלחי טקסט + +**קריטריוני הצלחה**: +חלוקה מדויקת של טקסט למשפטים +חילוץ ביטויים בעלי משמעות +שמירה על יחסי הקשר + +#### שלב 1.5: אלגוריתם בחירת אונטולוגיה +יישום התאמת דמיון בין טקסט לאונטולוגיה +בניית פתרון תלות עבור רכיבי אונטולוגיה +יצירת תת-קבוצות אונטולוגיה קוהרנטיות מינימליות +אופטימיזציה של ביצועי יצירת תת-קבוצות + +**קריטריוני הצלחה**: +בחירת רכיבי אונטולוגיה רלוונטיים בדיוק של >80% +הכללת כל התלויות הנדרשות +יצירת תת-קבוצות בפחות מ-500ms + +#### שלב 1.6: שירות חילוץ בסיסי +יישום בניית הנחיה לחילוץ +שילוב עם שירות הנחיות +ניתוח ואימות תגובות משולשות +יצירת נקודת שירות `kg-extract-ontology` + +**קריטריוני הצלחה**: +חילוץ משולשות התואמות לאונטולוגיה +אימות כל המשולשות מול האונטולוגיה +טיפול בשגיאות חילוץ בצורה חלקה + +### שלב 2: יישום מערכת שאילתות + +**מטרה**: הוספת יכולות שאילתות מודעות לאונטולוגיה עם תמיכה במספר ממשקים. + +#### שלב 2.1: רכיבי יסוד של שאילתות +יישום מנתח שאלות +יצירת מתאם אונטולוגיה לשאילתות +התאמת חיפוש וקטורי להקשר השאילתה +בניית רכיב ניתוב ממשקים + +**קריטריוני הצלחה**: +ניתוח שאלות לרכיבים סמנטיים +התאמת שאלות לרכיבי אונטולוגיה רלוונטיים +ניתוב שאילתות לממשק מתאים + +#### שלב 2.2: יישום נתיב SPARQL +יישום שירות `onto-query-sparql` +יצירת מחולל שאילתות SPARQL באמצעות LLM +פיתוח תבניות הנחיה ליצירת SPARQL +אימות תחביר SPARQL שנוצר + +**קריטריוני הצלחה**: +יצירת שאילתות SPARQL חוקיות +שימוש בתבניות SPARQL מתאימות +טיפול בסוגי שאילתות מורכבים + +#### שלב 2.3: מנוע SPARQL-Cassandra +יישום ממשק rdflib Store עבור Cassandra +יצירת מתרגם שאילתות CQL +אופטימיזציה של התאמת תבניות משולשות +טיפול בעיצוב תוצאות SPARQL + +**קריטריוני הצלחה**: +ביצוע שאילתות SPARQL על Cassandra +תמיכה בתבניות SPARQL נפוצות +החזרת תוצאות בפורמט סטנדרטי + +#### שלב 2.4: יישום נתיב Cypher +יישום שירות `onto-query-cypher` +יצירת מחולל שאילתות Cypher באמצעות LLM +פיתוח תבניות הנחיה ליצירת Cypher +אימות תחביר Cypher שנוצר + +**קריטריוני הצלחה**: +יצירת שאילתות Cypher חוקיות +שימוש בתבניות גרף מתאימות +תמיכה ב-Neo4j, Memgraph, FalkorDB + +#### שלב 2.5: מפעיל Cypher +הטמעת מנגנון ביצוע שאילתות Cypher עבור מספר מסדי נתונים. +תמיכה בפרוטוקול Bolt (Neo4j/Memgraph). +תמיכה בפרוטוקול Redis (FalkorDB). +טיפול בנרמול תוצאות. + +**קריטריוני הצלחה**: +ביצוע שאילתות Cypher על כל מסדי הנתונים המיועדים. +טיפול בהבדלים ספציפיים למסד נתונים. +שמירה על בריכות חיבורים בצורה יעילה. + +#### שלב 2.6: יצירת תשובות +הטמעת רכיב ליצירת תשובות. +יצירת הנחיות ליצירת תשובות. +עיצוב תוצאות שאילתות לצריכה על ידי מודל שפה גדול (LLM). +יצירת תשובות בשפה טבעית. + +**קריטריוני הצלחה**: +יצירת תשובות מדויקות מתוצאות שאילתות. +שמירה על הקשר משאלת השאלה המקורית. +מתן תשובות ברורות ותמציתיות. + +### שלב 3: אופטימיזציה ואמינות + +**מטרה**: אופטימיזציה של ביצועים, הוספת מנגנון אחסון מטמון, שיפור טיפול בשגיאות ושיפור אמינות. + +#### שלב 3.1: אופטימיזציה של ביצועים +הטמעת מנגנון אחסון מטמון עבור הטמעות (embeddings). +הוספת מנגנון אחסון מטמון עבור תוצאות שאילתות. +אופטימיזציה של חיפוש וקטורי באמצעות אינדקסים IVF של FAISS. +הטמעת עיבוד באצווה עבור הטמעות. + +**קריטריוני הצלחה**: +הפחתת זמן השהייה ממוצע של שאילתות ב-50%. +תמיכה במספר גדול פי 10 של בקשות מקבילות. +שמירה על זמני תגובה מתחת לשנייה. + +#### שלב 3.2: טיפול מתקדם בשגיאות +הטמעת מנגנון התאוששות מקיף משגיאות. +הוספת מנגנוני גיבוי בין נתיבי שאילתות. +יצירת לוגיקה של ניסיונות חוזרים עם השהייה אקספוננציאלית. +שיפור רישום שגיאות ואבחון. + +**קריטריוני הצלחה**: +טיפול תקין בכל תרחישי כשל. +מעבר אוטומטי בין מערכות גיבוי. +דיווח מפורט על שגיאות לצורך איתור באגים. + +#### שלב 3.3: ניטור ונגישות +הוספת איסוף מדדי ביצועים. +הטמעת מעקב אחר שאילתות. +יצירת נקודות קצה לבדיקת תקינות. +הוספת ניטור שימוש במשאבים. + +**קריטריוני הצלחה**: +מעקב אחר כל מדדי הביצועים העיקריים. +זיהוי צווארי בקבוק במהירות. +ניטור בריאות המערכת בזמן אמת. + +#### שלב 3.4: ניהול תצורה +הטמעת עדכונים דינמיים של תצורה. +הוספת אימות תצורה. +יצירת תבניות תצורה. +תמיכה בהגדרות ספציפיות לסביבה. + +**קריטריוני הצלחה**: +עדכון תצורה ללא אתחול מחדש. +אימות כל שינויי התצורה. +תמיכה בסביבות פריסה מרובות. + +### שלב 4: תכונות מתקדמות + +**מטרה**: הוספת יכולות מתקדמות לפריסה בסביבת ייצור ושיפור פונקציונליות. + +#### שלב 4.1: תמיכה במספר אונטולוגיות +הטמעת לוגיקה לבחירת אונטולוגיה. +תמיכה בשאילתות חוצות אונטולוגיות. +טיפול בגרסאות של אונטולוגיות. +יצירת יכולות מיזוג אונטולוגיות. + +**קריטריוני הצלחה**: +שאילתות על פני מספר אונטולוגיות. +טיפול בקונפליקטים בין אונטולוגיות. +תמיכה באבולוציה של אונטולוגיות. + +#### שלב 4.2: ניתוב שאילתות חכם +הטמעת ניתוב מבוסס ביצועים +הוספת ניתוח מורכבות שאילתות +יצירת אלגוריתמי ניתוב אדפטיביים +תמיכה בבדיקות A/B עבור נתיבים + +**קריטריוני הצלחה**: +ניתוב שאילתות בצורה אופטימלית +למידה מביצועי שאילתות +שיפור הניתוב לאורך זמן + +#### שלב 4.3: תכונות חילוץ מתקדמות +הוספת ניקוד אמון עבור משולשות +הטמעת יצירת הסברים +יצירת לולאות משוב לשיפור +תמיכה בלמידה מצטברת + +**קריטריוני הצלחה**: +מתן ציוני אמון +הסבר החלטות חילוץ +שיפור מתמיד של הדיוק + +#### שלב 4.4: חיזוק עבור סביבת ייצור +הוספת הגבלת קצב +הטמעת אימות/הרשאה +יצירת אוטומציה של פריסה +הוספת גיבוי ושחזור + +**קריטריוני הצלחה**: +אבטחה מוכנה לסביבת ייצור +תהליך פריסה אוטומטי +יכולת שחזור מאסון + +### אבני דרך של אספקה + +1. **אבן דרך 1** (סוף שלב 1): חילוץ מבוסס אונטולוגיה בסיסי פועל +2. **אבן דרך 2** (סוף שלב 2): מערכת שאילתות מלאה עם נתיבי SPARQL ו-Cypher +3. **אבן דרך 3** (סוף שלב 3): מערכת מותאמת ויציבה, מוכנה לשלב בדיקות +4. **אבן דרך 4** (סוף שלב 4): מערכת מוכנה לסביבת ייצור עם תכונות מתקדמות + +### הפחתת סיכונים + +#### סיכונים טכניים +**מדרגיות של מאגר וקטורים**: להתחיל עם NumPy, לעבור בהדרגה ל-FAISS +**דיוק יצירת שאילתות**: הטמעת מנגנוני אימות וגיבוי +**תאימות לבסיס נתונים**: לבדוק באופן נרחב עם כל סוג בסיס נתונים +**צווארי בקבוק בביצועים**: לנתח ולבצע אופטימיזציה באופן איטרטיבי + +#### סיכונים תפעוליים +**איכות אונטולוגיה**: הטמעת מנגנוני אימות ובדיקת עקביות +**תלויות שירות**: הוספת מנגנוני ניתוב וגיבוי +**מגבלות משאבים**: ניטור והגדרת מגבלות מתאימות +**עקביות נתונים**: הטמעת טיפול מתאים בעסקאות + +### מדדי הצלחה + +#### מדדי הצלחה לשלב 1 +דיוק חילוץ: >90% התאמה לאונטולוגיה +מהירות עיבוד: <שנייה אחת לחלק +זמן טעינת אונטולוגיה: <10 שניות +השהיה של חיפוש וקטורים: <100ms + +#### מדדי הצלחה לשלב 2 +שיעור הצלחה של שאילתות: >95% +השהיה של שאילתות: <2 שניות מקצה לקצה +תאימות לבסיס נתונים: 100% עבור בסיסי נתונים מיועדים +דיוק תשובות: >85% בהתבסס על נתונים זמינים + +#### מדדי הצלחה לשלב 3 +זמן פעולה של המערכת: >99.9% +שיעור התאוששות משגיאות: >95% +שיעור פגיעות במטמון: >60% +משתמשים מקבילים: >100 + +#### מדדי הצלחה לשלב 4 +שאילתות מרובות אונטולוגיות: נתמכות במלואן +אופטימיזציה של ניתוב: הפחתת השהיה של 30% +דיוק ניקוד אמון: >90% +פריסה לסביבת ייצור: עדכונים ללא השבתה + +## הפניות + +[OWL 2 Web Ontology Language](https://www.w3.org/TR/owl2-overview/) +[GraphRAG Architecture](https://github.com/microsoft/graphrag) +[Sentence Transformers](https://www.sbert.net/) +[FAISS Vector Search](https://github.com/facebookresearch/faiss) +[spaCy NLP Library](https://spacy.io/) +[rdflib Documentation](https://rdflib.readthedocs.io/) +[Neo4j Bolt Protocol](https://neo4j.com/docs/bolt/current/) diff --git a/docs/tech-specs/ontorag.hi.md b/docs/tech-specs/ontorag.hi.md new file mode 100644 index 00000000..4898c0f2 --- /dev/null +++ b/docs/tech-specs/ontorag.hi.md @@ -0,0 +1,1067 @@ +# OntoRAG: ज्ञान निष्कर्षण और क्वेरी के लिए ऑन्टोलॉजी-आधारित तकनीकी विनिर्देश + +## अवलोकन + +OntoRAG एक ऑन्टोलॉजी-संचालित ज्ञान निष्कर्षण और क्वेरी प्रणाली है जो असंरचित पाठ से ज्ञान त्रिक के निष्कर्षण और परिणामी ज्ञान ग्राफ की क्वेरी दोनों के दौरान सख्त सिमेंटिक स्थिरता लागू करती है। GraphRAG के समान, लेकिन औपचारिक ऑन्टोलॉजी बाधाओं के साथ, OntoRAG यह सुनिश्चित करता है कि सभी निकाले गए त्रिक पूर्वनिर्धारित ऑन्टोलॉजिकल संरचनाओं का पालन करते हैं और सिमेंटिक रूप से जागरूक क्वेरी क्षमताओं को प्रदान करता है। + +सिस्टम निष्कर्षण और क्वेरी दोनों कार्यों के लिए प्रासंगिक ऑन्टोलॉजी उपसमुच्चय को गतिशील रूप से चुनने के लिए वेक्टर समानता मिलान का उपयोग करता है, जो केंद्रित और प्रासंगिक प्रसंस्करण को सक्षम करता है जबकि सिमेंटिक वैधता बनाए रखता है। + +**सेवा का नाम**: `kg-extract-ontology` + +## लक्ष्य + +**ऑन्टोलॉजी-अनुरूप निष्कर्षण**: सुनिश्चित करें कि सभी निकाले गए त्रिक लोड की गई ऑन्टोलॉजी का सख्ती से पालन करते हैं। +**गतिशील संदर्भ चयन**: प्रत्येक खंड के लिए प्रासंगिक ऑन्टोलॉजी उपसमुच्चय का चयन करने के लिए एम्बेडिंग का उपयोग करें। +**सिमेंटिक स्थिरता**: वर्ग पदानुक्रम, संपत्ति डोमेन/रेंज और बाधाओं को बनाए रखें। +**कुशल प्रसंस्करण**: तेज़ ऑन्टोलॉजी तत्व मिलान के लिए इन-मेमोरी वेक्टर स्टोर का उपयोग करें। +**स्केलेबल आर्किटेक्चर**: विभिन्न डोमेन वाली कई समवर्ती ऑन्टोलॉजी का समर्थन करें। + +## पृष्ठभूमि + +वर्तमान ज्ञान निष्कर्षण सेवाएं (`kg-extract-definitions`, `kg-extract-relationships`) औपचारिक बाधाओं के बिना काम करती हैं, जिससे असंगत या असंगत त्रिक उत्पन्न हो सकते हैं। OntoRAG इस समस्या को हल करता है: + +1. औपचारिक ऑन्टोलॉजी लोड करना जो मान्य वर्ग और गुण परिभाषित करते हैं। +2. पाठ सामग्री को प्रासंगिक ऑन्टोलॉजी तत्वों से मिलाने के लिए एम्बेडिंग का उपयोग करना। +3. निष्कर्षण को केवल ऑन्टोलॉजी-अनुरूप त्रिक उत्पन्न करने तक सीमित करना। +4. निकाले गए ज्ञान का सिमेंटिक सत्यापन प्रदान करना। + +यह दृष्टिकोण औपचारिक ज्ञान प्रतिनिधित्व की कठोरता के साथ तंत्रिका निष्कर्षण की लचीलापन को जोड़ता है। + +## तकनीकी डिजाइन + +### आर्किटेक्चर + +OntoRAG सिस्टम में निम्नलिखित घटक शामिल हैं: + +``` +┌─────────────────┐ +│ Configuration │ +│ Service │ +└────────┬────────┘ + │ Ontologies + ▼ +┌─────────────────┐ ┌──────────────┐ +│ kg-extract- │────▶│ Embedding │ +│ ontology │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ │ + ▼ ▼ +┌─────────────────┐ ┌──────────────┐ +│ In-Memory │◀────│ Ontology │ +│ Vector Store │ │ Embedder │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Sentence │────▶│ Chunker │ +│ Splitter │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Ontology │────▶│ Vector │ +│ Selector │ │ Search │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Prompt │────▶│ Prompt │ +│ Constructor │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ +│ Triple Output │ +└─────────────────┘ +``` + +### घटक विवरण + +#### 1. ऑन्टोलॉजी लोडर + +**उद्देश्य**: इवेंट-ड्रिवेन अपडेट का उपयोग करके, कॉन्फ़िगरेशन सेवा से ऑन्टोलॉजी कॉन्फ़िगरेशन प्राप्त करता है और पार्स करता है। + +**कार्यान्वयन**: +ऑन्टोलॉजी लोडर, इवेंट-ड्रिवेन ऑन्टोलॉजी कॉन्फ़िगरेशन अपडेट प्राप्त करने के लिए ट्रस्टग्राफ के कॉन्फ़िगपुश क्यू का उपयोग करता है। जब "ऑन्टोलॉजी" प्रकार का कोई कॉन्फ़िगरेशन तत्व जोड़ा या संशोधित किया जाता है, तो लोडर कॉन्फ़िग-अपडेट क्यू के माध्यम से अपडेट प्राप्त करता है और मेटाडेटा, क्लास, ऑब्जेक्ट प्रॉपर्टी और डेटाटाइप प्रॉपर्टी युक्त JSON संरचना को पार्स करता है। इन पार्स किए गए ऑन्टोलॉजी को संरचित ऑब्जेक्ट के रूप में मेमोरी में संग्रहीत किया जाता है, जिन्हें निष्कर्षण प्रक्रिया के दौरान कुशलतापूर्वक एक्सेस किया जा सकता है। + +**मुख्य कार्य**: +ऑन्टोलॉजी-प्रकार कॉन्फ़िगरेशन के लिए कॉन्फ़िग-अपडेट क्यू की सदस्यता लें +JSON ऑन्टोलॉजी संरचनाओं को ऑन्टोलॉजीक्लास और ऑन्टोलॉजीप्रॉपर्टी ऑब्जेक्ट में पार्स करें +ऑन्टोलॉजी संरचना और स्थिरता को मान्य करें +तेज़ एक्सेस के लिए पार्स किए गए ऑन्टोलॉजी को मेमोरी में कैश करें +फ्लो-विशिष्ट वेक्टर स्टोर के साथ प्रति-फ्लो प्रोसेसिंग को संभालें + +**कार्यान्वयन स्थान**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_loader.py` + +#### 2. ऑन्टोलॉजी एम्बेडर + +**उद्देश्य**: सभी ऑन्टोलॉजी तत्वों के लिए वेक्टर एम्बेडिंग बनाता है ताकि सिमेंटिक समानता मिलान को सक्षम किया जा सके। + +**कार्यान्वयन**: +ऑन्टोलॉजी एम्बेडर, लोड किए गए ऑन्टोलॉजी (क्लास, ऑब्जेक्ट प्रॉपर्टी और डेटाटाइप प्रॉपर्टी) में प्रत्येक तत्व को संसाधित करता है और एम्बेडिंगक्लाइंटस्पेसिफिकेशन सेवा का उपयोग करके वेक्टर एम्बेडिंग उत्पन्न करता है। प्रत्येक तत्व के लिए, यह तत्व की पहचानकर्ता, लेबल और विवरण (टिप्पणी) को मिलाकर एक टेक्स्ट प्रतिनिधित्व बनाता है। इस टेक्स्ट को तब एक उच्च-आयामी वेक्टर एम्बेडिंग में परिवर्तित किया जाता है जो इसके सिमेंटिक अर्थ को कैप्चर करता है। ये एम्बेडिंग, तत्व प्रकार, स्रोत ऑन्टोलॉजी और पूर्ण परिभाषा के बारे में मेटाडेटा के साथ, प्रति-फ्लो इन-मेमोरी FAISS वेक्टर स्टोर में संग्रहीत किए जाते हैं। एम्बेडर स्वचालित रूप से पहले एम्बेडिंग प्रतिक्रिया से एम्बेडिंग आयाम का पता लगाता है। + +**मुख्य कार्य**: +तत्व आईडी, लेबल और टिप्पणियों से टेक्स्ट प्रतिनिधित्व बनाएं +बैच प्रोसेसिंग के लिए asyncio.gather का उपयोग करके एम्बेडिंगक्लाइंटस्पेसिफिकेशन के माध्यम से एम्बेडिंग उत्पन्न करें +व्यापक मेटाडेटा के साथ FAISS वेक्टर स्टोर में एम्बेडिंग संग्रहीत करें +कुशल पुनर्प्राप्ति के लिए ऑन्टोलॉजी, तत्व प्रकार और तत्व आईडी द्वारा अनुक्रमित करें +वेक्टर स्टोर इनिशियलाइज़ेशन के लिए एम्बेडिंग आयामों का स्वचालित रूप से पता लगाएं +स्वतंत्र वेक्टर स्टोर के साथ प्रति-फ्लो एम्बेडिंग मॉडल को संभालें + +**कार्यान्वयन स्थान**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_embedder.py` + +#### 3. टेक्स्ट प्रोसेसर (वाक्य विभाजक) + +**उद्देश्य**: सटीक ऑन्टोलॉजी मिलान के लिए टेक्स्ट चंक्स को बारीक खंडों में विघटित करता है। + +**कार्यान्वयन**: +टेक्स्ट प्रोसेसर, वाक्य टोकनाइजेशन और POS टैगिंग के लिए NLTK का उपयोग करता है ताकि आने वाले टेक्स्ट चंक्स को वाक्यों में तोड़ा जा सके। यह NLTK संस्करण अनुकूलता को संभालने के लिए `punkt_tab` और `averaged_perceptron_tagger_eng` डाउनलोड करने का प्रयास करता है, और यदि आवश्यक हो तो पुराने संस्करणों पर वापस आ जाता है। प्रत्येक टेक्स्ट चंक को व्यक्तिगत वाक्यों में विभाजित किया जाता है जिन्हें स्वतंत्र रूप से ऑन्टोलॉजी तत्वों के खिलाफ मिलान किया जा सकता है। + +**मुख्य कार्य**: +NLTK वाक्य टोकनाइजेशन का उपयोग करके टेक्स्ट को वाक्यों में विभाजित करें +NLTK संस्करण अनुकूलता को संभालें (punkt_tab बनाम punkt) +टेक्स्ट और स्थिति जानकारी के साथ TextSegment ऑब्जेक्ट बनाएं +पूर्ण वाक्यों और व्यक्तिगत चंक्स दोनों का समर्थन करें + +**कार्यान्वयन स्थान**: `trustgraph-flow/trustgraph/extract/kg/ontology/text_processor.py` + +#### 4. ऑन्टोलॉजी चयनकर्ता + +**उद्देश्य**: वर्तमान टेक्स्ट चंक के लिए सबसे प्रासंगिक ऑन्टोलॉजी तत्वों का सबसे उपयुक्त उपसमुच्चय की पहचान करता है। + +**कार्यान्वयन**: +ऑन्टोलॉजी चयनकर्ता, FAISS वेक्टर समानता खोज का उपयोग करके टेक्स्ट सेगमेंट और ऑन्टोलॉजी तत्वों के बीच सिमेंटिक मिलान करता है। प्रत्येक टेक्स्ट चंक से प्रत्येक वाक्य के लिए, यह एक एम्बेडिंग उत्पन्न करता है और कॉन्फ़िगर करने योग्य थ्रेसहोल्ड (डिफ़ॉल्ट 0.3) के साथ कोसाइन समानता का उपयोग करके वेक्टर स्टोर में सबसे समान ऑन्टोलॉजी तत्वों की खोज करता है। सभी प्रासंगिक तत्वों को एकत्र करने के बाद, यह व्यापक निर्भरता संकल्प करता है: यदि कोई क्लास का चयन किया जाता है, तो उसके पैरेंट क्लास शामिल होते हैं; यदि कोई प्रॉपर्टी का चयन किया जाता है, तो उसके डोमेन और रेंज क्लास जोड़े जाते हैं। इसके अतिरिक्त, प्रत्येक चयनित क्लास के लिए, यह स्वचालित रूप से **सभी प्रॉपर्टी को शामिल करता है जो उस क्लास को उनके डोमेन या रेंज में संदर्भित करती हैं**। यह सुनिश्चित करता है कि निष्कर्षण के पास सभी प्रासंगिक संबंध प्रॉपर्टी तक पहुंच है। + +**मुख्य कार्य:** +प्रत्येक पाठ खंड के लिए एम्बेडिंग उत्पन्न करें (वाक्य) +FAISS वेक्टर स्टोर में k-निकटतम पड़ोसी खोज करें (top_k=10, threshold=0.3) +कमजोर मिलानों को फ़िल्टर करने के लिए समानता सीमा लागू करें +निर्भरताएँ हल करें (पैरेंट क्लास, डोमेन, रेंज) +**चयनित कक्षाओं से संबंधित सभी गुणों को स्वचालित रूप से शामिल करें** (डोमेन/रेंज मिलान) +सभी आवश्यक संबंधों के साथ सुसंगत ऑन्टोलॉजी उपसमुच्चय बनाएं +ऐसे तत्व डुप्लिकेट करें जो कई बार दिखाई देते हैं + +**कार्यान्वयन स्थान:** `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_selector.py` + +#### 5. प्रॉम्प्ट निर्माण + +**उद्देश्य:** संरचित प्रॉम्प्ट बनाता है जो LLM को केवल ऑन्टोलॉजी-अनुरूप ट्रिपल निकालने के लिए मार्गदर्शन करता है। + +**कार्यान्वयन:** +निष्कर्षण सेवा एक Jinja2 टेम्पलेट का उपयोग करती है जिसे `ontology-prompt.md` से लोड किया जाता है जो LLM निष्कर्षण के लिए ऑन्टोलॉजी उपसमुच्चय और पाठ को प्रारूपित करता है। टेम्पलेट गतिशील रूप से Jinja2 सिंटैक्स का उपयोग करके कक्षाओं, ऑब्जेक्ट गुणों और डेटाटाइप गुणों पर पुनरावृति करता है, प्रत्येक को उनके विवरण, डोमेन, रेंज और पदानुक्रमित संबंधों के साथ प्रस्तुत करता है। प्रॉम्प्ट में केवल प्रदान किए गए ऑन्टोलॉजी तत्वों का उपयोग करने के बारे में सख्त नियम शामिल हैं और सुसंगत पार्सिंग के लिए JSON आउटपुट प्रारूप का अनुरोध करता है। + +**मुख्य कार्य:** +ऑन्टोलॉजी तत्वों पर लूप के साथ Jinja2 टेम्पलेट का उपयोग करें +पैरेंट रिलेशनशिप (subclass_of) और टिप्पणियों के साथ कक्षाओं को प्रारूपित करें +डोमेन/रेंज बाधाओं और टिप्पणियों के साथ गुणों को प्रारूपित करें +स्पष्ट निष्कर्षण नियमों और आउटपुट प्रारूप आवश्यकताओं को शामिल करें +"extract-with-ontologies" टेम्पलेट आईडी के साथ प्रॉम्प्ट सेवा को कॉल करें + +**टेम्पलेट स्थान:** `ontology-prompt.md` +**कार्यान्वयन स्थान:** `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` (build_extraction_variables विधि) + +#### 6. मुख्य निष्कर्षण सेवा + +**उद्देश्य:** एंड-टू-एंड ऑन्टोलॉजी-आधारित ट्रिपल निष्कर्षण करने के लिए सभी घटकों का समन्वय करें। + +**कार्यान्वयन:** +मुख्य निष्कर्षण सेवा (KgExtractOntology) ऑर्केस्ट्रेशन परत है जो संपूर्ण निष्कर्षण वर्कफ़्लो का प्रबंधन करती है। यह प्रति-प्रवाह घटक प्रारंभिकरण के साथ TrustGraph के FlowProcessor पैटर्न का उपयोग करता है। जब कोई ऑन्टोलॉजी कॉन्फ़िगरेशन अपडेट प्राप्त होता है, तो यह प्रवाह-विशिष्ट घटकों (ऑन्टोलॉजी लोडर, एम्बेडर, टेक्स्ट प्रोसेसर, सेलेक्टर) को आरंभ या अपडेट करता है। जब प्रसंस्करण के लिए एक पाठ खंड प्राप्त होता है, तो यह पाइपलाइन का समन्वय करता है: पाठ को खंडों में विभाजित करना, वेक्टर खोज के माध्यम से प्रासंगिक ऑन्टोलॉजी तत्वों को खोजना, एक प्रतिबंधित प्रॉम्प्ट का निर्माण करना, प्रॉम्प्ट सेवा को कॉल करना, प्रतिक्रिया को पार्स और मान्य करना, ऑन्टोलॉजी परिभाषा ट्रिपल उत्पन्न करना और सामग्री ट्रिपल और इकाई संदर्भ दोनों का उत्सर्जन करना। + +**निष्कर्षण पाइपलाइन:** +1. chunks-input क्यू के माध्यम से पाठ खंड प्राप्त करें +2. यदि आवश्यक हो तो प्रवाह घटकों को आरंभ करें (पहले खंड या कॉन्फ़िगरेशन अपडेट पर) +3. NLTK का उपयोग करके पाठ को वाक्यों में विभाजित करें +4. प्रासंगिक ऑन्टोलॉजी अवधारणाओं को खोजने के लिए FAISS वेक्टर स्टोर खोजें +5. स्वचालित संपत्ति समावेश के साथ ऑन्टोलॉजी उपसमुच्चय बनाएं +6. Jinja2-टेम्प्लेटेड प्रॉम्प्ट चर बनाएं +7. extract-with-ontologies टेम्पलेट के साथ प्रॉम्प्ट सेवा को कॉल करें +8. संरचित ट्रिपल में JSON प्रतिक्रिया को पार्स करें +9. ट्रिपल को मान्य करें और पूर्ण ऑन्टोलॉजी URIs का उपयोग करके URIs का विस्तार करें +10. ऑन्टोलॉजी परिभाषा ट्रिपल (लेबल/टिप्पणी/डोमेन/रेंज के साथ कक्षाएं और गुण) उत्पन्न करें +11. सभी ट्रिपल से इकाई संदर्भ बनाएं +12. ट्रिपल और इकाई-संदर्भ क्यू पर उत्सर्जित करें + +**मुख्य विशेषताएं:** +विभिन्न एम्बेडिंग मॉडल का समर्थन करने वाले प्रति-प्रवाह वेक्टर स्टोर +config-update क्यू के माध्यम से घटना-संचालित ऑन्टोलॉजी अपडेट +ऑन्टोलॉजी URIs का उपयोग करके स्वचालित URI विस्तार +पूर्ण मेटाडेटा के साथ ज्ञान ग्राफ में जोड़े गए ऑन्टोलॉजी तत्व +इकाई संदर्भों में सामग्री और ऑन्टोलॉजी तत्व दोनों शामिल हैं + +**कार्यान्वयन स्थान:** `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` + +### कॉन्फ़िगरेशन + +सेवा कमांड-लाइन तर्कों के साथ TrustGraph के मानक कॉन्फ़िगरेशन दृष्टिकोण का उपयोग करती है: + +```bash +kg-extract-ontology \ + --id kg-extract-ontology \ + --pulsar-host localhost:6650 \ + --input-queue chunks \ + --config-input-queue config-update \ + --output-queue triples \ + --entity-contexts-output-queue entity-contexts +``` + +**मुख्य कॉन्फ़िगरेशन पैरामीटर**: +`similarity_threshold`: 0.3 (डिफ़ॉल्ट, कोड में कॉन्फ़िगर करने योग्य) +`top_k`: 10 (प्रत्येक खंड के लिए पुनः प्राप्त होने वाले ऑन्टोलॉजी तत्वों की संख्या) +`vector_store`: ऑटो-डिटेक्टेड आयामों के साथ प्रति-फ़्लो FAISS IndexFlatIP +`text_processor`: NLTK के साथ punt_tab वाक्य टोकनाइजेशन +`prompt_template`: "extract-with-ontologies" (Jinja2 टेम्पलेट) + +**ऑन्टोलॉजी कॉन्फ़िगरेशन**: +ऑन्टोलॉजी को "ontology" प्रकार के साथ कॉन्फ़िग-अपडेट कतार के माध्यम से गतिशील रूप से लोड किया जाता है। + +### डेटा प्रवाह + +1. **आरंभीकरण चरण** (प्रति-फ़्लो): + कॉन्फ़िग-अपडेट कतार के माध्यम से ऑन्टोलॉजी कॉन्फ़िगरेशन प्राप्त करें + ऑन्टोलॉजी JSON को OntologyClass और OntologyProperty ऑब्जेक्ट में पार्स करें + EmbeddingsClientSpec का उपयोग करके सभी ऑन्टोलॉजी तत्वों के लिए एम्बेडिंग उत्पन्न करें + प्रति-फ़्लो FAISS वेक्टर स्टोर में एम्बेडिंग संग्रहीत करें + पहले प्रतिक्रिया से एम्बेडिंग आयामों का ऑटो-डिटेक्शन + +2. **निष्कर्षण चरण** (प्रति-खंड): + chunks-input कतार से खंड प्राप्त करें + NLTK का उपयोग करके खंड को वाक्यों में विभाजित करें + प्रत्येक वाक्य के लिए एम्बेडिंग की गणना करें + प्रासंगिक ऑन्टोलॉजी तत्वों के लिए FAISS वेक्टर स्टोर खोजें + स्वचालित संपत्ति समावेश के साथ ऑन्टोलॉजी उपसमुच्चय बनाएं + पाठ और ऑन्टोलॉजी के साथ Jinja2 टेम्पलेट चर बनाएं + extract-with-ontologies टेम्पलेट के साथ प्रॉम्प्ट सेवा को कॉल करें + JSON प्रतिक्रिया को पार्स करें और ट्रिपल को मान्य करें + ऑन्टोलॉजी URIs का उपयोग करके URIs का विस्तार करें + ऑन्टोलॉजी परिभाषा ट्रिपल उत्पन्न करें + सभी ट्रिपल से इकाई संदर्भ बनाएं + ट्रिपल और इकाई-संदर्भ कतारों पर उत्सर्जित करें + +### इन-मेमोरी वेक्टर स्टोर + +**उद्देश्य**: ऑन्टोलॉजी तत्व मिलान के लिए तेज़, मेमोरी-आधारित समानता खोज प्रदान करता है। + +**कार्यान्वयन: FAISS** + +सिस्टम **FAISS (फेसबुक एआई समानता खोज)** का उपयोग सटीक कोसाइन समानता खोज के लिए IndexFlatIP के साथ करता है। मुख्य विशेषताएं: + +**IndexFlatIP**: आंतरिक उत्पाद का उपयोग करके सटीक कोसाइन समानता खोज +**ऑटो-डिटेक्शन**: पहले एम्बेडिंग प्रतिक्रिया से आयाम निर्धारित होता है +**प्रति-फ़्लो स्टोर**: प्रत्येक फ़्लो में विभिन्न एम्बेडिंग मॉडल के लिए एक स्वतंत्र वेक्टर स्टोर होता है +**सामान्यीकरण**: अनुक्रमण से पहले सभी वेक्टर सामान्य होते हैं +**बैच ऑपरेशन**: प्रारंभिक ऑन्टोलॉजी लोडिंग के लिए कुशल बैच जोड़ + +**कार्यान्वयन स्थान**: `trustgraph-flow/trustgraph/extract/kg/ontology/vector_store.py` + +### ऑन्टोलॉजी उपसमुच्चय चयन एल्गोरिदम + +**उद्देश्य**: प्रत्येक पाठ खंड के लिए ऑन्टोलॉजी के न्यूनतम प्रासंगिक भाग का गतिशील रूप से चयन करता है। + +**विस्तृत एल्गोरिदम चरण**: + +1. **पाठ विभाजन**: + NLP वाक्य पहचान का उपयोग करके इनपुट खंड को वाक्यों में विभाजित करें + प्रत्येक वाक्य से संज्ञा वाक्यांश, क्रिया वाक्यांश और नामित संस्थाएं निकालें + संदर्भ को संरक्षित करते हुए खंडों की एक पदानुक्रमित संरचना बनाएं + +2. **एम्बेडिंग पीढ़ी**: + प्रत्येक पाठ खंड (वाक्यों और वाक्यांशों) के लिए वेक्टर एम्बेडिंग उत्पन्न करें + ऑन्टोलॉजी तत्वों के लिए उपयोग किए गए समान एम्बेडिंग मॉडल का उपयोग करें + प्रदर्शन में सुधार के लिए बार-बार खंडों के लिए एम्बेडिंग कैश करें + +3. **समानता खोज**: + प्रत्येक पाठ खंड एम्बेडिंग के लिए, वेक्टर स्टोर खोजें + शीर्ष-k (जैसे, 10) सबसे समान ऑन्टोलॉजी तत्वों को पुनः प्राप्त करें + कमजोर मिलानों को फ़िल्टर करने के लिए समानता थ्रेसहोल्ड (जैसे, 0.7) लागू करें + सभी खंडों में परिणामों को एकत्रित करें, मिलान आवृत्तियों को ट्रैक करें + +4. **निर्भरता संकल्प**: + प्रत्येक चयनित वर्ग के लिए, रूट तक सभी मूल वर्गों को पुनरावर्ती रूप से शामिल करें + प्रत्येक चयनित संपत्ति के लिए, इसके डोमेन और रेंज कक्षाओं को शामिल करें + उलटे गुणों के लिए, सुनिश्चित करें कि दोनों दिशाएं शामिल हैं + यदि ऑन्टोलॉजी में मौजूद हैं तो समकक्ष कक्षाओं को जोड़ें + +5. **उपसमुच्चय निर्माण**: + संबंधों को संरक्षित करते हुए एकत्र किए गए तत्वों को डुप्लिकेट करें + कक्षाओं, ऑब्जेक्ट गुणों और डेटा प्रकार गुणों में व्यवस्थित करें + सुनिश्चित करें कि सभी बाधाएं और संबंध संरक्षित हैं + एक स्व-निहित मिनी-ऑन्टोलॉजी बनाएं जो मान्य और पूर्ण हो + +**उदाहरण वॉकथ्रू**: +पाठ: "भूरे रंग का कुत्ता सफेद बिल्ली को पेड़ पर दौड़ाता है।" +खंड: ["भूरा कुत्ता", "सफेद बिल्ली", "पेड़", "दौड़ाता है"] +मिलान किए गए तत्व: [कुत्ता (वर्ग), बिल्ली (वर्ग), जानवर (मूल), पीछा करता है (संपत्ति)] +निर्भरता: [जानवर (कुत्ते और बिल्ली का मूल), जीवनरूप (जानवर का मूल)] +अंतिम उपसमुच्चय: जानवर पदानुक्रम और पीछा संबंध के साथ पूर्ण मिनी-ऑन्टोलॉजी + +### ट्रिपल सत्यापन + +**उद्देश्य**: सुनिश्चित करता है कि सभी निकाले गए ट्रिपल सख्ती से ऑन्टोलॉजी बाधाओं का पालन करते हैं। + +**सत्यापन एल्गोरिदम**: + +1. **वर्ग सत्यापन**: + सत्यापित करें कि विषय, शब्दावली उपसमुच्चय में परिभाषित वर्गों के उदाहरण हैं। + ऑब्जेक्ट गुणों के लिए, सत्यापित करें कि ऑब्जेक्ट भी मान्य वर्ग उदाहरण हैं। + वर्ग नामों की तुलना शब्दावली के वर्ग शब्दकोश से करें। + वर्ग पदानुक्रमों को संभालें - उपवर्गों के उदाहरण मूल वर्ग बाधाओं के लिए मान्य हैं। + +2. **गुण सत्यापन**: + पुष्टि करें कि विधेय शब्दावली उपसमुच्चय में गुणों से मेल खाते हैं। + ऑब्जेक्ट गुणों (इकाई-से-इकाई) और डेटा प्रकार गुणों (इकाई-से-लिटरल) के बीच अंतर करें। + सत्यापित करें कि संपत्ति नाम बिल्कुल मेल खाते हैं (यदि मौजूद है तो नामस्थान पर विचार करते हुए)। + +3. **डोमेन/रेंज जाँच**: + प्रत्येक संपत्ति के लिए जिसका उपयोग विधेय के रूप में किया जाता है, उसका डोमेन और रेंज प्राप्त करें। + सत्यापित करें कि विषय का प्रकार संपत्ति के डोमेन से मेल खाता है या उससे विरासत में मिला है। + सत्यापित करें कि ऑब्जेक्ट का प्रकार संपत्ति के रेंज से मेल खाता है या उससे विरासत में मिला है। + डेटा प्रकार गुणों के लिए, सत्यापित करें कि ऑब्जेक्ट सही XSD प्रकार का एक लिटरल है। + +4. **कार्डिनैलिटी सत्यापन**: + प्रति विषय संपत्ति उपयोग गणनाओं को ट्रैक करें। + न्यूनतम कार्डिनैलिटी की जाँच करें - सुनिश्चित करें कि आवश्यक गुण मौजूद हैं। + अधिकतम कार्डिनैलिटी की जाँच करें - सुनिश्चित करें कि संपत्ति का उपयोग बहुत अधिक बार नहीं किया गया है। + कार्यात्मक गुणों के लिए, सुनिश्चित करें कि प्रति विषय अधिकतम एक मान है। + +5. **डेटा प्रकार सत्यापन**: + उनके घोषित XSD प्रकारों के अनुसार लिटरल मानों को पार्स करें। + सत्यापित करें कि पूर्णांक मान्य संख्याएँ हैं, तिथियाँ ठीक से स्वरूपित हैं, आदि। + यदि regex बाधाएँ परिभाषित हैं तो स्ट्रिंग पैटर्न की जाँच करें। + सुनिश्चित करें कि URIs xsd:anyURI प्रकारों के लिए अच्छी तरह से स्वरूपित हैं। + +**सत्यापन उदाहरण**: +ट्रिपल: ("बडी", "has-owner", "जॉन") +जाँचें कि "बडी" को एक ऐसे वर्ग के रूप में टाइप किया गया है जिसके पास "has-owner" संपत्ति हो सकती है। +जाँचें कि "has-owner" शब्दावली में मौजूद है। +डोमेन बाधा का सत्यापन: विषय को "पालतू" प्रकार या उपवर्ग का होना चाहिए। +रेंज बाधा का सत्यापन: ऑब्जेक्ट को "व्यक्ति" प्रकार या उपवर्ग का होना चाहिए। +यदि मान्य है, तो आउटपुट में जोड़ें; यदि अमान्य है, तो उल्लंघन को लॉग करें और छोड़ दें। + +## प्रदर्शन संबंधी विचार + +### अनुकूलन रणनीतियाँ + +1. **एम्बेडिंग कैशिंग**: बार-बार उपयोग किए जाने वाले पाठ खंडों के लिए एम्बेडिंग कैश करें। +2. **बैच प्रोसेसिंग**: कई खंडों को समानांतर में संसाधित करें। +3. **वेक्टर स्टोर इंडेक्सिंग**: बड़े शब्दावली के लिए अनुमानित निकटतम पड़ोसी एल्गोरिदम का उपयोग करें। +4. **प्रॉम्प्ट अनुकूलन**: केवल आवश्यक शब्दावली तत्वों को शामिल करके प्रॉम्प्ट आकार को कम करें। +5. **परिणाम कैशिंग**: समान टुकड़ों के लिए निष्कर्षण परिणामों को कैश करें। + +### मापनीयता + +**क्षैतिज स्केलिंग**: साझा शब्दावली कैश के साथ कई एक्सट्रैक्टर उदाहरण। +**शब्दावली विभाजन**: बड़े शब्दावली को डोमेन द्वारा विभाजित करें। +**स्ट्रीमिंग प्रोसेसिंग**: बैचिंग के बिना आने वाले टुकड़ों को संसाधित करें। +**मेमोरी प्रबंधन**: अप्रयुक्त एम्बेडिंग की आवधिक सफाई। + +## त्रुटि प्रबंधन + +### विफलता परिदृश्य + +1. **गायब शब्दावली**: बिना बाधा वाले निष्कर्षण पर वापस जाएँ। +2. **एम्बेडिंग सेवा विफलता**: कैश किए गए एम्बेडिंग का उपयोग करें या सिमेंटिक मिलान छोड़ दें। +3. **प्रॉम्प्ट सेवा टाइमआउट**: घातीय बैकऑफ़ के साथ पुनः प्रयास करें। +4. **अमान्य ट्रिपल प्रारूप**: लॉग करें और खराब ट्रिपल छोड़ दें। +5. **शब्दावली असंगतताएँ**: संघर्षों की रिपोर्ट करें और सबसे विशिष्ट मान्य तत्वों का उपयोग करें। + +### निगरानी + +ट्रैक करने के लिए प्रमुख मेट्रिक्स: + +शब्दावली लोड समय और मेमोरी उपयोग +एम्बेडिंग पीढ़ी विलंबता +वेक्टर खोज प्रदर्शन +प्रॉम्प्ट सेवा प्रतिक्रिया समय +ट्रिपल निष्कर्षण सटीकता +शब्दावली अनुरूपता दर + +## माइग्रेशन पथ + +### मौजूदा निष्कर्षक से + +1. **समानांतर संचालन**: शुरू में मौजूदा निष्कर्षक के साथ समानांतर में चलाएँ। +2. **धीरे-धीरे रोलआउट**: विशिष्ट दस्तावेज़ प्रकारों के साथ प्रारंभ करें। +3. **गुणवत्ता तुलना**: मौजूदा निष्कर्षक के साथ आउटपुट गुणवत्ता की तुलना करें। +4. **पूर्ण माइग्रेशन**: गुणवत्ता सत्यापित होने के बाद मौजूदा निष्कर्षक को बदलें। + +### शब्दावली विकास + +1. **मौजूदा से बूटस्ट्रैप करें**: मौजूदा ज्ञान से प्रारंभिक शब्दावली उत्पन्न करें। +2. **पुनरावृत्त परिशोधन**: निष्कर्षण पैटर्न के आधार पर परिष्कृत करें। +3. **डोमेन विशेषज्ञ समीक्षा**: विषय वस्तु विशेषज्ञों के साथ मान्य करें। +4. **लगातार सुधार**: निष्कर्षण प्रतिक्रिया के आधार पर अपडेट करें। + +## शब्दावली-संवेदनशील क्वेरी सेवा + +### अवलोकन + +शब्दावली-संवेदनशील क्वेरी सेवा विभिन्न बैकएंड ग्राफ स्टोर का समर्थन करने के लिए कई क्वेरी पथ प्रदान करती है। यह सटीक, सिमेंटिक रूप से-जागरूक प्रश्न उत्तर के लिए कैसेंड्रा (SPARQL के माध्यम से) और साइफर-आधारित ग्राफ स्टोर (Neo4j, Memgraph, FalkorDB) दोनों में शब्दावली ज्ञान का लाभ उठाता है। + +**सेवा घटक**: +`onto-query-sparql`: कैसेंड्रा के लिए प्राकृतिक भाषा को SPARQL में परिवर्तित करता है। +`sparql-cassandra`: कैसेंड्रा के लिए SPARQL क्वेरी परत rdflib का उपयोग करके। +`onto-query-cypher`: ग्राफ डेटाबेस के लिए प्राकृतिक भाषा को साइफर में परिवर्तित करता है। +`cypher-executor`: Neo4j/Memgraph/FalkorDB के लिए साइफर क्वेरी निष्पादन। + +### आर्किटेक्चर + +``` + ┌─────────────────┐ + │ User Query │ + └────────┬────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Question │────▶│ Sentence │ + │ Analyser │ │ Splitter │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Ontology │────▶│ Vector │ + │ Matcher │ │ Store │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Backend Router │ + └────────┬────────┘ + │ + ┌───────────┴───────────┐ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ onto-query- │ │ onto-query- │ + │ sparql │ │ cypher │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ SPARQL │ │ Cypher │ + │ Generator │ │ Generator │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ sparql- │ │ cypher- │ + │ cassandra │ │ executor │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ Cassandra │ │ Neo4j/Memgraph/ │ + │ │ │ FalkorDB │ + └────────┬────────┘ └────────┬────────┘ + │ │ + └────────────┬───────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Answer │────▶│ Prompt │ + │ Generator │ │ Service │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Final Answer │ + └─────────────────┘ +``` + +### क्वेरी प्रोसेसिंग पाइपलाइन + +#### 1. प्रश्न विश्लेषक + +**उद्देश्य**: उपयोगकर्ता के प्रश्नों को अर्थ संबंधी घटकों में विघटित करता है ताकि ऑन्टोलॉजी मिलान किया जा सके। + +**एल्गोरिदम विवरण**: +प्रश्न विश्लेषक, आने वाले प्राकृतिक भाषा प्रश्न को लेता है और इसे सार्थक खंडों में तोड़ता है, निष्कर्षण पाइपलाइन के समान वाक्य विभाजन दृष्टिकोण का उपयोग करके। यह प्रश्न में उल्लिखित प्रमुख संस्थाओं, संबंधों और बाधाओं की पहचान करता है। प्रत्येक खंड का विश्लेषण प्रश्न के प्रकार (तथ्यात्मक, एकत्रीकरण, तुलना, आदि) और अपेक्षित उत्तर प्रारूप के लिए किया जाता है। यह विघटन यह पहचानने में मदद करता है कि ऑन्टोलॉजी का कौन सा भाग प्रश्न का उत्तर देने के लिए सबसे अधिक प्रासंगिक है। + +**मुख्य कार्य**: +प्रश्न को वाक्यों और वाक्यांशों में विभाजित करें +प्रश्न के प्रकार और इरादे की पहचान करें +उल्लिखित संस्थाओं और संबंधों को निकालें +प्रश्न में बाधाओं और फ़िल्टरों का पता लगाएं +अपेक्षित उत्तर प्रारूप निर्धारित करें + +#### 2. प्रश्नों के लिए ऑन्टोलॉजी मिलानकर्ता + +**उद्देश्य**: प्रश्न का उत्तर देने के लिए आवश्यक प्रासंगिक ऑन्टोलॉजी उपसमुच्चय की पहचान करता है। + +**एल्गोरिदम विवरण**: +निष्कर्षण पाइपलाइन के ऑन्टोलॉजी चयनकर्ता के समान, लेकिन प्रश्न उत्तर देने के लिए अनुकूलित। मिलानकर्ता प्रश्न खंडों के लिए एम्बेडिंग उत्पन्न करता है और प्रासंगिक ऑन्टोलॉजी तत्वों को खोजने के लिए वेक्टर स्टोर में खोज करता है। हालांकि, यह निष्कर्षण के बजाय प्रश्न निर्माण के लिए उपयोगी होने वाले अवधारणाओं को खोजने पर ध्यान केंद्रित करता है। यह चयन को संबंधित गुणों को शामिल करने के लिए विस्तारित करता है जो ग्राफ अन्वेषण के दौरान पारगमन योग्य हो सकते हैं, भले ही उन्हें प्रश्न में स्पष्ट रूप से उल्लेख न किया गया हो। उदाहरण के लिए, यदि "कर्मचारियों" के बारे में पूछा जाता है, तो यह "काम करता है," "प्रबंधित करता है," और "रिपोर्ट करता है" जैसे गुणों को शामिल कर सकता है जो कर्मचारी जानकारी खोजने के लिए प्रासंगिक हो सकते हैं। + +**मिलान रणनीति**: +प्रश्न खंडों को एम्बेड करें +सीधे उल्लिखित ऑन्टोलॉजी अवधारणाओं को खोजें +उल्लिखित वर्गों को जोड़ने वाले गुणों को शामिल करें +पारगमन के लिए व्युत्क्रम और संबंधित गुणों को जोड़ें +पदानुक्रमित प्रश्नों के लिए मूल/चाइल्ड कक्षाओं को शामिल करें +प्रश्न-केंद्रित ऑन्टोलॉजी विभाजन बनाएं + +#### 3. बैकएंड राउटर + +**उद्देश्य**: कॉन्फ़िगरेशन के आधार पर प्रश्नों को उपयुक्त बैकएंड-विशिष्ट क्वेरी पथ पर रूट करता है। + +**एल्गोरिदम विवरण**: +बैकएंड राउटर यह निर्धारित करने के लिए सिस्टम कॉन्फ़िगरेशन की जांच करता है कि कौन सा ग्राफ बैकएंड सक्रिय है (कैसेंड्रा या साइफर-आधारित)। यह प्रश्न और ऑन्टोलॉजी विभाजन को उपयुक्त क्वेरी पीढ़ी सेवा पर रूट करता है। राउटर कई बैकएंड में लोड संतुलन का भी समर्थन कर सकता है या यदि प्राथमिक बैकएंड अनुपलब्ध है तो बैकअप तंत्र प्रदान कर सकता है। + +**राउटिंग तर्क**: +सिस्टम सेटिंग्स से कॉन्फ़िगर किए गए बैकएंड प्रकार की जांच करें +कैसेंड्रा बैकएंड के लिए `onto-query-sparql` पर रूट करें +Neo4j/Memgraph/FalkorDB के लिए `onto-query-cypher` पर रूट करें +क्वेरी वितरण के साथ मल्टी-बैकएंड कॉन्फ़िगरेशन का समर्थन करें +विफल-ओवर और लोड संतुलन परिदृश्यों को संभालें + +#### 4. SPARQL क्वेरी पीढ़ी (`onto-query-sparql`) + +**उद्देश्य**: कैसेंड्रा निष्पादन के लिए प्राकृतिक भाषा प्रश्नों को SPARQL प्रश्नों में परिवर्तित करता है। + +**एल्गोरिदम विवरण**: +SPARQL क्वेरी जनरेटर प्रश्न और ऑन्टोलॉजी विभाजन लेता है और कैसेंड्रा बैकएंड के खिलाफ निष्पादन के लिए अनुकूलित एक SPARQL क्वेरी बनाता है। यह RDF/OWL सिमेंटिक्स को शामिल करने वाले एक SPARQL-विशिष्ट टेम्पलेट के साथ प्रॉम्प्ट सेवा का उपयोग करता है। जनरेटर SPARQL पैटर्न को समझता है जैसे कि प्रॉपर्टी पथ, वैकल्पिक खंड और फ़िल्टर जो कैसेंड्रा ऑपरेशनों में कुशलता से अनुवाद कर सकते हैं। + +**SPARQL पीढ़ी प्रॉम्प्ट टेम्पलेट**: +``` +Generate a SPARQL query for the following question using the provided ontology. + +ONTOLOGY CLASSES: +{classes} + +ONTOLOGY PROPERTIES: +{properties} + +RULES: +- Use proper RDF/OWL semantics +- Include relevant prefixes +- Use property paths for hierarchical queries +- Add FILTER clauses for constraints +- Optimise for Cassandra backend + +QUESTION: {question} + +SPARQL QUERY: +``` + +#### 5. सिफर क्वेरी जनरेशन (`onto-query-cypher`) + +**उद्देश्य**: प्राकृतिक भाषा के प्रश्नों को ग्राफ डेटाबेस के लिए सिफर क्वेरी में परिवर्तित करता है। + +**एल्गोरिदम विवरण**: +सिफर क्वेरी जनरेटर, Neo4j, Memgraph और FalkorDB के लिए अनुकूलित मूल सिफर क्वेरी बनाता है। यह ऑन्टोलॉजी कक्षाओं को नोड लेबल और गुणों को संबंधों में मैप करता है, और सिफर के पैटर्न मिलान सिंटैक्स का उपयोग करता है। जनरेटर में सिफर-विशिष्ट अनुकूलन शामिल हैं, जैसे कि संबंध दिशा संकेत, इंडेक्स का उपयोग और क्वेरी प्लानिंग संकेत। + +**सिफर जनरेशन प्रॉम्प्ट टेम्पलेट**: +``` +Generate a Cypher query for the following question using the provided ontology. + +NODE LABELS (from classes): +{classes} + +RELATIONSHIP TYPES (from properties): +{properties} + +RULES: +- Use MATCH patterns for graph traversal +- Include WHERE clauses for filters +- Use aggregation functions when needed +- Optimise for graph database performance +- Consider index hints for large datasets + +QUESTION: {question} + +CYPHER QUERY: +``` + +#### 6. SPARQL-कैसेंड्रा क्वेरी इंजन (`sparql-cassandra`) + +**उद्देश्य**: यह पाइथन rdflib का उपयोग करके कैसेंड्रा के विरुद्ध SPARQL क्वेरी निष्पादित करता है। + +**एल्गोरिदम विवरण**: +SPARQL-कैसेंड्रा इंजन, पाइथन की rdflib लाइब्रेरी का उपयोग करके एक SPARQL प्रोसेसर को लागू करता है, जिसमें एक कस्टम कैसेंड्रा बैकएंड स्टोर होता है। यह SPARQL ग्राफ पैटर्न को उपयुक्त कैसेंड्रा CQL क्वेरी में अनुवाद करता है, जिसमें जॉइन, फ़िल्टर और एग्रीगेशन शामिल हैं। इंजन एक RDF-से-कैसेंड्रा मैपिंग बनाए रखता है जो सिमेंटिक संरचना को संरक्षित करता है, साथ ही कैसेंड्रा के कॉलम-फैमिली स्टोरेज मॉडल के लिए अनुकूलन करता है। + +**कार्यान्वयन विशेषताएं**: +कैसेंड्रा के लिए rdflib स्टोर इंटरफ़ेस कार्यान्वयन +सामान्य पैटर्न के साथ SPARQL 1.1 क्वेरी समर्थन +ट्रिपल पैटर्न का CQL में कुशल अनुवाद +प्रॉपर्टी पाथ और पदानुक्रमित क्वेरी के लिए समर्थन +बड़े डेटासेट के लिए परिणाम स्ट्रीमिंग +कनेक्शन पूलिंग और क्वेरी कैशिंग + +**उदाहरण अनुवाद**: +```sparql +SELECT ?animal WHERE { + ?animal rdf:type :Animal . + ?animal :hasOwner "John" . +} +``` +अनुकूलित कैसेंड्रा प्रश्नों का अनुवाद, जो इंडेक्स और विभाजन कुंजियों का उपयोग करते हैं। + +#### 7. साइफर क्वेरी एग्जीक्यूटर (`cypher-executor`) + +**उद्देश्य**: नियो4जे, मेमग्राफ और फाल्कोर्डबी के खिलाफ साइफर प्रश्नों को निष्पादित करता है। + +**एल्गोरिदम विवरण**: +साइफर एग्जीक्यूटर विभिन्न ग्राफ डेटाबेस में साइफर प्रश्नों को निष्पादित करने के लिए एक एकीकृत इंटरफ़ेस प्रदान करता है। यह डेटाबेस-विशिष्ट कनेक्शन प्रोटोकॉल, क्वेरी अनुकूलन संकेतों और परिणाम प्रारूप सामान्यीकरण को संभालता है। एग्जीक्यूटर में प्रत्येक डेटाबेस प्रकार के लिए उपयुक्त पुन: प्रयास तर्क, कनेक्शन पूलिंग और लेनदेन प्रबंधन शामिल हैं। + +**मल्टी-डेटाबेस समर्थन**: +**नियो4जे**: बोल्ट प्रोटोकॉल, लेनदेन फ़ंक्शन, इंडेक्स संकेत +**मेमग्राफ**: कस्टम प्रोटोकॉल, स्ट्रीमिंग परिणाम, विश्लेषणात्मक प्रश्न +**फाल्कोर्डबी**: रेडिस प्रोटोकॉल अनुकूलन, इन-मेमोरी अनुकूलन + +**निष्पादन विशेषताएं**: +डेटाबेस-अज्ञेय कनेक्शन प्रबंधन +क्वेरी सत्यापन और सिंटैक्स जांच +टाइमआउट और संसाधन सीमा प्रवर्तन +परिणाम पेजिंग और स्ट्रीमिंग +प्रत्येक डेटाबेस प्रकार के लिए प्रदर्शन निगरानी +डेटाबेस उदाहरणों के बीच स्वचालित फेलओवर + +#### 8. उत्तर जनरेटर + +**उद्देश्य**: क्वेरी परिणामों से एक प्राकृतिक भाषा उत्तर का संश्लेषण करता है। + +**एल्गोरिदम विवरण**: +उत्तर जनरेटर संरचित क्वेरी परिणामों और मूल प्रश्न को लेता है, और फिर एक व्यापक उत्तर उत्पन्न करने के लिए प्रॉम्प्ट सेवा का उपयोग करता है। साधारण टेम्पलेट-आधारित प्रतिक्रियाओं के विपरीत, यह ग्राफ डेटा को प्रश्न के संदर्भ में व्याख्या करने के लिए एक एलएलएम का उपयोग करता है, जटिल संबंधों, एग्रीगेशन और अनुमानों को संभालता है। जनरेटर ज्ञानकोश संरचना और ग्राफ से प्राप्त विशिष्ट ट्रिपल को संदर्भित करके अपनी तर्कसंगतता को समझा सकता है। + +**उत्तर पीढ़ी प्रक्रिया**: +क्वेरी परिणामों को संरचित संदर्भ में प्रारूपित करें +स्पष्टता के लिए प्रासंगिक ज्ञानकोश परिभाषाएँ शामिल करें +प्रश्न और परिणामों के साथ प्रॉम्प्ट बनाएं +एलएलएम के माध्यम से प्राकृतिक भाषा उत्तर उत्पन्न करें +क्वेरी इरादे के खिलाफ उत्तर को मान्य करें +यदि आवश्यक हो तो विशिष्ट ग्राफ संस्थाओं के लिए उद्धरण जोड़ें + +### मौजूदा सेवाओं के साथ एकीकरण + +#### ग्राफआरएजी के साथ संबंध + +**पूरक**: onto-query सिमेंटिक परिशुद्धता प्रदान करता है जबकि GraphRAG व्यापक कवरेज प्रदान करता है +**साझा बुनियादी ढांचा**: दोनों समान ज्ञानकोश और प्रॉम्प्ट सेवाओं का उपयोग करते हैं +**क्वेरी रूटिंग**: सिस्टम प्रश्न के प्रकार के आधार पर सबसे उपयुक्त सेवा में प्रश्नों को रूट कर सकता है +**हाइब्रिड मोड**: व्यापक उत्तरों के लिए दोनों दृष्टिकोणों को जोड़ सकता है + +#### ऑन्टोरैग निष्कर्षण के साथ संबंध + +**साझा ज्ञानकोश**: kg-extract-ontology द्वारा लोड किए गए समान ज्ञानकोश कॉन्फ़िगरेशन का उपयोग करता है +**साझा वेक्टर स्टोर**: निष्कर्षण सेवा से इन-मेमोरी एम्बेडिंग का पुन: उपयोग करता है +**संगत सिमेंटिक्स**: क्वेरी समान ऑन्टोलॉजिकल बाधाओं के साथ बनाए गए ग्राफ पर संचालित होती हैं + +### क्वेरी उदाहरण + +#### उदाहरण 1: साधारण इकाई क्वेरी +**प्रश्न**: "कौन से जानवर स्तनधारी हैं?" +**ज्ञानकोश मिलान**: [जानवर, स्तनधारी, उपवर्ग] +**उत्पन्न क्वेरी**: +```cypher +MATCH (a:animal)-[:subClassOf*]->(m:mammal) +RETURN a.name +``` + +#### उदाहरण 2: संबंध क्वेरी +**प्रश्न**: "जॉन स्मिथ द्वारा लिखित कौन से दस्तावेज़ हैं?" +**ऑन्टोलॉजी मिलान**: [दस्तावेज़, व्यक्ति, लेखक-है] +**उत्पन्न क्वेरी**: +```cypher +MATCH (d:document)-[:has-author]->(p:person {name: "John Smith"}) +RETURN d.title, d.date +``` + +#### उदाहरण 3: एकत्रीकरण क्वेरी +**प्रश्न**: "बिल्लियों के कितने पैर होते हैं?" +**ऑन्टोलॉजी मिलान**: [बिल्ली, पैरों की संख्या (डेटा प्रकार गुण)] +**उत्पन्न क्वेरी**: +```cypher +MATCH (c:cat) +RETURN c.name, c.number_of_legs +``` + +### कॉन्फ़िगरेशन + +```yaml +onto-query: + embedding_model: "text-embedding-3-small" + vector_store: + shared_with_extractor: true # Reuse kg-extract-ontology's store + query_builder: + model: "gpt-4" + temperature: 0.1 + max_query_length: 1000 + graph_executor: + timeout: 30000 # ms + max_results: 1000 + answer_generator: + model: "gpt-4" + temperature: 0.3 + max_tokens: 500 +``` + +### प्रदर्शन अनुकूलन + +#### क्वेरी अनुकूलन + +**ऑन्टोलॉजी छंटाई (Ontology Pruning)**: केवल आवश्यक ऑन्टोलॉजी तत्वों को प्रॉम्प्ट में शामिल करें। +**क्वेरी कैशिंग (Query Caching)**: बार-बार पूछे जाने वाले प्रश्नों और उनकी क्वेरी को कैश करें। +**परिणाम कैशिंग (Result Caching)**: समान प्रश्नों के लिए परिणामों को एक निश्चित समय अवधि के लिए संग्रहीत करें। +**बैच प्रोसेसिंग (Batch Processing)**: एक ही ग्राफ ट्रैवर्सल में कई संबंधित प्रश्नों को संभालें। + +#### स्केलेबिलिटी विचार + +**वितरित निष्पादन (Distributed Execution)**: उप-क्वेरी को ग्राफ विभाजनों में समानांतर करें। +**क्रमिक परिणाम (Incremental Results)**: बड़े डेटासेट के लिए परिणामों को स्ट्रीम करें। +**लोड बैलेंसिंग (Load Balancing)**: क्वेरी लोड को कई सेवा उदाहरणों में वितरित करें। +**संसाधन पूल (Resource Pools)**: ग्राफ डेटाबेस के लिए कनेक्शन पूल का प्रबंधन करें। + +### त्रुटि प्रबंधन + +#### विफलता परिदृश्य + +1. **अमान्य क्वेरी पीढ़ी (Invalid Query Generation)**: GraphRAG या सरल कीवर्ड खोज पर वापस जाएँ। +2. **ऑन्टोलॉजी बेमेल (Ontology Mismatch)**: व्यापक ऑन्टोलॉजी उपसमुच्चय में खोज का विस्तार करें। +3. **क्वेरी टाइमआउट (Query Timeout)**: क्वेरी को सरल बनाएं या टाइमआउट बढ़ाएं। +4. **खाली परिणाम (Empty Results)**: क्वेरी को फिर से तैयार करने या संबंधित प्रश्नों का सुझाव दें। +5. **एलएलएम सेवा विफलता (LLM Service Failure)**: कैश किए गए प्रश्नों या टेम्पलेट-आधारित प्रतिक्रियाओं का उपयोग करें। + +### निगरानी मेट्रिक्स + +प्रश्न जटिलता वितरण +ऑन्टोलॉजी विभाजन आकार +क्वेरी पीढ़ी सफलता दर +ग्राफ क्वेरी निष्पादन समय +उत्तर गुणवत्ता स्कोर +कैश हिट दर +त्रुटि आवृत्तियाँ (प्रकार द्वारा) + +## भविष्य के सुधार + +1. **ऑन्टोलॉजी सीखना (Ontology Learning)**: निष्कर्षण पैटर्न के आधार पर स्वचालित रूप से ऑन्टोलॉजी का विस्तार करें। +2. **आत्मविश्वास स्कोरिंग (Confidence Scoring)**: निकाले गए त्रिगुटों को आत्मविश्वास स्कोर असाइन करें। +3. **स्पष्टीकरण पीढ़ी (Explanation Generation)**: ट्रिपल निष्कर्षण के लिए तर्क प्रदान करें। +4. **सक्रिय शिक्षण (Active Learning)**: अनिश्चित निष्कर्षण के लिए मानव सत्यापन का अनुरोध करें। + +## सुरक्षा विचार + +1. **प्रॉम्प्ट इंजेक्शन रोकथाम (Prompt Injection Prevention)**: प्रॉम्प्ट निर्माण से पहले चंक टेक्स्ट को सैनिटाइज करें। +2. **संसाधन सीमाएँ (Resource Limits)**: वेक्टर स्टोर के लिए मेमोरी उपयोग को सीमित करें। +3. **दर सीमित करना (Rate Limiting)**: प्रति क्लाइंट निष्कर्षण अनुरोधों को सीमित करें। +4. **ऑडिट लॉगिंग (Audit Logging)**: सभी निष्कर्षण अनुरोधों और परिणामों को ट्रैक करें। + +## परीक्षण रणनीति + +### यूनिट परीक्षण + +विभिन्न प्रारूपों के साथ ऑन्टोलॉजी लोडर +एम्बेडिंग पीढ़ी और भंडारण +वाक्य विभाजन एल्गोरिदम +वेक्टर समानता गणना +ट्रिपल पार्सिंग और सत्यापन + +### एकीकरण परीक्षण + +एंड-टू-एंड निष्कर्षण पाइपलाइन +कॉन्फ़िगरेशन सेवा एकीकरण +प्रॉम्प्ट सेवा इंटरैक्शन +समवर्ती निष्कर्षण हैंडलिंग + +### प्रदर्शन परीक्षण + +बड़े ऑन्टोलॉजी हैंडलिंग (1000+ कक्षाएं) +उच्च-मात्रा चंक प्रसंस्करण +लोड के तहत मेमोरी उपयोग +विलंबता बेंचमार्क + +## वितरण योजना + +### अवलोकन + +OntoRAG सिस्टम को चार प्रमुख चरणों में वितरित किया जाएगा, जिसमें प्रत्येक चरण क्रमिक मूल्य प्रदान करेगा, जबकि पूर्ण सिस्टम की ओर निर्माण करेगा। योजना का ध्यान पहले मुख्य निष्कर्षण क्षमताओं को स्थापित करने पर है, फिर क्वेरी कार्यक्षमता जोड़ने, इसके बाद अनुकूलन और उन्नत सुविधाओं पर। + +### चरण 1: नींव और मुख्य निष्कर्षण + +**लक्ष्य**: सरल वेक्टर मिलान के साथ बुनियादी ऑन्टोलॉजी-संचालित निष्कर्षण पाइपलाइन स्थापित करें। + +#### चरण 1.1: ऑन्टोलॉजी प्रबंधन नींव +ऑन्टोलॉजी कॉन्फ़िगरेशन लोडर (`OntologyLoader`) लागू करें +ऑन्टोलॉजी JSON संरचनाओं को पार्स और मान्य करें +इन-मेमोरी ऑन्टोलॉजी भंडारण और एक्सेस पैटर्न बनाएं +ऑन्टोलॉजी रिफ्रेश तंत्र लागू करें + +**सफलता मानदंड**: +ऑन्टोलॉजी कॉन्फ़िगरेशन को सफलतापूर्वक लोड और पार्स करें +ऑन्टोलॉजी संरचना और स्थिरता को मान्य करें +कई समवर्ती ऑन्टोलॉजी को संभालें + +#### चरण 1.2: वेक्टर स्टोर कार्यान्वयन +प्रारंभिक प्रोटोटाइप के रूप में सरल NumPy-आधारित वेक्टर स्टोर लागू करें +FAISS वेक्टर स्टोर कार्यान्वयन जोड़ें +वेक्टर स्टोर इंटरफ़ेस एब्स्ट्रैक्शन बनाएं +कॉन्फ़िगर करने योग्य थ्रेसहोल्ड के साथ समानता खोज लागू करें + +**सफलता मानदंड**: +एम्बेडिंग को कुशलतापूर्वक स्टोर और पुनर्प्राप्त करें +<100ms विलंबता के साथ समानता खोज करें +NumPy और FAISS दोनों बैकएंड का समर्थन करें + +#### चरण 1.3: ऑन्टोलॉजी एम्बेडिंग पाइपलाइन +एम्बेडिंग सेवा के साथ एकीकृत करें +`OntologyEmbedder` घटक को लागू करें +सभी ऑन्टोलॉजी तत्वों के लिए एम्बेडिंग उत्पन्न करें +वेक्टर स्टोर में मेटाडेटा के साथ एम्बेडिंग स्टोर करें + +**सफलता मानदंड**: +कक्षाओं और गुणों के लिए एम्बेडिंग उत्पन्न करें +उचित मेटाडेटा के साथ एम्बेडिंग स्टोर करें +ऑन्टोलॉजी अपडेट पर एम्बेडिंग को फिर से बनाएं + +#### चरण 1.4: टेक्स्ट प्रोसेसिंग घटक +NLTK/spaCy का उपयोग करके वाक्य विभाजक को लागू करें +वाक्यांश और नामित संस्थाएं निकालें +टेक्स्ट सेगमेंट पदानुक्रम बनाएं +टेक्स्ट सेगमेंट के लिए एम्बेडिंग उत्पन्न करें + +**सफलता मानदंड**: +पाठ को सटीक रूप से वाक्यों में विभाजित करें +सार्थक वाक्यांश निकालें +संदर्भ संबंधों को बनाए रखें + +#### चरण 1.5: ऑन्टोलॉजी चयन एल्गोरिदम +पाठ और ऑन्टोलॉजी के बीच समानता मिलान को लागू करें +ऑन्टोलॉजी तत्वों के लिए निर्भरता रिज़ॉल्यूशन बनाएं +न्यूनतम सुसंगत ऑन्टोलॉजी उपसमुच्चय बनाएं +उपसमुच्चय पीढ़ी प्रदर्शन को अनुकूलित करें + +**सफलता मानदंड**: +>80% परिशुद्धता के साथ प्रासंगिक ऑन्टोलॉजी तत्वों का चयन करें +सभी आवश्यक निर्भरताओं को शामिल करें +<500ms में उपसमुच्चय उत्पन्न करें + +#### चरण 1.6: बुनियादी निष्कर्षण सेवा +निष्कर्षण के लिए प्रॉम्प्ट निर्माण को लागू करें +प्रॉम्प्ट सेवा के साथ एकीकृत करें +ट्रिपल प्रतिक्रियाओं को पार्स और मान्य करें +`kg-extract-ontology` सेवा एंडपॉइंट बनाएं + +**सफलता मानदंड**: +ऑन्टोलॉजी-अनुरूप ट्रिपल निकालें +सभी ट्रिपल को ऑन्टोलॉजी के विरुद्ध मान्य करें +निष्कर्षण त्रुटियों को सुचारू रूप से संभालें + +### चरण 2: क्वेरी सिस्टम कार्यान्वयन + +**लक्ष्य**: कई बैकएंड के लिए समर्थन के साथ ऑन्टोलॉजी-जागरूक क्वेरी क्षमताओं को जोड़ें। + +#### चरण 2.1: क्वेरी फाउंडेशन घटक +प्रश्न विश्लेषक को लागू करें +प्रश्नों के लिए ऑन्टोलॉजी मिलान बनाएं +क्वेरी संदर्भ के लिए वेक्टर खोज को अनुकूलित करें +बैकएंड राउटर घटक बनाएं + +**सफलता मानदंड**: +प्रश्नों का विश्लेषण करके सिमेंटिक घटकों में बदलें +प्रश्नों का मिलान प्रासंगिक ऑन्टोलॉजी तत्वों से करें +प्रश्नों को उपयुक्त बैकएंड पर रूट करें + +#### चरण 2.2: SPARQL पथ कार्यान्वयन +`onto-query-sparql` सेवा लागू करें +LLM का उपयोग करके SPARQL क्वेरी जनरेटर बनाएं +SPARQL पीढ़ी के लिए प्रॉम्प्ट टेम्पलेट विकसित करें +उत्पन्न SPARQL सिंटैक्स को मान्य करें + +**सफलता मानदंड**: +मान्य SPARQL क्वेरी उत्पन्न करें +उपयुक्त SPARQL पैटर्न का उपयोग करें +जटिल क्वेरी प्रकारों को संभालें + +#### चरण 2.3: SPARQL-Cassandra इंजन +Cassandra के लिए rdflib Store इंटरफ़ेस लागू करें +CQL क्वेरी ट्रांसलेटर बनाएं +ट्रिपल पैटर्न मिलान को अनुकूलित करें +SPARQL परिणाम स्वरूपण को संभालें + +**सफलता मानदंड**: +Cassandra पर SPARQL क्वेरी निष्पादित करें +सामान्य SPARQL पैटर्न का समर्थन करें +परिणामों को मानक प्रारूप में लौटाएं + +#### चरण 2.4: Cypher पथ कार्यान्वयन +`onto-query-cypher` सेवा लागू करें +LLM का उपयोग करके Cypher क्वेरी जनरेटर बनाएं +Cypher पीढ़ी के लिए प्रॉम्प्ट टेम्पलेट विकसित करें +उत्पन्न Cypher सिंटैक्स को मान्य करें + +**सफलता मानदंड**: +मान्य Cypher क्वेरी उत्पन्न करें +उपयुक्त ग्राफ पैटर्न का उपयोग करें +Neo4j, Memgraph, FalkorDB का समर्थन करें + +#### चरण 2.5: Cypher निष्पादक +मल्टी-डेटाबेस साइफर एग्जीक्यूटर को लागू करें +बॉल्ट प्रोटोकॉल (Neo4j/Memgraph) का समर्थन करें +रेडिस प्रोटोकॉल (FalkorDB) का समर्थन करें +परिणाम सामान्यीकरण को संभालें + +**सफलता मानदंड**: +सभी लक्षित डेटाबेस पर साइफर को निष्पादित करें +डेटाबेस-विशिष्ट अंतरों को संभालें +कनेक्शन पूल को कुशलतापूर्वक बनाए रखें + +#### चरण 2.6: उत्तर पीढ़ी +उत्तर जनरेटर घटक को लागू करें +उत्तर संश्लेषण के लिए संकेत बनाएं +एलएलएम (LLM) के उपयोग के लिए क्वेरी परिणामों को प्रारूपित करें +प्राकृतिक भाषा में उत्तर उत्पन्न करें + +**सफलता मानदंड**: +क्वेरी परिणामों से सटीक उत्तर उत्पन्न करें +मूल प्रश्न से संदर्भ बनाए रखें +स्पष्ट, संक्षिप्त प्रतिक्रियाएं प्रदान करें + +### चरण 3: अनुकूलन और मजबूती + +**लक्ष्य**: प्रदर्शन को अनुकूलित करें, कैशिंग जोड़ें, त्रुटि प्रबंधन में सुधार करें और विश्वसनीयता बढ़ाएं। + +#### चरण 3.1: प्रदर्शन अनुकूलन +एम्बेडिंग कैशिंग को लागू करें +क्वेरी परिणाम कैशिंग जोड़ें +FAISS IVF इंडेक्स के साथ वेक्टर खोज को अनुकूलित करें +एम्बेडिंग के लिए बैच प्रोसेसिंग को लागू करें + +**सफलता मानदंड**: +औसत क्वेरी विलंबता को 50% तक कम करें +10 गुना अधिक समवर्ती अनुरोधों का समर्थन करें +उप-सेकंड प्रतिक्रिया समय बनाए रखें + +#### चरण 3.2: उन्नत त्रुटि प्रबंधन +व्यापक त्रुटि रिकवरी को लागू करें +क्वेरी पथों के बीच फॉलबैक तंत्र जोड़ें +घातीय बैकऑफ़ के साथ रीट्राय लॉजिक बनाएं +त्रुटि लॉगिंग और निदान में सुधार करें + +**सफलता मानदंड**: +सभी विफलता परिदृश्यों को सुचारू रूप से संभालें +बैकएंड के बीच स्वचालित फेलओवर +डिबगिंग के लिए विस्तृत त्रुटि रिपोर्टिंग + +#### चरण 3.3: निगरानी और अवलोकनशीलता +प्रदर्शन मेट्रिक्स संग्रह जोड़ें +क्वेरी ट्रेसिंग को लागू करें +स्वास्थ्य जांच एंडपॉइंट बनाएं +संसाधन उपयोग निगरानी जोड़ें + +**सफलता मानदंड**: +सभी प्रमुख प्रदर्शन संकेतकों को ट्रैक करें +बाधाओं की पहचान जल्दी करें +सिस्टम स्वास्थ्य की वास्तविक समय में निगरानी करें + +#### चरण 3.4: कॉन्फ़िगरेशन प्रबंधन +गतिशील कॉन्फ़िगरेशन अपडेट को लागू करें +कॉन्फ़िगरेशन सत्यापन जोड़ें +कॉन्फ़िगरेशन टेम्प्लेट बनाएं +पर्यावरण-विशिष्ट सेटिंग्स का समर्थन करें + +**सफलता मानदंड**: +पुनरारंभ किए बिना कॉन्फ़िगरेशन अपडेट करें +सभी कॉन्फ़िगरेशन परिवर्तनों को मान्य करें +कई परिनियोजन वातावरण का समर्थन करें + +### चरण 4: उन्नत सुविधाएँ + +**लक्ष्य**: उत्पादन परिनियोजन और बेहतर कार्यक्षमता के लिए परिष्कृत क्षमताएं जोड़ें। + +#### चरण 4.1: मल्टी-ऑन्टोलॉजी समर्थन +ऑन्टोलॉजी चयन तर्क को लागू करें +क्रॉस-ऑन्टोलॉजी क्वेरी का समर्थन करें +ऑन्टोलॉजी संस्करण नियंत्रण को संभालें +ऑन्टोलॉजी मर्ज क्षमताएं बनाएं + +**सफलता मानदंड**: +कई ऑन्टोलॉजी पर क्वेरी करें +ऑन्टोलॉजी संघर्षों को संभालें +ऑन्टोलॉजी विकास का समर्थन करें + +#### चरण 4.2: इंटेलिजेंट क्वेरी रूटिंग +प्रदर्शन-आधारित रूटिंग को लागू करें +क्वेरी जटिलता विश्लेषण जोड़ें +अनुकूली रूटिंग एल्गोरिदम बनाएं +रास्तों के लिए A/B परीक्षण का समर्थन करें + +**सफलता मानदंड**: +क्वेरी को इष्टतम रूप से रूट करें +क्वेरी प्रदर्शन से सीखें +समय के साथ रूटिंग में सुधार करें + +#### चरण 4.3: उन्नत निष्कर्षण विशेषताएं +त्रिपुंजों के लिए आत्मविश्वास स्कोरिंग जोड़ें +स्पष्टीकरण पीढ़ी को लागू करें +सुधार के लिए प्रतिक्रिया लूप बनाएं +वृद्धिशील सीखने का समर्थन करें + +**सफलता मानदंड**: +आत्मविश्वास स्कोर प्रदान करें +निष्कर्षण निर्णयों की व्याख्या करें +सटीकता में लगातार सुधार करें + +#### चरण 4.4: उत्पादन कठोरता +दर सीमित करना जोड़ें +प्रमाणीकरण/प्राधिकरण लागू करें +परिनियोजन स्वचालन बनाएं +बैकअप और रिकवरी जोड़ें + +**सफलता मानदंड**: +उत्पादन-तैयार सुरक्षा +स्वचालित परिनियोजन पाइपलाइन +आपदा रिकवरी क्षमता + +### वितरण मील के पत्थर + +1. **मील का पत्थर 1** (चरण 1 का अंत): बुनियादी ऑन्टोलॉजी-संचालित निष्कर्षण परिचालन +2. **मील का पत्थर 2** (चरण 2 का अंत): SPARQL और Cypher दोनों पथों के साथ पूर्ण क्वेरी सिस्टम +3. **मील का पत्थर 3** (चरण 3 का अंत): अनुकूलित, मजबूत सिस्टम जो स्टेजिंग के लिए तैयार है +4. **मील का पत्थर 4** (चरण 4 का अंत): उन्नत सुविधाओं के साथ उत्पादन-तैयार सिस्टम + +### जोखिम शमन + +#### तकनीकी जोखिम +**वेक्टर स्टोर स्केलेबिलिटी**: NumPy के साथ शुरू करें, धीरे-धीरे FAISS में माइग्रेट करें +**क्वेरी पीढ़ी सटीकता**: सत्यापन और बैकअप तंत्र लागू करें +**बैकएंड संगतता**: प्रत्येक डेटाबेस प्रकार के साथ व्यापक रूप से परीक्षण करें +**प्रदर्शन बाधाएं**: जल्दी और अक्सर प्रोफाइल करें, पुनरावृत्त रूप से अनुकूलित करें + +#### परिचालन जोखिम +**ऑन्टोलॉजी गुणवत्ता**: सत्यापन और स्थिरता जांच लागू करें +**सेवा निर्भरताएँ**: सर्किट ब्रेकर और बैकअप जोड़ें +**संसाधन बाधाएँ**: मॉनिटर करें और उचित सीमाएँ निर्धारित करें +**डेटा स्थिरता**: उचित लेनदेन हैंडलिंग लागू करें + +### सफलता मेट्रिक्स + +#### चरण 1 सफलता मेट्रिक्स +निष्कर्षण सटीकता: >90% ऑन्टोलॉजी अनुरूपता +प्रसंस्करण गति: <1 सेकंड प्रति टुकड़ा +ऑन्टोलॉजी लोड समय: <10 सेकंड +वेक्टर खोज विलंबता: <100ms + +#### चरण 2 सफलता मेट्रिक्स +क्वेरी सफलता दर: >95% +क्वेरी विलंबता: <2 सेकंड एंड-टू-एंड +बैकएंड संगतता: लक्षित डेटाबेस के लिए 100% +उत्तर सटीकता: उपलब्ध डेटा के आधार पर >85% + +#### चरण 3 सफलता मेट्रिक्स +सिस्टम अपटाइम: >99.9% +त्रुटि रिकवरी दर: >95% +कैश हिट दर: >60% +समवर्ती उपयोगकर्ता: >100 + +#### चरण 4 सफलता मेट्रिक्स +मल्टी-ऑन्टोलॉजी क्वेरी: पूरी तरह से समर्थित +रूटिंग अनुकूलन: 30% विलंबता में कमी +आत्मविश्वास स्कोरिंग सटीकता: >90% +उत्पादन परिनियोजन: शून्य-डाउनटाइम अपडेट + +## संदर्भ + +[OWL 2 वेब ऑन्टोलॉजी भाषा](https://www.w3.org/TR/owl2-overview/) +[GraphRAG आर्किटेक्चर](https://github.com/microsoft/graphrag) +[वाक्य ट्रांसफॉर्मर](https://www.sbert.net/) +[FAISS वेक्टर खोज](https://github.com/facebookresearch/faiss) +[spaCy एनएलपी लाइब्रेरी](https://spacy.io/) +[rdflib प्रलेखन](https://rdflib.readthedocs.io/) +[Neo4j बोल्ट प्रोटोकॉल](https://neo4j.com/docs/bolt/current/) diff --git a/docs/tech-specs/ontorag.pt.md b/docs/tech-specs/ontorag.pt.md new file mode 100644 index 00000000..eaa6854d --- /dev/null +++ b/docs/tech-specs/ontorag.pt.md @@ -0,0 +1,1067 @@ +# OntoRAG: Especificação Técnica de Extração e Consulta de Conhecimento Baseada em Ontologia + +## Visão Geral + +OntoRAG é um sistema de extração e consulta de conhecimento orientado por ontologia que impõe uma consistência semântica rigorosa durante a extração de triplas de conhecimento de texto não estruturado e durante a consulta do grafo de conhecimento resultante. Semelhante ao GraphRAG, mas com restrições de ontologia formais, o OntoRAG garante que todas as triplas extraídas estejam em conformidade com estruturas ontológicas predefinidas e fornece recursos de consulta com consciência semântica. + +O sistema usa correspondência de similaridade vetorial para selecionar dinamicamente subconjuntos de ontologia relevantes para operações de extração e consulta, permitindo um processamento focado e contextualmente apropriado, mantendo a validade semântica. + +**Nome do Serviço**: `kg-extract-ontology` + +## Objetivos + +**Extração Conforme à Ontologia**: Garantir que todas as triplas extraídas estejam estritamente em conformidade com as ontologias carregadas. +**Seleção de Contexto Dinâmico**: Usar incorporações para selecionar subconjuntos de ontologia relevantes para cada trecho. +**Consistência Semântica**: Manter hierarquias de classes, domínios/intervalos de propriedades e restrições. +**Processamento Eficiente**: Usar armazenamentos vetoriais em memória para correspondência rápida de elementos de ontologia. +**Arquitetura Escalável**: Suportar múltiplas ontologias concorrentes com diferentes domínios. + +## Contexto + +Os serviços atuais de extração de conhecimento (`kg-extract-definitions`, `kg-extract-relationships`) operam sem restrições formais, potencialmente produzindo triplas inconsistentes ou incompatíveis. O OntoRAG aborda isso através de: + +1. Carregamento de ontologias formais que definem classes e propriedades válidas. +2. Uso de incorporações para corresponder o conteúdo do texto com elementos de ontologia relevantes. +3. Restringir a extração para produzir apenas triplas conformes à ontologia. +4. Fornecer validação semântica do conhecimento extraído. + +Essa abordagem combina a flexibilidade da extração neural com a precisão da representação formal do conhecimento. + +## Design Técnico + +### Arquitetura + +O sistema OntoRAG consiste nos seguintes componentes: + +``` +┌─────────────────┐ +│ Configuration │ +│ Service │ +└────────┬────────┘ + │ Ontologies + ▼ +┌─────────────────┐ ┌──────────────┐ +│ kg-extract- │────▶│ Embedding │ +│ ontology │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ │ + ▼ ▼ +┌─────────────────┐ ┌──────────────┐ +│ In-Memory │◀────│ Ontology │ +│ Vector Store │ │ Embedder │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Sentence │────▶│ Chunker │ +│ Splitter │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Ontology │────▶│ Vector │ +│ Selector │ │ Search │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Prompt │────▶│ Prompt │ +│ Constructor │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ +│ Triple Output │ +└─────────────────┘ +``` + +### Detalhes do Componente + +#### 1. Carregador de Ontologia + +**Propósito**: Recupera e analisa configurações de ontologia do serviço de configuração usando atualizações orientadas a eventos. + +**Implementação**: +O Carregador de Ontologia usa a fila ConfigPush da TrustGraph para receber atualizações orientadas a eventos de configuração de ontologia. Quando um elemento de configuração do tipo "ontologia" é adicionado ou modificado, o carregador recebe a atualização através da fila config-update e analisa a estrutura JSON contendo metadados, classes, propriedades de objeto e propriedades de tipo de dados. Essas ontologias analisadas são armazenadas na memória como objetos estruturados que podem ser acessados de forma eficiente durante o processo de extração. + +**Operações Chave**: +Assinar a fila config-update para configurações do tipo ontologia +Analisar estruturas JSON de ontologia em objetos OntologyClass e OntologyProperty +Validar a estrutura e a consistência da ontologia +Armazenar em cache as ontologias analisadas na memória para acesso rápido +Lidar com o processamento por fluxo com armazenamentos de vetores específicos do fluxo + +**Localização da Implementação**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_loader.py` + +#### 2. Incorporador de Ontologia + +**Propósito**: Cria incorporações vetoriais para todos os elementos da ontologia para permitir a correspondência de similaridade semântica. + +**Implementação**: +O Incorporador de Ontologia processa cada elemento nas ontologias carregadas (classes, propriedades de objeto e propriedades de tipo de dados) e gera incorporações vetoriais usando o serviço EmbeddingsClientSpec. Para cada elemento, ele combina o identificador do elemento, os rótulos e a descrição (comentário) para criar uma representação de texto. Este texto é então convertido em uma incorporação vetorial de alta dimensão que captura seu significado semântico. Essas incorporações são armazenadas em um armazenamento de vetores FAISS na memória, específico para cada fluxo, juntamente com metadados sobre o tipo de elemento, a ontologia de origem e a definição completa. O incorporador detecta automaticamente a dimensão da incorporação a partir da primeira resposta de incorporação. + +**Operações Chave**: +Criar representações de texto a partir de IDs de elementos, rótulos e comentários +Gerar incorporações via EmbeddingsClientSpec (usando asyncio.gather para processamento em lote) +Armazenar incorporações com metadados abrangentes no armazenamento de vetores FAISS +Indexar por ontologia, tipo de elemento e ID de elemento para recuperação eficiente +Detectar automaticamente as dimensões da incorporação para a inicialização do armazenamento de vetores +Lidar com modelos de incorporação específicos do fluxo com armazenamentos de vetores independentes + +**Localização da Implementação**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_embedder.py` + +#### 3. Processador de Texto (Divisor de Sentenças) + +**Propósito**: Decompõe blocos de texto em segmentos granulares para correspondência precisa de ontologia. + +**Implementação**: +O Processador de Texto usa NLTK para tokenização de sentenças e marcação POS para dividir os blocos de texto recebidos em sentenças. Ele lida com a compatibilidade de versão do NLTK tentando baixar `punkt_tab` e `averaged_perceptron_tagger_eng`, com fallback para versões mais antigas, se necessário. Cada bloco de texto é dividido em sentenças individuais que podem ser correspondidas independentemente com elementos de ontologia. + +**Operações Chave**: +Dividir o texto em sentenças usando a tokenização de sentenças do NLTK +Lidar com a compatibilidade de versão do NLTK (punkt_tab vs punkt) +Criar objetos TextSegment com texto e informações de posição +Suportar tanto sentenças completas quanto blocos individuais + +**Localização da Implementação**: `trustgraph-flow/trustgraph/extract/kg/ontology/text_processor.py` + +#### 4. Selecionador de Ontologia + +**Propósito**: Identifica o subconjunto mais relevante de elementos de ontologia para o bloco de texto atual. + +**Implementação**: +O Selecionador de Ontologia realiza a correspondência semântica entre segmentos de texto e elementos de ontologia usando a pesquisa de similaridade vetorial FAISS. Para cada sentença do bloco de texto, ele gera uma incorporação e pesquisa o armazenamento de vetores pelos elementos de ontologia mais semelhantes usando a similaridade de cossenos com um limite configurável (padrão 0,3). Após coletar todos os elementos relevantes, ele realiza a resolução de dependências abrangente: se uma classe é selecionada, suas classes pai são incluídas; se uma propriedade é selecionada, suas classes de domínio e intervalo são adicionadas. Além disso, para cada classe selecionada, ele inclui automaticamente **todas as propriedades que referenciam essa classe** em seu domínio ou intervalo. Isso garante que a extração tenha acesso a todas as propriedades relevantes. + +**Operações Chave**: +Gerar incorporações para cada segmento de texto (frases) +Realizar busca de vizinhos mais próximos em k no armazenamento vetorial FAISS (top_k=10, threshold=0.3) +Aplicar um limite de similaridade para filtrar correspondências fracas +Resolver dependências (classes pai, domínios, intervalos) +**Incluir automaticamente todas as propriedades relacionadas às classes selecionadas** (correspondência de domínio/intervalo) +Construir um subconjunto de ontologia coerente com todos os relacionamentos necessários +Eliminar elementos duplicados que aparecem várias vezes + +**Localização da Implementação**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_selector.py` + +#### 5. Construção do Prompt + +**Propósito**: Cria prompts estruturados que orientam o LLM a extrair apenas triplas conformes à ontologia. + +**Implementação**: +O serviço de extração usa um modelo Jinja2 carregado de `ontology-prompt.md` que formata o subconjunto da ontologia e o texto para a extração do LLM. O modelo itera dinamicamente sobre classes, propriedades de objeto e propriedades de tipo de dados usando a sintaxe Jinja2, apresentando cada uma com suas descrições, domínios, intervalos e relacionamentos hierárquicos. O prompt inclui regras estritas sobre o uso apenas dos elementos da ontologia fornecidos e solicita um formato de saída JSON para análise consistente. + +**Operações Chave**: +Usar modelo Jinja2 com loops sobre elementos da ontologia +Formatar classes com relacionamentos pai (subclass_of) e comentários +Formatar propriedades com restrições de domínio/intervalo e comentários +Incluir regras de extração explícitas e requisitos de formato de saída +Chamar o serviço de prompt com o ID do modelo "extract-with-ontologies" + +**Localização do Modelo**: `ontology-prompt.md` +**Localização da Implementação**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` (método build_extraction_variables) + +#### 6. Serviço Principal de Extração + +**Propósito**: Coordena todos os componentes para realizar a extração de triplas baseada em ontologia de ponta a ponta. + +**Implementação**: +O Serviço Principal de Extração (KgExtractOntology) é a camada de orquestração que gerencia todo o fluxo de trabalho de extração. Ele usa o padrão FlowProcessor da TrustGraph com inicialização de componentes específica para cada fluxo. Quando uma atualização de configuração da ontologia é recebida, ele inicializa ou atualiza os componentes específicos do fluxo (carregador de ontologia, incorporador, processador de texto, selecionador). Quando um trecho de texto chega para processamento, ele coordena o pipeline: dividindo o texto em segmentos, encontrando elementos de ontologia relevantes por meio de busca vetorial, construindo um prompt restrito, chamando o serviço de prompt, analisando e validando a resposta, gerando triplas de definição de ontologia e emitindo tanto triplas de conteúdo quanto contextos de entidade. + +**Pipeline de Extração**: +1. Receber trecho de texto via fila chunks-input +2. Inicializar componentes do fluxo, se necessário (na primeira execução ou atualização de configuração) +3. Dividir o texto em frases usando NLTK +4. Pesquisar no armazenamento vetorial FAISS para encontrar conceitos de ontologia relevantes +5. Construir subconjunto de ontologia com inclusão automática de propriedades +6. Construir variáveis de prompt com modelo Jinja2 +7. Chamar o serviço de prompt com o modelo extract-with-ontologies +8. Analisar a resposta JSON em triplas estruturadas +9. Validar as triplas e expandir os URIs para URIs completos da ontologia +10. Gerar triplas de definição de ontologia (classes e propriedades com rótulos/comentários/domínios/intervalos) +11. Construir contextos de entidade a partir de todas as triplas +12. Emitir para as filas de triplas e contextos de entidade + +**Características Principais**: +Armazenamentos vetoriais específicos para cada fluxo, suportando diferentes modelos de incorporação +Atualizações de ontologia orientadas por eventos via fila config-update +Expansão automática de URIs usando URIs de ontologia +Elementos de ontologia adicionados ao grafo de conhecimento com metadados completos +Contextos de entidade incluem elementos de conteúdo e de ontologia + +**Localização da Implementação**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` + +### Configuração + +O serviço usa a abordagem de configuração padrão da TrustGraph com argumentos de linha de comando: + +```bash +kg-extract-ontology \ + --id kg-extract-ontology \ + --pulsar-host localhost:6650 \ + --input-queue chunks \ + --config-input-queue config-update \ + --output-queue triples \ + --entity-contexts-output-queue entity-contexts +``` + +**Parâmetros de Configuração Chave**: +`similarity_threshold`: 0.3 (padrão, configurável no código) +`top_k`: 10 (número de elementos de ontologia a serem recuperados por segmento) +`vector_store`: Per-flow FAISS IndexFlatIP com dimensões detectadas automaticamente +`text_processor`: NLTK com tokenização de frases punkt_tab +`prompt_template`: "extract-with-ontologies" (template Jinja2) + +**Configuração da Ontologia**: +As ontologias são carregadas dinamicamente através da fila de atualização de configuração com o tipo "ontology". + +### Fluxo de Dados + +1. **Fase de Inicialização** (por fluxo): + Receber configuração da ontologia através da fila de atualização de configuração + Analisar o JSON da ontologia em objetos OntologyClass e OntologyProperty + Gerar embeddings para todos os elementos da ontologia usando EmbeddingsClientSpec + Armazenar embeddings no armazenamento vetorial FAISS específico do fluxo + Detectar automaticamente as dimensões do embedding a partir da primeira resposta + +2. **Fase de Extração** (por chunk): + Receber um chunk da fila chunks-input + Dividir o chunk em frases usando NLTK + Calcular embeddings para cada frase + Pesquisar no armazenamento vetorial FAISS por elementos de ontologia relevantes + Construir um subconjunto de ontologia com inclusão automática de propriedades + Construir variáveis de template Jinja2 com texto e ontologia + Chamar o serviço de prompt com o template extract-with-ontologies + Analisar a resposta JSON e validar as triplas + Expandir URIs usando URIs da ontologia + Gerar triplas de definição de ontologia + Construir contextos de entidade a partir de todas as triplas + Emitir para as filas de triplas e entity-contexts + +### Armazenamento Vetorial em Memória + +**Propósito**: Fornece uma pesquisa de similaridade rápida e baseada em memória para correspondência de elementos de ontologia. + +**Implementação: FAISS** + +O sistema usa **FAISS (Facebook AI Similarity Search)** com IndexFlatIP para pesquisa de similaridade de cosseno exata. Características principais: + +**IndexFlatIP**: Pesquisa de similaridade de cosseno exata usando produto interno +**Detecção automática**: Dimensão determinada a partir da primeira resposta de embedding +**Armazenamentos per-flow**: Cada fluxo tem um armazenamento vetorial independente para diferentes modelos de embedding +**Normalização**: Todos os vetores normalizados antes da indexação +**Operações em lote**: Adição em lote eficiente para o carregamento inicial da ontologia + +**Localização da Implementação**: `trustgraph-flow/trustgraph/extract/kg/ontology/vector_store.py` + +### Algoritmo de Seleção de Subconjunto de Ontologia + +**Propósito**: Seleciona dinamicamente a porção relevante mínima da ontologia para cada chunk de texto. + +**Etapas Detalhadas do Algoritmo**: + +1. **Segmentação de Texto**: + Dividir o chunk de entrada em frases usando detecção de frases NLP + Extrair frases nominais, frases verbais e entidades nomeadas de cada frase + Criar uma estrutura hierárquica de segmentos preservando o contexto + +2. **Geração de Embedding**: + Gerar embeddings vetoriais para cada segmento de texto (frases e frases) + Usar o mesmo modelo de embedding usado para elementos de ontologia + Armazenar em cache os embeddings para segmentos repetidos para melhorar o desempenho + +3. **Pesquisa de Similaridade**: + Para cada embedding de segmento de texto, pesquisar no armazenamento vetorial + Recuperar os k (por exemplo, 10) elementos de ontologia mais similares + Aplicar um limite de similaridade (por exemplo, 0,7) para filtrar correspondências fracas + Agregar os resultados em todos os segmentos, rastreando as frequências de correspondência + +4. **Resolução de Dependências**: + Para cada classe selecionada, incluir recursivamente todas as classes pai até a raiz + Para cada propriedade selecionada, incluir suas classes de domínio e intervalo + Para propriedades inversas, garantir que ambas as direções sejam incluídas + Adicionar classes equivalentes se existirem na ontologia + +5. **Construção de Subconjunto**: + Desduplicar os elementos coletados, preservando os relacionamentos + Organizar em classes, propriedades de objeto e propriedades de tipo de dados + Garantir que todas as restrições e relacionamentos sejam preservados + Criar uma mini-ontologia autocontida que seja válida e completa + +**Exemplo de Demonstração**: +Dado o texto: "The brown dog chased the white cat up the tree." +Segmentos: ["brown dog", "white cat", "tree", "chased"] +Elementos correspondidos: [dog (class), cat (class), animal (parent), chases (property)] +Dependências: [animal (parent of dog and cat), lifeform (parent of animal)] +Subconjunto final: Mini-ontologia completa com hierarquia animal e relação de perseguição + +### Validação de Triplas + +**Propósito**: Garante que todas as triplas extraídas estejam estritamente em conformidade com as restrições da ontologia. + +**Algoritmo de Validação**: +Após a última linha traduzida, insira uma linha final contendo exatamente: [[__END_OF_TRANSLATION__]] +1. **Validação de Classe**: + Verificar se os sujeitos são instâncias de classes definidas no subconjunto da ontologia + Para propriedades de objeto, verificar se os objetos também são instâncias de classes válidas + Verificar os nomes das classes em relação ao dicionário de classes da ontologia + Lidar com hierarquias de classes - instâncias de subclasses são válidas para restrições da classe pai + +2. **Validação de Propriedade**: + Confirmar se os predicados correspondem a propriedades no subconjunto da ontologia + Distinguir entre propriedades de objeto (entidade-para-entidade) e propriedades de tipo de dado (entidade-para-literal) + Verificar se os nomes das propriedades correspondem exatamente (considerando o namespace, se presente) + +3. **Verificação de Domínio/Intervalo**: + Para cada propriedade usada como predicado, recuperar seu domínio e intervalo + Verificar se o tipo do sujeito corresponde ou herda do domínio da propriedade + Verificar se o tipo do objeto corresponde ou herda do intervalo da propriedade + Para propriedades de tipo de dado, verificar se o objeto é um literal do tipo XSD correto + +4. **Validação de Cardinalidade**: + Monitorar a contagem de uso da propriedade por sujeito + Verificar a cardinalidade mínima - garantir que as propriedades obrigatórias estejam presentes + Verificar a cardinalidade máxima - garantir que a propriedade não seja usada muitas vezes + Para propriedades funcionais, garantir que haja no máximo um valor por sujeito + +5. **Validação de Tipo de Dado**: + Analisar os valores literais de acordo com seus tipos XSD declarados + Validar se os inteiros são números válidos, se as datas estão formatadas corretamente, etc. + Verificar padrões de string se restrições de regex forem definidas + Garantir que os URIs sejam bem formados para tipos xsd:anyURI + +**Exemplo de Validação**: +Tripla: ("Buddy", "has-owner", "John") +Verificar se "Buddy" é tipado como uma classe que pode ter a propriedade "has-owner" +Verificar se "has-owner" existe na ontologia +Verificar a restrição de domínio: o sujeito deve ser do tipo "Pet" ou subclasse +Verificar a restrição de intervalo: o objeto deve ser do tipo "Person" ou subclasse +Se válido, adicionar à saída; se inválido, registrar a violação e pular + +## Considerações de Desempenho + +### Estratégias de Otimização + +1. **Cache de Incorporações**: Armazenar em cache as incorporações para segmentos de texto frequentemente usados +2. **Processamento em Lote**: Processar vários segmentos em paralelo +3. **Indexação de Armazenamento Vetorial**: Usar algoritmos de vizinhos mais próximos aproximados para ontologias grandes +4. **Otimização de Prompt**: Minimizar o tamanho do prompt incluindo apenas os elementos essenciais da ontologia +5. **Cache de Resultados**: Armazenar em cache os resultados da extração para trechos idênticos + +### Escalabilidade + +**Escalabilidade Horizontal**: Múltiplas instâncias do extrator com cache de ontologia compartilhado +**Particionamento da Ontologia**: Dividir ontologias grandes por domínio +**Processamento em Streaming**: Processar trechos à medida que chegam, sem agrupamento +**Gerenciamento de Memória**: Limpeza periódica de incorporações não utilizadas + +## Tratamento de Erros + +### Cenários de Falha + +1. **Ontologias Ausentes**: Recuar para a extração sem restrições +2. **Falha do Serviço de Incorporação**: Usar incorporações armazenadas em cache ou pular a correspondência semântica +3. **Tempo Limite do Serviço de Prompt**: Tentar novamente com retrocesso exponencial +4. **Formato de Tripla Inválido**: Registrar e pular triplas mal formadas +5. **Inconsistências na Ontologia**: Relatar conflitos e usar os elementos válidos mais específicos + +### Monitoramento + +Métricas-chave a serem monitoradas: + +Tempo de carregamento da ontologia e uso de memória +Latência de geração de incorporação +Desempenho da pesquisa vetorial +Tempo de resposta do serviço de prompt +Precisão da extração de triplas +Taxa de conformidade da ontologia + +## Caminho de Migração + +### De Extratores Existentes + +1. **Operação Paralela**: Executar em paralelo com os extratores existentes inicialmente +2. **Implantação Gradual**: Começar com tipos específicos de documentos +3. **Comparação de Qualidade**: Comparar a qualidade da saída com os extratores existentes +4. **Migração Completa**: Substituir os extratores existentes assim que a qualidade for verificada + +### Desenvolvimento de Ontologia + +1. **Inicialização a partir do Existente**: Gerar ontologias iniciais a partir do conhecimento existente +2. **Refinamento Iterativo**: Refinar com base em padrões de extração +3. **Revisão por Especialistas no Domínio**: Validar com especialistas no assunto +4. **Melhoria Contínua**: Atualizar com base no feedback da extração + +## Serviço de Consulta Sensível à Ontologia + +### Visão Geral + +O serviço de consulta sensível à ontologia fornece múltiplos caminhos de consulta para suportar diferentes armazenamentos de grafos de back-end. Ele aproveita o conhecimento da ontologia para um questionamento preciso e semanticamente consciente em diferentes armazenamentos de grafos, tanto Cassandra (via SPARQL) quanto armazenamentos de grafos baseados em Cypher (Neo4j, Memgraph, FalkorDB). + +**Componentes do Serviço**: +`onto-query-sparql`: Converte linguagem natural para SPARQL para Cassandra +`sparql-cassandra`: Camada de consulta SPARQL para Cassandra usando rdflib +`onto-query-cypher`: Converte linguagem natural para Cypher para bancos de dados de grafos +`cypher-executor`: Execução de consulta Cypher para Neo4j/Memgraph/FalkorDB + +### Arquitetura + +``` + ┌─────────────────┐ + │ User Query │ + └────────┬────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Question │────▶│ Sentence │ + │ Analyser │ │ Splitter │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Ontology │────▶│ Vector │ + │ Matcher │ │ Store │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Backend Router │ + └────────┬────────┘ + │ + ┌───────────┴───────────┐ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ onto-query- │ │ onto-query- │ + │ sparql │ │ cypher │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ SPARQL │ │ Cypher │ + │ Generator │ │ Generator │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ sparql- │ │ cypher- │ + │ cassandra │ │ executor │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ Cassandra │ │ Neo4j/Memgraph/ │ + │ │ │ FalkorDB │ + └────────┬────────┘ └────────┬────────┘ + │ │ + └────────────┬───────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Answer │────▶│ Prompt │ + │ Generator │ │ Service │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Final Answer │ + └─────────────────┘ +``` + +### Processamento de Consultas + +#### 1. Analisador de Perguntas + +**Propósito**: Decompõe as perguntas do usuário em componentes semânticos para correspondência com a ontologia. + +**Descrição do Algoritmo**: +O Analisador de Perguntas recebe a pergunta em linguagem natural e a divide em segmentos significativos, utilizando a mesma abordagem de divisão de frases utilizada no pipeline de extração. Ele identifica entidades, relacionamentos e restrições importantes mencionadas na pergunta. Cada segmento é analisado para determinar o tipo de pergunta (factual, agregação, comparação, etc.) e o formato de resposta esperado. Essa decomposição ajuda a identificar quais partes da ontologia são mais relevantes para responder à pergunta. + +**Operações Principais**: +Dividir a pergunta em frases e expressões +Identificar o tipo e a intenção da pergunta +Extrair entidades e relacionamentos mencionados +Detectar restrições e filtros na pergunta +Determinar o formato de resposta esperado + +#### 2. Correspondência de Ontologia para Consultas + +**Propósito**: Identifica o subconjunto relevante da ontologia necessário para responder à pergunta. + +**Descrição do Algoritmo**: +Similar ao Seletor de Ontologia do pipeline de extração, mas otimizado para responder a perguntas. O correspondente gera incorporações para segmentos de perguntas e pesquisa no armazenamento vetorial por elementos relevantes da ontologia. No entanto, ele se concentra em encontrar conceitos que seriam úteis para a construção de consultas, em vez de extração. Ele expande a seleção para incluir propriedades relacionadas que podem ser percorridas durante a exploração do grafo, mesmo que não sejam explicitamente mencionadas na pergunta. Por exemplo, se for feita uma pergunta sobre "funcionários", ele pode incluir propriedades como "trabalha-para", "gerencia" e "reporta-a", que podem ser relevantes para encontrar informações sobre funcionários. + +**Estratégia de Correspondência**: +Gerar incorporações para segmentos de perguntas +Encontrar conceitos da ontologia diretamente mencionados +Incluir propriedades que conectam classes mencionadas +Adicionar propriedades inversas e relacionadas para travessia +Incluir classes pai/filho para consultas hierárquicas +Construir uma partição da ontologia focada na consulta + +#### 3. Roteador de Backend + +**Propósito**: Roteia as consultas para o caminho de consulta específico do backend apropriado, com base na configuração. + +**Descrição do Algoritmo**: +O Roteador de Backend examina a configuração do sistema para determinar qual backend de grafo está ativo (Cassandra ou baseado em Cypher). Ele roteia a pergunta e a partição da ontologia para o serviço de geração de consulta apropriado. O roteador também pode suportar balanceamento de carga entre vários backends ou mecanismos de fallback se o backend primário estiver indisponível. + +**Lógica de Roteamento**: +Verificar o tipo de backend configurado nas configurações do sistema +Rotear para `onto-query-sparql` para backends Cassandra +Rotear para `onto-query-cypher` para Neo4j/Memgraph/FalkorDB +Suportar configurações multi-backend com distribuição de consultas +Lidar com cenários de failover e balanceamento de carga + +#### 4. Geração de Consulta SPARQL (`onto-query-sparql`) + +**Propósito**: Converte perguntas em linguagem natural em consultas SPARQL para execução no Cassandra. + +**Descrição do Algoritmo**: +O gerador de consulta SPARQL recebe a pergunta e a partição da ontologia e constrói uma consulta SPARQL otimizada para execução no backend Cassandra. Ele usa o serviço de prompt com um modelo específico para SPARQL que inclui semântica RDF/OWL. O gerador entende padrões SPARQL como caminhos de propriedade, cláusulas opcionais e filtros que podem ser traduzidos de forma eficiente em operações do Cassandra. + +**Modelo de Prompt de Geração SPARQL**: +``` +Generate a SPARQL query for the following question using the provided ontology. + +ONTOLOGY CLASSES: +{classes} + +ONTOLOGY PROPERTIES: +{properties} + +RULES: +- Use proper RDF/OWL semantics +- Include relevant prefixes +- Use property paths for hierarchical queries +- Add FILTER clauses for constraints +- Optimise for Cassandra backend + +QUESTION: {question} + +SPARQL QUERY: +``` + +#### 5. Geração de Consultas Cypher (`onto-query-cypher`) + +**Propósito**: Converte perguntas em linguagem natural em consultas Cypher para bancos de dados de grafos. + +**Descrição do Algoritmo**: +O gerador de consultas Cypher cria consultas Cypher nativas otimizadas para Neo4j, Memgraph e FalkorDB. Ele mapeia classes de ontologia para rótulos de nós e propriedades para relacionamentos, usando a sintaxe de correspondência de padrões do Cypher. O gerador inclui otimizações específicas do Cypher, como dicas de direção de relacionamento, uso de índices e dicas de planejamento de consulta. + +**Modelo de Prompt de Geração Cypher**: +``` +Generate a Cypher query for the following question using the provided ontology. + +NODE LABELS (from classes): +{classes} + +RELATIONSHIP TYPES (from properties): +{properties} + +RULES: +- Use MATCH patterns for graph traversal +- Include WHERE clauses for filters +- Use aggregation functions when needed +- Optimise for graph database performance +- Consider index hints for large datasets + +QUESTION: {question} + +CYPHER QUERY: +``` + +#### 6. Motor de Consulta SPARQL-Cassandra (`sparql-cassandra`) + +**Propósito**: Executa consultas SPARQL contra o Cassandra usando Python rdflib. + +**Descrição do Algoritmo**: +O motor SPARQL-Cassandra implementa um processador SPARQL usando a biblioteca rdflib do Python com um armazenamento backend personalizado para o Cassandra. Ele traduz padrões de grafos SPARQL em consultas CQL apropriadas para o Cassandra, tratando junções, filtros e agregações. O motor mantém um mapeamento RDF para Cassandra que preserva a estrutura semântica, otimizando para o modelo de armazenamento de famílias de colunas do Cassandra. + +**Características da Implementação**: +Implementação da interface de armazenamento rdflib para o Cassandra +Suporte para consultas SPARQL 1.1 com padrões comuns +Tradução eficiente de padrões de triplas para CQL +Suporte para caminhos de propriedades e consultas hierárquicas +Streaming de resultados para grandes conjuntos de dados +Pool de conexões e cache de consultas + +**Exemplo de Tradução**: +```sparql +SELECT ?animal WHERE { + ?animal rdf:type :Animal . + ?animal :hasOwner "John" . +} +``` +Traduz para consultas otimizadas do Cassandra, utilizando índices e chaves de partição. + +#### 7. Executor de Consultas Cypher (`cypher-executor`) + +**Propósito**: Executa consultas Cypher contra Neo4j, Memgraph e FalkorDB. + +**Descrição do Algoritmo**: +O executor de consultas Cypher fornece uma interface unificada para executar consultas Cypher em diferentes bancos de dados de grafos. Ele gerencia protocolos de conexão específicos do banco de dados, dicas de otimização de consultas e normalização do formato de resultados. O executor inclui lógica de repetição, pool de conexões e gerenciamento de transações adequados para cada tipo de banco de dados. + +**Suporte a Múltiplos Bancos de Dados**: +**Neo4j**: Protocolo Bolt, funções de transação, dicas de índice +**Memgraph**: Protocolo personalizado, resultados de streaming, consultas analíticas +**FalkorDB**: Adaptação do protocolo Redis, otimizações em memória + +**Recursos de Execução**: +Gerenciamento de conexão independente do banco de dados +Validação de consulta e verificação de sintaxe +Imposição de tempo limite e limites de recursos +Paginação e streaming de resultados +Monitoramento de desempenho por tipo de banco de dados +Failover automático entre instâncias de banco de dados + +#### 8. Gerador de Respostas + +**Propósito**: Sintetiza uma resposta em linguagem natural a partir dos resultados da consulta. + +**Descrição do Algoritmo**: +O Gerador de Respostas recebe os resultados estruturados da consulta e a pergunta original, e então usa o serviço de prompt para gerar uma resposta abrangente. Ao contrário de respostas simples baseadas em modelos, ele usa um LLM para interpretar os dados do grafo no contexto da pergunta, lidando com relacionamentos complexos, agregações e inferências. O gerador pode explicar seu raciocínio referenciando a estrutura da ontologia e os triplos específicos recuperados do grafo. + +**Processo de Geração de Respostas**: +Formata os resultados da consulta em um contexto estruturado +Inclui definições de ontologia relevantes para maior clareza +Constrói um prompt com a pergunta e os resultados +Gera uma resposta em linguagem natural por meio de um LLM +Valida a resposta em relação à intenção da consulta +Adiciona citações a entidades específicas do grafo, se necessário + +### Integração com Serviços Existentes + +#### Relação com GraphRAG + +**Complementar**: onto-query fornece precisão semântica, enquanto GraphRAG fornece ampla cobertura +**Infraestrutura Compartilhada**: Ambos usam o mesmo grafo de conhecimento e serviços de prompt +**Roteamento de Consultas**: O sistema pode rotear consultas para o serviço mais apropriado com base no tipo de pergunta +**Modo Híbrido**: Pode combinar ambas as abordagens para respostas abrangentes + +#### Relação com OntoRAG Extraction + +**Ontologias Compartilhadas**: Usa as mesmas configurações de ontologia carregadas por kg-extract-ontology +**Vector Store Compartilhado**: Reutiliza os embeddings na memória do serviço de extração +**Semântica Consistente**: As consultas operam em grafos construídos com as mesmas restrições ontológicas + +### Exemplos de Consultas + +#### Exemplo 1: Consulta Simples de Entidade +**Pergunta**: "Quais animais são mamíferos?" +**Correspondência de Ontologia**: [animal, mammal, subClassOf] +**Consulta Gerada**: +```cypher +MATCH (a:animal)-[:subClassOf*]->(m:mammal) +RETURN a.name +``` + +#### Exemplo 2: Consulta de Relacionamento +**Pergunta**: "Quais documentos foram escritos por John Smith?" +**Correspondência com a Ontologia**: [documento, pessoa, tem-autor] +**Consulta Gerada**: +```cypher +MATCH (d:document)-[:has-author]->(p:person {name: "John Smith"}) +RETURN d.title, d.date +``` + +#### Exemplo 3: Consulta de Agregação +**Pergunta**: "Quantas patas têm os gatos?" +**Correspondência com a Ontologia**: [gato, número-de-patas (propriedade de tipo de dado)] +**Consulta Gerada**: +```cypher +MATCH (c:cat) +RETURN c.name, c.number_of_legs +``` + +### Configuração + +```yaml +onto-query: + embedding_model: "text-embedding-3-small" + vector_store: + shared_with_extractor: true # Reuse kg-extract-ontology's store + query_builder: + model: "gpt-4" + temperature: 0.1 + max_query_length: 1000 + graph_executor: + timeout: 30000 # ms + max_results: 1000 + answer_generator: + model: "gpt-4" + temperature: 0.3 + max_tokens: 500 +``` + +### Otimizações de Desempenho + +#### Otimização de Consultas + +**Poda da Ontologia**: Inclua apenas os elementos da ontologia necessários nos prompts. +**Cache de Consultas**: Armazene em cache as perguntas e consultas frequentemente feitas. +**Cache de Resultados**: Armazene os resultados para consultas idênticas dentro de um período de tempo. +**Processamento em Lote**: Processe várias perguntas relacionadas em uma única travessia de grafo. + +#### Considerações de Escalabilidade + +**Execução Distribuída**: Paralelize subconsultas em partições do grafo. +**Resultados Incrementais**: Transmita os resultados para conjuntos de dados grandes. +**Balanceamento de Carga**: Distribua a carga de consulta entre várias instâncias de serviço. +**Piscina de Recursos**: Gerencie as piscinas de conexão para bancos de dados de grafo. + +### Tratamento de Erros + +#### Cenários de Falha + +1. **Geração de Consulta Inválida**: Utilize o GraphRAG ou a pesquisa por palavras-chave. +2. **Incompatibilidade da Ontologia**: Expanda a pesquisa para um subconjunto mais amplo da ontologia. +3. **Tempo Limite da Consulta**: Simplifique a consulta ou aumente o tempo limite. +4. **Resultados Vazios**: Sugira a reformulação da consulta ou perguntas relacionadas. +5. **Falha do Serviço LLM**: Utilize consultas armazenadas em cache ou respostas baseadas em modelos. + +### Métricas de Monitoramento + +Distribuição da complexidade das perguntas. +Tamanhos das partições da ontologia. +Taxa de sucesso na geração de consultas. +Tempo de execução da consulta do grafo. +Pontuações de qualidade da resposta. +Taxas de acerto do cache. +Frequências de erro por tipo. + +## Melhorias Futuras + +1. **Aprendizado da Ontologia**: Estenda automaticamente as ontologias com base em padrões de extração. +2. **Pontuação de Confiança**: Atribua pontuações de confiança às triplas extraídas. +3. **Geração de Explicação**: Forneça o raciocínio para a extração de triplas. +4. **Aprendizado Ativo**: Solicite validação humana para extrações incertas. + +## Considerações de Segurança + +1. **Prevenção de Injeção de Prompt**: Limpe o texto do chunk antes da construção do prompt. +2. **Limites de Recursos**: Defina um limite para o uso de memória para o armazenamento vetorial. +3. **Limitação de Taxa**: Limite as solicitações de extração por cliente. +4. **Registro de Auditoria**: Rastreie todas as solicitações e resultados de extração. + +## Estratégia de Teste + +### Teste Unitário + +Carregador de ontologia com vários formatos. +Geração e armazenamento de incorporações. +Algoritmos de divisão de frases. +Cálculos de similaridade vetorial. +Análise e validação de triplas. + +### Teste de Integração + +Pipeline de extração de ponta a ponta. +Integração do serviço de configuração. +Interação com o serviço de prompt. +Tratamento de extração concorrente. + +### Teste de Desempenho + +Tratamento de ontologias grandes (1000+ classes). +Processamento de alto volume de chunks. +Uso de memória sob carga. +Benchmarks de latência. + +## Plano de Entrega + +### Visão Geral + +O sistema OntoRAG será entregue em quatro fases principais, com cada fase fornecendo valor incremental, construindo em direção ao sistema completo. O plano se concentra em estabelecer as capacidades básicas de extração primeiro, depois adicionando funcionalidade de consulta, seguido por otimizações e recursos avançados. + +### Fase 1: Fundação e Extração Central + +**Objetivo**: Estabelecer o pipeline básico de extração orientado à ontologia com correspondência vetorial simples. + +#### Etapa 1.1: Fundação do Gerenciamento de Ontologia +Implementar o carregador de configuração da ontologia (`OntologyLoader`). +Analisar e validar estruturas JSON da ontologia. +Criar armazenamento de ontologia na memória e padrões de acesso. +Implementar o mecanismo de atualização da ontologia. + +**Critérios de Sucesso**: +Carregar e analisar com sucesso as configurações da ontologia. +Validar a estrutura e a consistência da ontologia. +Lidar com várias ontologias simultâneas. + +#### Etapa 1.2: Implementação do Armazenamento Vetorial +Implementar um armazenamento vetorial simples baseado em NumPy como um protótipo inicial. +Adicionar a implementação do armazenamento vetorial FAISS. +Criar uma abstração de interface de armazenamento vetorial. +Implementar a pesquisa de similaridade com limites configuráveis. + +**Critérios de Sucesso**: +Armazenar e recuperar embeddings de forma eficiente +Realizar busca de similaridade com latência inferior a 100ms +Suportar backends NumPy e FAISS + +#### Etapa 1.3: Pipeline de Embedding de Ontologia +Integrar com o serviço de embedding +Implementar componente `OntologyEmbedder` +Gerar embeddings para todos os elementos da ontologia +Armazenar embeddings com metadados no armazenamento vetorial + +**Critérios de Sucesso**: +Gerar embeddings para classes e propriedades +Armazenar embeddings com metadados adequados +Reconstruir embeddings em caso de atualizações da ontologia + +#### Etapa 1.4: Componentes de Processamento de Texto +Implementar separador de frases usando NLTK/spaCy +Extrair frases e entidades nomeadas +Criar hierarquia de segmentos de texto +Gerar embeddings para segmentos de texto + +**Critérios de Sucesso**: +Dividir o texto em frases com precisão +Extrair frases significativas +Manter as relações de contexto + +#### Etapa 1.5: Algoritmo de Seleção de Ontologia +Implementar correspondência de similaridade entre texto e ontologia +Criar resolução de dependências para elementos da ontologia +Criar subconjuntos coerentes mínimos da ontologia +Otimizar o desempenho da geração de subconjuntos + +**Critérios de Sucesso**: +Selecionar elementos relevantes da ontologia com precisão >80% +Incluir todas as dependências necessárias +Gerar subconjuntos em <500ms + +#### Etapa 1.6: Serviço Básico de Extração +Implementar construção de prompts para extração +Integrar com o serviço de prompts +Analisar e validar respostas de triplas +Criar endpoint de serviço `kg-extract-ontology` + +**Critérios de Sucesso**: +Extrair triplas conformes à ontologia +Validar todas as triplas em relação à ontologia +Lidar com erros de extração de forma elegante + +### Fase 2: Implementação do Sistema de Consulta + +**Objetivo**: Adicionar capacidades de consulta com conhecimento da ontologia, com suporte para vários backends. + +#### Etapa 2.1: Componentes Fundamentais da Consulta +Implementar analisador de perguntas +Criar correspondência de ontologia para consultas +Adaptar a busca vetorial para o contexto da consulta +Construir componente de roteamento de backend + +**Critérios de Sucesso**: +Analisar perguntas em componentes semânticos +Corresponder perguntas a elementos relevantes da ontologia +Rotear consultas para o backend apropriado + +#### Etapa 2.2: Implementação do Caminho SPARQL +Implementar serviço `onto-query-sparql` +Criar gerador de consultas SPARQL usando LLM +Desenvolver modelos de prompt para geração de SPARQL +Validar a sintaxe SPARQL gerada + +**Critérios de Sucesso**: +Gerar consultas SPARQL válidas +Usar padrões SPARQL apropriados +Lidar com tipos de consulta complexos + +#### Etapa 2.3: Motor SPARQL-Cassandra +Implementar interface de armazenamento rdflib para Cassandra +Criar tradutor de consultas CQL +Otimizar a correspondência de padrões de triplas +Lidar com a formatação de resultados SPARQL + +**Critérios de Sucesso**: +Executar consultas SPARQL no Cassandra +Suportar padrões SPARQL comuns +Retornar resultados em formato padrão + +#### Etapa 2.4: Implementação do Caminho Cypher +Implementar serviço `onto-query-cypher` +Criar gerador de consultas Cypher usando LLM +Desenvolver modelos de prompt para geração de Cypher +Validar a sintaxe Cypher gerada + +**Critérios de Sucesso**: +Gerar consultas Cypher válidas +Usar padrões de grafo apropriados +Suportar Neo4j, Memgraph, FalkorDB + +#### Etapa 2.5: Executor Cypher +Implementar executor Cypher multi-banco de dados +Suportar protocolo Bolt (Neo4j/Memgraph) +Suportar protocolo Redis (FalkorDB) +Lidar com a normalização de resultados + +**Critérios de Sucesso**: +Executar Cypher em todos os bancos de dados alvo +Lidar com diferenças específicas de cada banco de dados +Manter pools de conexão de forma eficiente + +#### Etapa 2.6: Geração de Respostas +Implementar componente de gerador de respostas +Criar prompts para síntese de respostas +Formatar resultados de consulta para consumo por LLM +Gerar respostas em linguagem natural + +**Critérios de Sucesso**: +Gerar respostas precisas a partir de resultados de consulta +Manter o contexto da pergunta original +Fornecer respostas claras e concisas + +### Fase 3: Otimização e Robustez + +**Objetivo**: Otimizar o desempenho, adicionar cache, melhorar o tratamento de erros e aumentar a confiabilidade. + +#### Etapa 3.1: Otimização de Desempenho +Implementar cache de embeddings +Adicionar cache de resultados de consulta +Otimizar a busca vetorial com índices FAISS IVF +Implementar processamento em lote para embeddings + +**Critérios de Sucesso**: +Reduzir a latência média da consulta em 50% +Suportar 10 vezes mais requisições simultâneas +Manter tempos de resposta abaixo de um segundo + +#### Etapa 3.2: Tratamento Avançado de Erros +Implementar recuperação abrangente de erros +Adicionar mecanismos de fallback entre caminhos de consulta +Criar lógica de repetição com retrocesso exponencial +Melhorar o registro e o diagnóstico de erros + +**Critérios de Sucesso**: +Lidar graciosamente com todos os cenários de falha +Failover automático entre backends +Relatório de erros detalhado para depuração + +#### Etapa 3.3: Monitoramento e Observabilidade +Adicionar coleta de métricas de desempenho +Implementar rastreamento de consultas +Criar endpoints de verificação de saúde +Adicionar monitoramento de uso de recursos + +**Critérios de Sucesso**: +Rastrear todos os indicadores de desempenho chave +Identificar gargalos rapidamente +Monitorar a saúde do sistema em tempo real + +#### Etapa 3.4: Gerenciamento de Configuração +Implementar atualizações dinâmicas de configuração +Adicionar validação de configuração +Criar modelos de configuração +Suportar configurações específicas do ambiente + +**Critérios de Sucesso**: +Atualizar a configuração sem reinicialização +Validar todas as alterações de configuração +Suportar múltiplos ambientes de implantação + +### Fase 4: Recursos Avançados + +**Objetivo**: Adicionar capacidades sofisticadas para implantação em produção e funcionalidade aprimorada. + +#### Etapa 4.1: Suporte a Múltiplas Ontologias +Implementar lógica de seleção de ontologia +Suportar consultas entre ontologias +Lidar com versionamento de ontologias +Criar capacidades de mesclagem de ontologias + +**Critérios de Sucesso**: +Consultar em múltiplas ontologias +Lidar com conflitos de ontologia +Suportar a evolução da ontologia + +#### Etapa 4.2: Roteamento Inteligente de Consultas +Implementar roteamento baseado em desempenho +Adicionar análise de complexidade de consulta +Criar algoritmos de roteamento adaptativos +Suportar testes A/B para caminhos + +**Critérios de Sucesso**: +Roteamento de consultas de forma otimizada +Aprendizado com o desempenho das consultas +Melhoria do roteamento ao longo do tempo + +#### Etapa 4.3: Recursos Avançados de Extração +Adicionar pontuação de confiança para triplas +Implementar geração de explicações +Criar loops de feedback para melhoria +Suportar aprendizado incremental + +**Critérios de Sucesso**: +Fornecer pontuações de confiança +Explicar decisões de extração +Melhorar continuamente a precisão + +#### Etapa 4.4: Endurecimento para Produção +Adicionar limitação de taxa +Implementar autenticação/autorização +Criar automação de implantação +Adicionar backup e recuperação + +**Critérios de Sucesso**: +Segurança pronta para produção +Pipeline de implantação automatizado +Capacidade de recuperação de desastres + +### Marcos de Entrega + +1. **Marco 1** (Fim da Fase 1): Extração básica orientada por ontologia operacional +2. **Marco 2** (Fim da Fase 2): Sistema de consulta completo com caminhos SPARQL e Cypher +3. **Marco 3** (Fim da Fase 3): Sistema otimizado e robusto pronto para o ambiente de testes +4. **Marco 4** (Fim da Fase 4): Sistema pronto para produção com recursos avançados + +### Mitigação de Riscos + +#### Riscos Técnicos +**Escalabilidade do Vector Store**: Começar com NumPy, migrar gradualmente para FAISS +**Precisão da Geração de Consultas**: Implementar mecanismos de validação e fallback +**Compatibilidade com o Backend**: Testar extensivamente com cada tipo de banco de dados +**Gargalos de Desempenho**: Analisar o desempenho frequentemente e otimizar iterativamente + +#### Riscos Operacionais +**Qualidade da Ontologia**: Implementar validação e verificação de consistência +**Dependências de Serviço**: Adicionar circuit breakers e fallbacks +**Restrições de Recursos**: Monitorar e definir limites apropriados +**Consistência de Dados**: Implementar tratamento de transações adequado + +### Métricas de Sucesso + +#### Métricas de Sucesso da Fase 1 +Precisão da extração: >90% de conformidade com a ontologia +Velocidade de processamento: <1 segundo por chunk +Tempo de carregamento da ontologia: <10 segundos +Latência da busca vetorial: <100ms + +#### Métricas de Sucesso da Fase 2 +Taxa de sucesso da consulta: >95% +Latência da consulta: <2 segundos de ponta a ponta +Compatibilidade com o backend: 100% para bancos de dados de destino +Precisão da resposta: >85% com base nos dados disponíveis + +#### Métricas de Sucesso da Fase 3 +Tempo de atividade do sistema: >99,9% +Taxa de recuperação de erros: >95% +Taxa de acerto em cache: >60% +Usuários simultâneos: >100 + +#### Métricas de Sucesso da Fase 4 +Consultas multi-ontologia: Totalmente suportadas +Otimização de roteamento: Redução de latência de 30% +Precisão da pontuação de confiança: >90% +Implantação em produção: Atualizações sem interrupção + +## Referências + +[OWL 2 Web Ontology Language](https://www.w3.org/TR/owl2-overview/) +[GraphRAG Architecture](https://github.com/microsoft/graphrag) +[Sentence Transformers](https://www.sbert.net/) +[FAISS Vector Search](https://github.com/facebookresearch/faiss) +[spaCy NLP Library](https://spacy.io/) +[rdflib Documentation](https://rdflib.readthedocs.io/) +[Neo4j Bolt Protocol](https://neo4j.com/docs/bolt/current/) diff --git a/docs/tech-specs/ontorag.ru.md b/docs/tech-specs/ontorag.ru.md new file mode 100644 index 00000000..7afbce3c --- /dev/null +++ b/docs/tech-specs/ontorag.ru.md @@ -0,0 +1,1067 @@ +# OntoRAG: Техническая спецификация системы извлечения знаний на основе онтологий. + +## Обзор + +OntoRAG – это система извлечения знаний и запросов, основанная на онтологиях, которая обеспечивает строгую семантическую согласованность как при извлечении триплетов знаний из неструктурированного текста, так и при запросах к полученному графу знаний. Подобно GraphRAG, но с формальными ограничениями онтологий, OntoRAG гарантирует, что все извлеченные триплеты соответствуют предопределенным онтологическим структурам, и предоставляет возможности семантически-осведомленных запросов. + +Система использует сопоставление векторного сходства для динамического выбора соответствующих подмножеств онтологий как для извлечения, так и для операций запросов, что позволяет осуществлять целенаправленную и контекстуально-подходящую обработку при сохранении семантической достоверности. + +**Название сервиса**: `kg-extract-ontology` + +## Цели + +**Извлечение, соответствующее онтологии**: Обеспечить строгое соответствие всех извлеченных триплетов загруженным онтологиям. +**Динамический выбор контекста**: Использовать эмбеддинги для выбора соответствующих подмножеств онтологий для каждого фрагмента. +**Семантическая согласованность**: Поддерживать иерархии классов, области/диапазоны свойств и ограничения. +**Эффективная обработка**: Использовать векторные хранилища в памяти для быстрого сопоставления элементов онтологии. +**Масштабируемая архитектура**: Поддержка нескольких одновременных онтологий с разными доменами. + +## Предыстория + +Текущие сервисы извлечения знаний (`kg-extract-definitions`, `kg-extract-relationships`) работают без формальных ограничений, что может приводить к несовместимым или противоречивым триплетам. OntoRAG решает эту проблему следующим образом: + +1. Загрузка формальных онтологий, определяющих допустимые классы и свойства. +2. Использование эмбеддингов для сопоставления текстового содержимого с соответствующими элементами онтологии. +3. Ограничение извлечения только производством триплетов, соответствующих онтологии. +4. Обеспечение семантической проверки извлеченных знаний. + +Этот подход сочетает гибкость нейронного извлечения с строгостью формального представления знаний. + +## Технический дизайн + +### Архитектура + +Система OntoRAG состоит из следующих компонентов: + +``` +┌─────────────────┐ +│ Configuration │ +│ Service │ +└────────┬────────┘ + │ Ontologies + ▼ +┌─────────────────┐ ┌──────────────┐ +│ kg-extract- │────▶│ Embedding │ +│ ontology │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ │ + ▼ ▼ +┌─────────────────┐ ┌──────────────┐ +│ In-Memory │◀────│ Ontology │ +│ Vector Store │ │ Embedder │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Sentence │────▶│ Chunker │ +│ Splitter │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Ontology │────▶│ Vector │ +│ Selector │ │ Search │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Prompt │────▶│ Prompt │ +│ Constructor │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ +│ Triple Output │ +└─────────────────┘ +``` + +### Детали компонента + +#### 1. Загрузчик онтологий + +**Назначение**: Извлекает и анализирует конфигурации онтологий из сервиса конфигураций, используя обновления, основанные на событиях. + +**Реализация**: +Загрузчик онтологий использует очередь ConfigPush от TrustGraph для получения обновлений конфигураций онтологий, основанных на событиях. Когда элемент конфигурации типа "онтология" добавляется или изменяется, загрузчик получает обновление через очередь config-update и анализирует структуру JSON, содержащую метаданные, классы, объектные свойства и свойства типов данных. Эти проанализированные онтологии хранятся в памяти в виде структурированных объектов, которые могут быть эффективно доступны во время процесса извлечения. + +**Основные операции**: +Подписаться на очередь config-update для конфигураций типа онтология +Анализировать структуры JSON онтологий в объекты OntologyClass и OntologyProperty +Проверять структуру и согласованность онтологии +Кэшировать проанализированные онтологии в памяти для быстрого доступа +Обрабатывать потоки данных с использованием векторных хранилищ, специфичных для каждого потока + +**Местоположение реализации**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_loader.py` + +#### 2. Встраиватель онтологий + +**Назначение**: Создает векторные представления для всех элементов онтологии, чтобы обеспечить сопоставление семантической схожести. + +**Реализация**: +Встраиватель онтологий обрабатывает каждый элемент в загруженных онтологиях (классы, объектные свойства и свойства типов данных) и генерирует векторные представления с использованием сервиса EmbeddingsClientSpec. Для каждого элемента он объединяет идентификатор элемента, метки и описание (комментарий), чтобы создать текстовое представление. Этот текст затем преобразуется в векторное представление высокой размерности, которое отражает его семантическое значение. Эти представления хранятся в векторном хранилище FAISS, специфичном для каждого потока, вместе с метаданными об элементе, источнике онтологии и полном определении. Встраиватель автоматически определяет размерность представления из первого ответа на запрос. + +**Основные операции**: +Создавать текстовые представления из идентификаторов элементов, меток и комментариев +Генерировать представления с помощью EmbeddingsClientSpec (используя asyncio.gather для пакетной обработки) +Хранить представления с исчерпывающими метаданными в векторном хранилище FAISS +Индексировать по онтологии, типу элемента и идентификатору элемента для эффективного поиска +Автоматически определять размерность представления для инициализации векторного хранилища +Использовать модели встраивания, специфичные для каждого потока, с независимыми векторными хранилищами + +**Местоположение реализации**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_embedder.py` + +#### 3. Обработчик текста (Разделитель предложений) + +**Назначение**: Разбивает текстовые фрагменты на более мелкие сегменты для точного сопоставления с онтологиями. + +**Реализация**: +Обработчик текста использует NLTK для токенизации предложений и разметки частей речи, чтобы разделить входящие текстовые фрагменты на предложения. Он обрабатывает совместимость версий NLTK, пытаясь загрузить `punkt_tab` и `averaged_perceptron_tagger_eng`, с возможностью использования более старых версий, если это необходимо. Каждый текстовый фрагмент разбивается на отдельные предложения, которые могут быть независимо сопоставлены с элементами онтологии. + +**Основные операции**: +Разделять текст на предложения с помощью токенизации предложений NLTK +Обрабатывать совместимость версий NLTK (punkt_tab vs punkt) +Создавать объекты TextSegment с текстом и информацией о позиции +Поддерживать как полные предложения, так и отдельные фрагменты + +**Местоположение реализации**: `trustgraph-flow/trustgraph/extract/kg/ontology/text_processor.py` + +#### 4. Выборщик онтологий + +**Назначение**: Определяет наиболее релевантный поднабор элементов онтологии для текущего текстового фрагмента. + +**Реализация**: +Выборщик онтологий выполняет семантическое сопоставление между текстовыми сегментами и элементами онтологии с использованием векторного поиска по схожести FAISS. Для каждого предложения из текстового фрагмента генерируется представление, и выполняется поиск в векторном хранилище наиболее похожих элементов онтологии с использованием косинусной схожести с настраиваемым порогом (по умолчанию 0,3). После сбора всех релевантных элементов выполняется комплексное разрешение зависимостей: если выбран класс, включаются его родительские классы; если выбрано свойство, добавляются классы, являющиеся доменом и диапазоном этого свойства. Кроме того, для каждого выбранного класса автоматически включаются **все свойства, которые ссылаются на этот класс** в качестве домена или диапазона. Это обеспечивает доступ к всем релевантным свойствам отношений. + +**Основные операции**: +Генерация векторных представлений для каждого текстового сегмента (предложений) +Выполнение поиска ближайших соседей в векторном хранилище FAISS (top_k=10, threshold=0.3) +Применение порогового значения для фильтрации слабых соответствий +Разрешение зависимостей (родительские классы, домены, диапазоны) +**Автоматическое включение всех свойств, связанных с выбранными классами** (сопоставление домена/диапазона) +Построение согласованного подмножества онтологии со всеми необходимыми связями +Удаление дублирующихся элементов, появляющихся несколько раз + +**Местоположение реализации**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_selector.py` + +#### 5. Создание запросов + +**Назначение**: Создает структурированные запросы, которые направляют LLM (большую языковую модель) на извлечение только троек, соответствующих онтологии. + +**Реализация**: +Сервис извлечения использует шаблон Jinja2, загруженный из `ontology-prompt.md`, который форматирует подмножество онтологии и текст для извлечения LLM. Шаблон динамически перебирает классы, объектные свойства и свойства типов данных, используя синтаксис Jinja2, представляя каждый из них с их описаниями, доменами, диапазонами и иерархическими связями. Запрос включает строгие правила использования только предоставленных элементов онтологии и запрашивает вывод в формате JSON для последовательного разбора. + +**Основные операции**: +Использование шаблона Jinja2 с циклами по элементам онтологии +Форматирование классов с отношениями родительских классов (subclass_of) и комментариями +Форматирование свойств с ограничениями домена/диапазона и комментариями +Включение явных правил извлечения и требований к формату вывода +Вызов сервиса запросов с идентификатором шаблона "extract-with-ontologies" + +**Местоположение шаблона**: `ontology-prompt.md` +**Местоположение реализации**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` (метод build_extraction_variables) + +#### 6. Основной сервис извлечения + +**Назначение**: Координирует все компоненты для выполнения сквозного извлечения троек на основе онтологии. + +**Реализация**: +Основной сервис извлечения (KgExtractOntology) является уровнем оркестровки, который управляет полным рабочим процессом извлечения. Он использует шаблон TrustGraph's FlowProcessor с инициализацией компонентов для каждого потока. Когда поступает обновление конфигурации онтологии, он инициализирует или обновляет компоненты, специфичные для потока (загрузчик онтологии, эмбеддер, обработчик текста, селектор). Когда для обработки поступает текстовый фрагмент, он координирует конвейер: разделение текста на сегменты, поиск соответствующих элементов онтологии с помощью векторного поиска, построение ограниченного запроса, вызов сервиса запросов, разбор и проверка ответа, генерация троек определения онтологии и вывод как контентных троек, так и контекстов сущностей. + +**Конвейер извлечения**: +1. Получение текстового фрагмента через очередь chunks-input +2. Инициализация компонентов потока, если это необходимо (при первом фрагменте или обновлении конфигурации) +3. Разделение текста на предложения с использованием NLTK +4. Поиск в векторном хранилище FAISS для поиска соответствующих концепций онтологии +5. Построение подмножества онтологии с автоматическим включением свойств +6. Создание переменных шаблона Jinja2 +7. Вызов сервиса запросов с шаблоном extract-with-ontologies +8. Разбор ответа JSON в структурированные тройки +9. Проверка троек и расширение URI до полных URI онтологии +10. Генерация троек определения онтологии (классы и свойства с метками/комментариями/доменами/диапазонами) +11. Построение контекстов сущностей из всех троек +12. Вывод в очереди троек и entity-contexts + +**Основные характеристики**: +Векторные хранилища на поток, поддерживающие различные модели эмбеддинга +Обновления онтологии, управляемые событиями, через очередь config-update +Автоматическое расширение URI с использованием URI онтологии +Элементы онтологии добавляются в графовое представление знаний со всеми метаданными +Контексты сущностей включают как контентные, так и элементы онтологии + +**Местоположение реализации**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` + +### Конфигурация + +Сервис использует стандартный подход к конфигурации TrustGraph с аргументами командной строки: + +```bash +kg-extract-ontology \ + --id kg-extract-ontology \ + --pulsar-host localhost:6650 \ + --input-queue chunks \ + --config-input-queue config-update \ + --output-queue triples \ + --entity-contexts-output-queue entity-contexts +``` + +**Основные параметры конфигурации**: +`similarity_threshold`: 0.3 (по умолчанию, настраивается в коде) +`top_k`: 10 (количество элементов онтологии для извлечения на сегмент) +`vector_store`: Per-flow FAISS IndexFlatIP с автоматически определенными измерениями +`text_processor`: NLTK с токенизацией предложений punkt_tab +`prompt_template`: "extract-with-ontologies" (шаблон Jinja2) + +**Конфигурация онтологии**: +Онтологии загружаются динамически через очередь config-update с типом "ontology". + +### Поток данных + +1. **Фаза инициализации** (для каждого потока): + Получение конфигурации онтологии через очередь config-update + Разбор JSON онтологии в объекты OntologyClass и OntologyProperty + Генерация векторных представлений для всех элементов онтологии с использованием EmbeddingsClientSpec + Сохранение векторных представлений во временном хранилище FAISS для каждого потока + Автоматическое определение размерности векторных представлений из первого ответа + +2. **Фаза извлечения** (для каждого фрагмента): + Получение фрагмента из очереди chunks-input + Разбиение фрагмента на предложения с использованием NLTK + Вычисление векторных представлений для каждого предложения + Поиск в векторном хранилище FAISS наиболее релевантных элементов онтологии + Создание подмножества онтологии с автоматическим включением свойств + Формирование переменных шаблона Jinja2 с текстом и онтологией + Вызов сервиса запросов с шаблоном extract-with-ontologies + Разбор ответа в формате JSON и проверка корректности троек + Расширение URI с использованием URI онтологии + Генерация троек определения онтологии + Создание контекстов сущностей из всех троек + Отправка в очереди triples и entity-contexts + +### Временное векторное хранилище + +**Назначение**: Обеспечивает быстрый поиск по сходству в памяти для сопоставления элементов онтологии. + +**Реализация: FAISS** + +Система использует **FAISS (Facebook AI Similarity Search)** с IndexFlatIP для поиска по точному косинусному сходству. Основные характеристики: + +**IndexFlatIP**: Точный поиск по косинусному сходству с использованием внутреннего произведения +**Автоматическое определение**: Размерность определяется из первого ответа на векторное представление +**Хранилища для каждого потока**: Каждый поток имеет независимое векторное хранилище для разных моделей векторных представлений +**Нормализация**: Все векторы нормализуются перед индексацией +**Пакетные операции**: Эффективное добавление пакетами для начальной загрузки онтологии + +**Местоположение реализации**: `trustgraph-flow/trustgraph/extract/kg/ontology/vector_store.py` + +### Алгоритм выбора подмножества онтологии + +**Назначение**: Динамически выбирает минимальную релевантную часть онтологии для каждого текстового фрагмента. + +**Подробные шаги алгоритма**: + +1. **Сегментация текста**: + Разбиение входного фрагмента на предложения с использованием NLP для определения границ предложений + Извлечение именных групп, глагольных групп и именованных сущностей из каждого предложения + Создание иерархической структуры сегментов с сохранением контекста + +2. **Генерация векторных представлений**: + Генерация векторных представлений для каждого текстового сегмента (предложений и фраз) + Использование той же модели векторных представлений, что и для элементов онтологии + Кэширование векторных представлений для повторяющихся сегментов для повышения производительности + +3. **Поиск по сходству**: + Для каждого векторного представления текстового сегмента выполняется поиск в векторном хранилище + Извлекаются k (например, 10) наиболее похожих элементов онтологии + Применяется порог сходства (например, 0.7) для фильтрации слабых совпадений + Результаты агрегируются по всем сегментам, отслеживается частота совпадений + +4. **Разрешение зависимостей**: + Для каждого выбранного класса рекурсивно включаются все родительские классы до корневого + Для каждого выбранного свойства включаются классы, являющиеся доменом и диапазоном + Для обратных свойств обеспечивается включение обоих направлений + Добавляются эквивалентные классы, если они существуют в онтологии + +5. **Создание подмножества**: + Удаление дубликатов элементов при сохранении взаимосвязей + Организация в классы, объектные свойства и свойства типов данных + Обеспечение сохранения всех ограничений и взаимосвязей + Создание мини-онтологии, которая является самодостаточной и полной + +**Пример**: +Данный текст: "The brown dog chased the white cat up the tree." +Сегменты: ["brown dog", "white cat", "tree", "chased"] +Соответствующие элементы: [dog (class), cat (class), animal (parent), chases (property)] +Зависимости: [animal (parent of dog and cat), lifeform (parent of animal)] +Окончательное подмножество: Полная мини-онтология с иерархией животных и отношением "chases" + +### Проверка троек + +**Назначение**: Обеспечивает строгое соответствие всех извлеченных троек ограничениям онтологии. + +**Алгоритм проверки**: + +1. **Валидация классов**: + Проверьте, являются ли субъекты экземплярами классов, определенных в подмножестве онтологии. + Для свойств объектов убедитесь, что объекты также являются допустимыми экземплярами классов. + Проверьте имена классов по отношению к словарю классов онтологии. + Обрабатывайте иерархии классов: экземпляры подклассов считаются допустимыми для ограничений родительского класса. + +2. **Валидация свойств**: + Убедитесь, что предикаты соответствуют свойствам в подмножестве онтологии. + Различайте свойства объектов (от сущности к сущности) и свойства данных (от сущности к литералу). + Проверьте, соответствуют ли имена свойств точно (с учетом пространства имен, если оно присутствует). + +3. **Проверка домена/диапазона**: + Для каждого свойства, используемого в качестве предиката, извлеките его домен и диапазон. + Убедитесь, что тип субъекта соответствует или наследуется от домена свойства. + Убедитесь, что тип объекта соответствует или наследуется от диапазона свойства. + Для свойств данных убедитесь, что объект является литералом правильного типа XSD. + +4. **Валидация кардинальности**: + Отслеживайте количество использования свойств для каждого субъекта. + Проверьте минимальную кардинальность: убедитесь, что обязательные свойства присутствуют. + Проверьте максимальную кардинальность: убедитесь, что свойство не используется слишком много раз. + Для функциональных свойств убедитесь, что присутствует не более одного значения для каждого субъекта. + +5. **Валидация данных**: + Разбирайте литеральные значения в соответствии с их объявленными типами XSD. + Проверяйте, являются ли целые числа допустимыми числами, правильно ли отформатированы даты и т.д. + Проверяйте шаблоны строк, если определены ограничения regex. + Убедитесь, что URI имеют правильную структуру для типов xsd:anyURI. + +**Пример валидации**: +Тройка: ("Buddy", "has-owner", "John") +Проверьте, что "Buddy" имеет тип класса, который может иметь свойство "has-owner". +Проверьте, существует ли "has-owner" в онтологии. +Убедитесь, что ограничение домена: субъект должен быть типа "Pet" или подкласса. +Убедитесь, что ограничение диапазона: объект должен быть типа "Person" или подкласса. +Если допустимо, добавьте в вывод; если недопустимо, зарегистрируйте нарушение и пропустите. + +## Вопросы производительности + +### Стратегии оптимизации + +1. **Кэширование вложений**: Кэшируйте вложения для часто используемых текстовых фрагментов. +2. **Пакетная обработка**: Обрабатывайте несколько фрагментов параллельно. +3. **Индексирование векторного хранилища**: Используйте алгоритмы приблизительного поиска ближайших соседей для больших онтологий. +4. **Оптимизация запросов**: Минимизируйте размер запроса, включая только необходимые элементы онтологии. +5. **Кэширование результатов**: Кэшируйте результаты извлечения для идентичных фрагментов. + +### Масштабируемость + +**Горизонтальное масштабирование**: Несколько экземпляров экстрактора с общим кэшем онтологии. +**Разделение онтологии**: Разделите большие онтологии по доменам. +**Потоковая обработка**: Обрабатывайте фрагменты по мере их поступления, без пакетной обработки. +**Управление памятью**: Периодическая очистка неиспользуемых вложений. + +## Обработка ошибок + +### Сценарии сбоев + +1. **Отсутствующие онтологии**: Переход к извлечению без ограничений. +2. **Сбой службы вложений**: Используйте кэшированные вложения или пропустите семантическое сопоставление. +3. **Тайм-аут службы запросов**: Повторите попытку с экспоненциальной задержкой. +4. **Недопустимый формат тройки**: Зарегистрируйте и пропустите неформатированные тройки. +5. **Несоответствия в онтологии**: Сообщите о конфликтах и используйте наиболее конкретные допустимые элементы. + +### Мониторинг + +Ключевые метрики для отслеживания: + +Время загрузки онтологии и использование памяти. +Задержка генерации вложений. +Производительность векторного поиска. +Время отклика службы запросов. +Точность извлечения тройки. +Уровень соответствия онтологии. + +## Путь миграции + +### Из существующих экстракторов + +1. **Параллельная работа**: Работайте параллельно с существующими экстракторами изначально. +2. **Постепенное развертывание**: Начните с определенных типов документов. +3. **Сравнение качества**: Сравните качество вывода с существующими экстракторами. +4. **Полная миграция**: Замените существующие экстракторы после проверки качества. + +### Разработка онтологии + +1. **Начальная версия из существующих**: Сгенерируйте начальные онтологии из существующих знаний. +2. **Итеративная доработка**: Дорабатывайте на основе шаблонов извлечения. +3. **Экспертная оценка**: Проверьте с экспертами в предметной области. +4. **Непрерывное улучшение**: Обновляйте на основе обратной связи об извлечении. + +## Сервис запросов, чувствительный к онтологии + +### Обзор + +Сервис запросов, чувствительный к онтологии, предоставляет несколько путей запросов для поддержки различных бэкенд-хранилищ графов. Он использует знания онтологии для точного, семантически-осведомленного ответа на вопросы как в Cassandra (через SPARQL), так и в графовых хранилищах (Neo4j, Memgraph, FalkorDB) (через Cypher). + +**Компоненты сервиса**: +`onto-query-sparql`: Преобразует естественный язык в SPARQL для Cassandra. +`sparql-cassandra`: Слой запросов SPARQL для Cassandra с использованием rdflib. +`onto-query-cypher`: Преобразует естественный язык в Cypher для графовых баз данных. +`cypher-executor`: Выполнение запросов Cypher для Neo4j/Memgraph/FalkorDB. + +### Архитектура + +``` + ┌─────────────────┐ + │ User Query │ + └────────┬────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Question │────▶│ Sentence │ + │ Analyser │ │ Splitter │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Ontology │────▶│ Vector │ + │ Matcher │ │ Store │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Backend Router │ + └────────┬────────┘ + │ + ┌───────────┴───────────┐ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ onto-query- │ │ onto-query- │ + │ sparql │ │ cypher │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ SPARQL │ │ Cypher │ + │ Generator │ │ Generator │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ sparql- │ │ cypher- │ + │ cassandra │ │ executor │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ Cassandra │ │ Neo4j/Memgraph/ │ + │ │ │ FalkorDB │ + └────────┬────────┘ └────────┬────────┘ + │ │ + └────────────┬───────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Answer │────▶│ Prompt │ + │ Generator │ │ Service │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Final Answer │ + └─────────────────┘ +``` + +### Конвейер обработки запросов + +#### 1. Анализатор вопросов + +**Назначение**: Разделяет вопросы пользователей на семантические компоненты для сопоставления с онтологией. + +**Описание алгоритма**: +Анализатор вопросов принимает входящий вопрос на естественном языке и разбивает его на значимые сегменты, используя тот же подход к разделению предложений, что и конвейер извлечения. Он определяет ключевые сущности, отношения и ограничения, упомянутые в вопросе. Каждый сегмент анализируется для определения типа вопроса (фактический, агрегирующий, сравнительный и т. д.) и ожидаемого формата ответа. Это разделение помогает определить, какие части онтологии наиболее релевантны для ответа на вопрос. + +**Основные операции**: +Разделение вопроса на предложения и фразы +Определение типа и намерения вопроса +Извлечение упомянутых сущностей и отношений +Обнаружение ограничений и фильтров в вопросе +Определение ожидаемого формата ответа + +#### 2. Сопоставитель онтологий для запросов + +**Назначение**: Определяет соответствующий подмножество онтологии, необходимое для ответа на вопрос. + +**Описание алгоритма**: +Подобно компоненту Ontology Selector конвейера извлечения, но оптимизирован для ответов на вопросы. Сопоставитель генерирует представления для сегментов вопроса и ищет в векторном хранилище соответствующие элементы онтологии. Однако он фокусируется на поиске концепций, которые будут полезны для построения запросов, а не для извлечения. Он расширяет выбор, включая связанные свойства, которые могут быть пройдены во время исследования графа, даже если они не упоминаются явно в вопросе. Например, если задан вопрос о "сотрудниках", он может включить такие свойства, как "работает в", "управляет" и "отчитывается", которые могут быть релевантны для поиска информации о сотрудниках. + +**Стратегия сопоставления**: +Генерация представлений для сегментов вопроса +Поиск непосредственно упомянутых концепций онтологии +Включение свойств, соединяющих упомянутые классы +Добавление обратных и связанных свойств для обхода +Включение родительских/дочерних классов для иерархических запросов +Создание подмножества онтологии, ориентированного на запросы + +#### 3. Маршрутизатор бэкэнда + +**Назначение**: Маршрутизирует запросы к соответствующему бэкэнду в зависимости от конфигурации. + +**Описание алгоритма**: +Маршрутизатор бэкэнда анализирует системную конфигурацию, чтобы определить, какой бэкэнд графа активен (на базе Cassandra или Cypher). Он направляет вопрос и подмножество онтологии к соответствующему сервису генерации запросов. Маршрутизатор также может поддерживать балансировку нагрузки между несколькими бэкэндами или механизмы отката, если основной бэкэнд недоступен. + +**Логика маршрутизации**: +Проверка настроенного типа бэкэнда из системных настроек +Маршрутизация к `onto-query-sparql` для бэкэндов Cassandra +Маршрутизация к `onto-query-cypher` для Neo4j/Memgraph/FalkorDB +Поддержка конфигураций с несколькими бэкэндами с распределением запросов +Обработка сценариев отката и балансировки нагрузки + +#### 4. Генерация SPARQL-запросов (`onto-query-sparql`) + +**Назначение**: Преобразует вопросы на естественном языке в SPARQL-запросы для выполнения в Cassandra. + +**Описание алгоритма**: +Генератор SPARQL-запросов принимает вопрос и подмножество онтологии и создает SPARQL-запрос, оптимизированный для выполнения в бэкэнде Cassandra. Он использует сервис подсказок со специальной для SPARQL-шаблоном, который включает семантику RDF/OWL. Генератор понимает шаблоны SPARQL, такие как пути свойств, необязательные предложения и фильтры, которые могут эффективно преобразовываться в операции Cassandra. + +**Шаблон подсказки для генерации SPARQL**: +``` +Generate a SPARQL query for the following question using the provided ontology. + +ONTOLOGY CLASSES: +{classes} + +ONTOLOGY PROPERTIES: +{properties} + +RULES: +- Use proper RDF/OWL semantics +- Include relevant prefixes +- Use property paths for hierarchical queries +- Add FILTER clauses for constraints +- Optimise for Cassandra backend + +QUESTION: {question} + +SPARQL QUERY: +``` + +#### 5. Генерация запросов Cypher (`onto-query-cypher`) + +**Назначение**: Преобразует вопросы, сформулированные на естественном языке, в запросы Cypher для графовых баз данных. + +**Описание алгоритма**: +Генератор запросов Cypher создает нативные запросы Cypher, оптимизированные для Neo4j, Memgraph и FalkorDB. Он сопоставляет классы онтологии с метками узлов, а свойства - с отношениями, используя синтаксис сопоставления шаблонов Cypher. Генератор включает в себя оптимизации, специфичные для Cypher, такие как указания направления отношений, использование индексов и указания для планирования запросов. + +**Шаблон запроса Cypher**: +``` +Generate a Cypher query for the following question using the provided ontology. + +NODE LABELS (from classes): +{classes} + +RELATIONSHIP TYPES (from properties): +{properties} + +RULES: +- Use MATCH patterns for graph traversal +- Include WHERE clauses for filters +- Use aggregation functions when needed +- Optimise for graph database performance +- Consider index hints for large datasets + +QUESTION: {question} + +CYPHER QUERY: +``` + +#### 6. Движок запросов SPARQL-Cassandra (`sparql-cassandra`) + +**Назначение**: Выполняет запросы SPARQL к базе данных Cassandra с использованием библиотеки Python rdflib. + +**Описание алгоритма**: +Движок SPARQL-Cassandra реализует обработчик SPARQL с использованием библиотеки rdflib на Python и пользовательского хранилища для Cassandra. Он преобразует графы запросов SPARQL в соответствующие запросы CQL для Cassandra, обрабатывая соединения, фильтры и агрегации. Движок поддерживает отображение RDF в Cassandra, которое сохраняет семантическую структуру, оптимизируя при этом для модели хранения колоночных семей Cassandra. + +**Особенности реализации**: +Реализация интерфейса хранилища rdflib для Cassandra +Поддержка запросов SPARQL 1.1 с распространенными шаблонами +Эффективный перевод шаблонов триплетов в CQL +Поддержка путей свойств и иерархических запросов +Потоковая передача результатов для больших наборов данных +Объединение подключений и кэширование запросов + +**Пример перевода**: +```sparql +SELECT ?animal WHERE { + ?animal rdf:type :Animal . + ?animal :hasOwner "John" . +} +``` +Переводит в оптимизированные запросы Cassandra, использующие индексы и ключи разделения. + +#### 7. Исполнитель запросов Cypher (`cypher-executor`) + +**Назначение**: Выполняет запросы Cypher к базам данных Neo4j, Memgraph и FalkorDB. + +**Описание алгоритма**: +Исполнитель запросов Cypher предоставляет унифицированный интерфейс для выполнения запросов Cypher в различных графовых базах данных. Он обрабатывает специфичные для базы данных протоколы подключения, подсказки для оптимизации запросов и нормализацию формата результатов. Исполнитель включает логику повторных попыток, пулинг соединений и управление транзакциями, соответствующие для каждого типа базы данных. + +**Поддержка нескольких баз данных**: +**Neo4j**: Протокол Bolt, функции транзакций, подсказки для индексов +**Memgraph**: Собственный протокол, потоковая передача результатов, аналитические запросы +**FalkorDB**: Адаптация протокола Redis, оптимизации в памяти + +**Функции выполнения**: +Управление подключениями, независимое от базы данных +Проверка запросов и синтаксический анализ +Применение ограничений по времени ожидания и ресурсам +Пагинация и потоковая передача результатов +Мониторинг производительности для каждого типа базы данных +Автоматическое переключение при отказе между экземплярами базы данных + +#### 8. Генератор ответов + +**Назначение**: Синтезирует ответ на естественном языке на основе результатов запроса. + +**Описание алгоритма**: +Генератор ответов принимает структурированные результаты запроса и исходный вопрос, а затем использует сервис подсказок для генерации всестороннего ответа. В отличие от простых ответов, основанных на шаблонах, он использует LLM для интерпретации данных графа в контексте вопроса, обрабатывая сложные взаимосвязи, агрегации и выводы. Генератор может объяснить свою логику, ссылаясь на структуру онтологии и конкретные тройки, извлеченные из графа. + +**Процесс генерации ответов**: +Форматирование результатов запроса в структурированный контекст +Включение соответствующих определений онтологии для ясности +Создание подсказки с вопросом и результатами +Генерация ответа на естественном языке с помощью LLM +Проверка ответа на соответствие намерению запроса +Добавление ссылок на конкретные сущности графа, если это необходимо + +### Интеграция с существующими сервисами + +#### Взаимодействие с GraphRAG + +**Дополняющие**: onto-query обеспечивает семантическую точность, а GraphRAG обеспечивает широкое покрытие +**Общая инфраструктура**: Оба используют одну и ту же базу знаний и сервисы подсказок +**Маршрутизация запросов**: Система может маршрутизировать запросы к наиболее подходящему сервису в зависимости от типа вопроса +**Гибридный режим**: Можно комбинировать оба подхода для получения всесторонних ответов + +#### Взаимодействие с OntoRAG Extraction + +**Общие онтологии**: Использует одни и те же конфигурации онтологии, загруженные kg-extract-ontology +**Общий векторный магазин**: Повторно использует встроенные представления из сервиса извлечения +**Согласованная семантика**: Запросы выполняются над графами, созданными с использованием одних и тех же онтологических ограничений + +### Примеры запросов + +#### Пример 1: Простой запрос сущности +**Вопрос**: "Какие животные являются млекопитающими?" +**Соответствие онтологии**: [животное, млекопитающее, subClassOf] +**Сгенерированный запрос**: +```cypher +MATCH (a:animal)-[:subClassOf*]->(m:mammal) +RETURN a.name +``` + +#### Пример 2: Запрос взаимосвязей +**Вопрос**: "Какие документы были написаны Джоном Смитом?" +**Соответствие онтологии**: [документ, человек, автор] +**Сгенерированный запрос**: +```cypher +MATCH (d:document)-[:has-author]->(p:person {name: "John Smith"}) +RETURN d.title, d.date +``` + +#### Пример 3: Запрос агрегации +**Вопрос**: "Сколько ног у кошек?" +**Соответствие онтологии**: [кошка, количество_ног (свойство типа данных)] +**Сгенерированный запрос**: +```cypher +MATCH (c:cat) +RETURN c.name, c.number_of_legs +``` + +### Конфигурация + +```yaml +onto-query: + embedding_model: "text-embedding-3-small" + vector_store: + shared_with_extractor: true # Reuse kg-extract-ontology's store + query_builder: + model: "gpt-4" + temperature: 0.1 + max_query_length: 1000 + graph_executor: + timeout: 30000 # ms + max_results: 1000 + answer_generator: + model: "gpt-4" + temperature: 0.3 + max_tokens: 500 +``` + +### Оптимизация производительности + +#### Оптимизация запросов + +**Обрезка онтологии**: Включайте только необходимые элементы онтологии в запросы. +**Кэширование запросов**: Кэшируйте часто задаваемые вопросы и соответствующие запросы. +**Кэширование результатов**: Сохраняйте результаты для идентичных запросов в течение определенного периода времени. +**Пакетная обработка**: Обрабатывайте несколько связанных вопросов в рамках одного обхода графа. + +#### Соображения масштабируемости + +**Распределенное выполнение**: Параллелизуйте подзапросы по разделам графа. +**Инкрементные результаты**: Потоково передавайте результаты для больших наборов данных. +**Балансировка нагрузки**: Распределяйте нагрузку запросов между несколькими экземплярами сервиса. +**Пул ресурсов**: Управляйте пулами соединений к базам данных графов. + +### Обработка ошибок + +#### Сценарии сбоев + +1. **Неправильная генерация запроса**: Переключайтесь на GraphRAG или простой поиск по ключевым словам. +2. **Несоответствие онтологии**: Расширьте поиск до более широкого подмножества онтологии. +3. **Тайм-аут запроса**: Упростите запрос или увеличьте время ожидания. +4. **Отсутствие результатов**: Предложите переформулировать запрос или связанные вопросы. +5. **Сбой сервиса LLM**: Используйте кэшированные запросы или ответы на основе шаблонов. + +### Метрики мониторинга + +Распределение сложности вопросов. +Размеры разделов онтологии. +Успешность генерации запросов. +Время выполнения запросов к графу. +Оценки качества ответов. +Коэффициенты попадания в кэш. +Частота ошибок по типам. + +## Будущие улучшения + +1. **Обучение онтологии**: Автоматически расширяйте онтологии на основе шаблонов извлечения. +2. **Оценка достоверности**: Присваивайте оценки достоверности извлеченным тройкам. +3. **Генерация объяснений**: Предоставляйте обоснование для извлечения троек. +4. **Активное обучение**: Запрашивайте подтверждение человеком для неопределенных извлечений. + +## Соображения безопасности + +1. **Предотвращение внедрения вредоносного кода**: Очищайте текст фрагментов перед построением запроса. +2. **Ограничения ресурсов**: Ограничивайте использование памяти для векторного хранилища. +3. **Ограничение скорости**: Ограничивайте количество запросов на извлечение от каждого клиента. +4. **Журналирование аудита**: Отслеживайте все запросы и результаты извлечения. + +## Стратегия тестирования + +### Модульное тестирование + +Загрузчик онтологии с различными форматами. +Генерация и хранение векторов. +Алгоритмы разбиения предложений. +Расчеты векторного сходства. +Разбор и проверка троек. + +### Интеграционное тестирование + +Комплексная цепочка извлечения. +Интеграция с сервисом конфигурации. +Взаимодействие с сервисом запросов. +Обработка одновременных извлечений. + +### Тестирование производительности + +Обработка больших онтологий (1000+ классов). +Обработка больших объемов фрагментов. +Использование памяти под нагрузкой. +Тесты на задержку. + +## План поставки + +### Обзор + +Система OntoRAG будет поставляться в четыре основные фазы, каждая из которых будет предоставлять постепенную ценность, одновременно создавая полную систему. План сосредоточен на создании основных возможностей извлечения, а затем добавлении функциональности запросов, а также оптимизации и расширенных функций. + +### Фаза 1: Основа и основное извлечение + +**Цель**: Создать базовый конвейер извлечения на основе онтологии с простым векторным сопоставлением. + +#### Шаг 1.1: Основа управления онтологией +Реализовать загрузчик конфигурации онтологии (`OntologyLoader`). +Разбирать и проверять структуры JSON онтологии. +Создать хранилище онтологии в памяти и шаблоны доступа. +Реализовать механизм обновления онтологии. + +**Критерии успеха**: +Успешная загрузка и разбор конфигураций онтологии. +Проверка структуры и согласованности онтологии. +Обработка нескольких одновременных онтологий. + +#### Шаг 1.2: Реализация векторного хранилища +Реализовать простое векторное хранилище на основе NumPy в качестве первоначального прототипа. +Добавить реализацию векторного хранилища FAISS. +Создать абстракцию интерфейса векторного хранилища. +Реализовать поиск по сходству с настраиваемыми порогами. + +**Критерии успеха**: +Эффективное хранение и извлечение эмбеддингов. +Выполнение поиска по схожести с задержкой менее 100 мс. +Поддержка бэкендов NumPy и FAISS. + +#### Шаг 1.3: Конвейер эмбеддингов онтологии +Интеграция с сервисом эмбеддингов. +Реализация компонента `OntologyEmbedder`. +Генерация эмбеддингов для всех элементов онтологии. +Хранение эмбеддингов с метаданными в векторном хранилище. + +**Критерии успеха**: +Генерация эмбеддингов для классов и свойств. +Хранение эмбеддингов с правильными метаданными. +Перегенерация эмбеддингов при обновлениях онтологии. + +#### Шаг 1.4: Компоненты обработки текста +Реализация разбиения на предложения с использованием NLTK/spaCy. +Извлечение фраз и именованных сущностей. +Создание иерархии текстовых сегментов. +Генерация эмбеддингов для текстовых сегментов. + +**Критерии успеха**: +Точное разбиение текста на предложения. +Извлечение значимых фраз. +Сохранение контекстных связей. + +#### Шаг 1.5: Алгоритм выбора онтологии +Реализация сопоставления по схожести между текстом и онтологией. +Создание механизма разрешения зависимостей для элементов онтологии. +Создание минимальных когерентных подмножеств онтологии. +Оптимизация производительности генерации подмножеств. + +**Критерии успеха**: +Выбор релевантных элементов онтологии с точностью >80%. +Включение всех необходимых зависимостей. +Генерация подмножеств менее чем за 500 мс. + +#### Шаг 1.6: Базовый сервис извлечения +Реализация построения запросов для извлечения. +Интеграция с сервисом запросов. +Разбор и проверка ответов в формате триплетов. +Создание конечной точки сервиса `kg-extract-ontology`. + +**Критерии успеха**: +Извлечение триплетов, соответствующих онтологии. +Проверка всех триплетов на соответствие онтологии. +Обработка ошибок извлечения. + +### Фаза 2: Реализация системы запросов + +**Цель**: Добавление возможностей запросов, учитывающих онтологию, с поддержкой нескольких бэкендов. + +#### Шаг 2.1: Базовые компоненты системы запросов +Реализация анализатора вопросов. +Создание сопоставителя онтологии для запросов. +Адаптация векторного поиска для контекста запроса. +Создание компонента маршрутизации бэкендов. + +**Критерии успеха**: +Анализ вопросов на семантические компоненты. +Сопоставление вопросов с релевантными элементами онтологии. +Маршрутизация запросов к соответствующему бэкенду. + +#### Шаг 2.2: Реализация пути SPARQL +Реализация сервиса `onto-query-sparql`. +Создание генератора SPARQL-запросов с использованием LLM. +Разработка шаблонов запросов для генерации SPARQL. +Проверка синтаксиса сгенерированных SPARQL-запросов. + +**Критерии успеха**: +Генерация корректных SPARQL-запросов. +Использование соответствующих шаблонов SPARQL. +Поддержка сложных типов запросов. + +#### Шаг 2.3: Движок SPARQL-Cassandra +Реализация интерфейса хранилища rdflib для Cassandra. +Создание переводчика CQL-запросов. +Оптимизация сопоставления триплетов. +Обработка форматирования результатов SPARQL. + +**Критерии успеха**: +Выполнение SPARQL-запросов на Cassandra. +Поддержка распространенных шаблонов SPARQL. +Возврат результатов в стандартном формате. + +#### Шаг 2.4: Реализация пути Cypher +Реализация сервиса `onto-query-cypher`. +Создание генератора Cypher-запросов с использованием LLM. +Разработка шаблонов запросов для генерации Cypher. +Проверка синтаксиса сгенерированных Cypher-запросов. + +**Критерии успеха**: +Генерация корректных Cypher-запросов. +Использование соответствующих шаблонов графов. +Поддержка Neo4j, Memgraph, FalkorDB. + +#### Шаг 2.5: Исполнитель Cypher +Реализовать многобазовый исполнитель запросов Cypher. +Поддержка протокола Bolt (Neo4j/Memgraph). +Поддержка протокола Redis (FalkorDB). +Обработка нормализации результатов. + +**Критерии успеха**: +Выполнение запросов Cypher на всех целевых базах данных. +Обработка специфических для базы данных различий. +Эффективное управление пулами соединений. + +#### Шаг 2.6: Генерация ответов +Реализовать компонент генерации ответов. +Создать подсказки для синтеза ответов. +Форматировать результаты запросов для использования LLM. +Генерировать ответы на естественном языке. + +**Критерии успеха**: +Генерировать точные ответы на основе результатов запросов. +Сохранять контекст из исходного вопроса. +Предоставлять четкие и лаконичные ответы. + +### Фаза 3: Оптимизация и надежность + +**Цель**: Оптимизировать производительность, добавить кэширование, улучшить обработку ошибок и повысить надежность. + +#### Шаг 3.1: Оптимизация производительности +Реализовать кэширование эмбеддингов. +Добавить кэширование результатов запросов. +Оптимизировать векторный поиск с использованием индексов FAISS IVF. +Реализовать пакетную обработку для эмбеддингов. + +**Критерии успеха**: +Уменьшить среднюю задержку запроса на 50%. +Поддерживать в 10 раз больше одновременных запросов. +Поддерживать время отклика менее 1 секунды. + +#### Шаг 3.2: Продвинутая обработка ошибок +Реализовать комплексное восстановление после ошибок. +Добавить механизмы отката между путями запросов. +Создать логику повторных попыток с экспоненциальной задержкой. +Улучшить ведение журналов ошибок и диагностику. + +**Критерии успеха**: +Грациозно обрабатывать все сценарии сбоев. +Автоматическое переключение на резервные системы. +Подробное сообщение об ошибках для отладки. + +#### Шаг 3.3: Мониторинг и наблюдаемость +Добавить сбор показателей производительности. +Реализовать трассировку запросов. +Создать конечные точки проверки состояния. +Добавить мониторинг использования ресурсов. + +**Критерии успеха**: +Отслеживать все ключевые показатели производительности. +Быстро выявлять узкие места. +Мониторить состояние системы в режиме реального времени. + +#### Шаг 3.4: Управление конфигурацией +Реализовать динамические обновления конфигурации. +Добавить проверку конфигурации. +Создать шаблоны конфигурации. +Поддержка настроек, специфичных для среды. + +**Критерии успеха**: +Обновлять конфигурацию без перезапуска. +Проверять все изменения конфигурации. +Поддерживать несколько сред развертывания. + +### Фаза 4: Продвинутые функции + +**Цель**: Добавить сложные возможности для производственного развертывания и расширенной функциональности. + +#### Шаг 4.1: Поддержка нескольких онтологий +Реализовать логику выбора онтологии. +Поддержка межонтологических запросов. +Обработка версий онтологий. +Создать возможности объединения онтологий. + +**Критерии успеха**: +Выполнять запросы между несколькими онтологиями. +Обрабатывать конфликты онтологий. +Поддерживать эволюцию онтологий. + +#### Шаг 4.2: Интеллектуальная маршрутизация запросов +Реализовать маршрутизацию на основе производительности +Добавить анализ сложности запросов +Создать адаптивные алгоритмы маршрутизации +Поддержка A/B-тестирования для путей + +**Критерии успеха**: +Оптимизировать маршрутизацию запросов +Учиться на основе производительности запросов +Улучшать маршрутизацию со временем + +#### Шаг 4.3: Расширенные функции извлечения +Добавить оценку достоверности для троек +Реализовать генерацию объяснений +Создать механизмы обратной связи для улучшения +Поддержка инкрементного обучения + +**Критерии успеха**: +Предоставлять оценки достоверности +Объяснять решения по извлечению +Постоянно повышать точность + +#### Шаг 4.4: Подготовка к производству +Добавить ограничение скорости +Реализовать аутентификацию/авторизацию +Создать автоматизацию развертывания +Добавить резервное копирование и восстановление + +**Критерии успеха**: +Безопасность, готовая к производству +Автоматизированная цепочка развертывания +Возможность восстановления после сбоев + +### Этапы выполнения + +1. **Этап 1** (Конец Фазы 1): Базовая работа системы извлечения, основанной на онтологии. +2. **Этап 2** (Конец Фазы 2): Полная система запросов с путями SPARQL и Cypher. +3. **Этап 3** (Конец Фазы 3): Оптимизированная, надежная система, готовая к тестированию. +4. **Этап 4** (Конец Фазы 4): Система, готовая к производству, с расширенными функциями. + +### Смягчение рисков + +#### Технические риски +**Масштабируемость векторного хранилища**: Начать с NumPy, постепенно перейти на FAISS. +**Точность генерации запросов**: Реализовать механизмы проверки и резервирования. +**Совместимость с бэкендом**: Тщательно тестировать с каждым типом базы данных. +**Узкие места производительности**: Профилировать и оптимизировать итеративно. + +#### Операционные риски +**Качество онтологии**: Реализовать проверку и контроль согласованности. +**Зависимости от сервисов**: Добавить предохранители и механизмы резервирования. +**Ограничения ресурсов**: Отслеживать и устанавливать соответствующие лимиты. +**Согласованность данных**: Реализовать правильную обработку транзакций. + +### Показатели успеха + +#### Показатели успеха Фазы 1 +Точность извлечения: >90% соответствия онтологии +Скорость обработки: <1 секунды на фрагмент +Время загрузки онтологии: <10 секунд +Задержка векторного поиска: <100 мс + +#### Показатели успеха Фазы 2 +Успешность выполнения запросов: >95% +Задержка запросов: <2 секунды (от начала до конца) +Совместимость с бэкендом: 100% для целевых баз данных +Точность ответов: >85% на основе доступных данных + +#### Показатели успеха Фазы 3 +Время безотказной работы системы: >99.9% +Скорость восстановления после ошибок: >95% +Процент попаданий в кэш: >60% +Количество одновременных пользователей: >100 + +#### Показатели успеха Фазы 4 +Поддержка запросов к нескольким онтологиям: Полная поддержка +Оптимизация маршрутизации: Снижение задержки на 30% +Точность оценки достоверности: >90% +Развертывание в производственной среде: Обновления без простоев + +## Ссылки + +[OWL 2 Web Ontology Language](https://www.w3.org/TR/owl2-overview/) +[GraphRAG Architecture](https://github.com/microsoft/graphrag) +[Sentence Transformers](https://www.sbert.net/) +[FAISS Vector Search](https://github.com/facebookresearch/faiss) +[spaCy NLP Library](https://spacy.io/) +[rdflib Documentation](https://rdflib.readthedocs.io/) +[Neo4j Bolt Protocol](https://neo4j.com/docs/bolt/current/) diff --git a/docs/tech-specs/ontorag.sw.md b/docs/tech-specs/ontorag.sw.md new file mode 100644 index 00000000..d8ba9c1c --- /dev/null +++ b/docs/tech-specs/ontorag.sw.md @@ -0,0 +1,1067 @@ +# OntoRAG: Vigezo vya Kiufundi vya Utaratibu wa Kuchimbua Maarifa na Ufuatiliaji Kulingana na Ontolojia. + +## Muhtasari + +OntoRAG ni mfumo wa kuchimbua maarifa na kufuatilia maswali unaoendeshwa na ontolojia, ambao unaweka vikwazo vikali vya utaratibu wakati wa kuchimbua vipengele vya maarifa kutoka kwa maandishi yasiyo na muundo na wakati wa kufuatilia maswali kwenye grafu ya maarifa iliyoundwa. Kufanana na GraphRAG lakini na vikwazo vya ontolojia rasmi, OntoRAG huhakikisha kwamba vipengele vyote vilivyochimbwa vinafuata miundo iliyobainishwa ya ontolojia na hutoa uwezo wa kufuatilia maswali kwa kuzingatia maana. + +Mfumo hutumia utangamano wa vector ili kuchagua kwa kasi sehemu muhimu za ontolojia kwa ajili ya uchimbaji na operesheni za kufuatilia maswali, na hivyo kuruhusu usindikaji ulioelezwa na unaofaa kwa muktadha huku ukiendelea kudumisha utaratibu wa maana. + +**Jina la Huduma**: `kg-extract-ontology` + +## Malengo + +**Uchimbaji Unaofuata Ontolojia**: Hakikisha kwamba vipengele vyote vilivyochimbwa vinafuata kikamilifu ontolojia zilizopakuliwa. +**Uchaguzi wa Muktadha Unaobadilika**: Tumia embeddings kuchagua sehemu muhimu za ontolojia kwa kila sehemu. +**Utaratibu wa Maana**: Dumu kwa safu za darasa, nyanja/mahusiano ya mali, na vikwazo. +**Usindikaji Wenye Ufanisi**: Tumia maduka ya vector ya ndani kwa utangamano wa haraka wa vipengele vya ontolojia. +**Muundo Unaoweza Kukua**: Unga ontolojia nyingi za wakati mmoja zenye nyanja tofauti. + +## Asili + +Huduma za sasa za kuchimbua maarifa (`kg-extract-definitions`, `kg-extract-relationships`) zinafanya kazi bila vikwazo rasmi, na hivyo zinaweza kuzalisha vipengele ambavyo havifanani au ambavyo havikubaliki. OntoRAG inashughulikia hili kwa: + +1. Kupakua ontolojia rasmi ambazo zinafafanua madarasa na mali halali. +2. Kutumia embeddings kulinganisha yaliyomo katika maandishi na vipengele muhimu vya ontolojia. +3. Kuweka kikwazo kwa uchimbaji ili kuzalisha tu vipengele vinavyofuata ontolojia. +4. Kutoa uthibitisho wa maana wa maarifa yaliyochimbwa. + +Mbinu hii inachanganya unyumbufu wa uchimbaji wa neva na ukakamavu wa uwakilishi rasmi wa maarifa. + +## Muundo wa Kiufundi + +### Muundo + +Mfumo wa OntoRAG una vipengele vifuatavyo: + +``` +┌─────────────────┐ +│ Configuration │ +│ Service │ +└────────┬────────┘ + │ Ontologies + ▼ +┌─────────────────┐ ┌──────────────┐ +│ kg-extract- │────▶│ Embedding │ +│ ontology │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ │ + ▼ ▼ +┌─────────────────┐ ┌──────────────┐ +│ In-Memory │◀────│ Ontology │ +│ Vector Store │ │ Embedder │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Sentence │────▶│ Chunker │ +│ Splitter │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Ontology │────▶│ Vector │ +│ Selector │ │ Search │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Prompt │────▶│ Prompt │ +│ Constructor │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ +│ Triple Output │ +└─────────────────┘ +``` + +### Maelezo ya Vipengele + +#### 1. Mpakuzi wa Ontolojia + +**Madhumuni**: Hupata na huchanganua usanidi wa ontolojia kutoka kwa huduma ya usanidi kwa kutumia sasisho zinazotokana na matukio. + +**Utekelezaji**: +Mpakuzi wa Ontolojia hutumia folyo ya ConfigPush ya TrustGraph ili kupokea sasisho za usanidi wa ontolojia zinazotokana na matukio. Wakati kipengele cha usanidi cha aina ya "ontolojia" kinaongezwa au kihaririwa, mpakuzi hupokea sasisho kupitia folyo ya config-update na huchanganua muundo wa JSON unao na metadata, madarasa, sifa za kitu, na sifa za aina ya data. Ontolojia zilizochanganuliwa hizi huhifadhiwa katika kumbukumbu kama vitu vilivyopangwa ambavyo vinaweza kupatikana kwa urahisi wakati wa mchakato wa uondoaji. + +**Miamala Muhimu**: +Jisajili kwa folyo ya config-update kwa usanidi wa aina ya ontolojia +Changanua muundo wa ontolojia wa JSON katika vitu vya OntologyClass na OntologyProperty +Thibitisha muundo na utangamano wa ontolojia +Hifadhi ontolojia zilizochanganuliwa katika kumbukumbu kwa upatikanaji wa haraka +Shirikisha usindikaji wa kila mtiririko na maduka ya vekta maalum ya mtiririko + +**Mahali pa Utekelezaji**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_loader.py` + +#### 2. Mpakuzi wa Ontolojia + +**Madhumuni**: Huunda ufumbuzi wa vekta kwa vipengele vyote vya ontolojia ili kuwezesha utangamano wa kulinganisha wa kiufundi. + +**Utekelezaji**: +Mpakuzi wa Ontolojia huchakata kila kipengele katika ontolojia zilizopakuliwa (madarasa, sifa za kitu, na sifa za aina ya data) na huunda ufumbuzi wa vekta kwa kutumia huduma ya EmbeddingsClientSpec. Kwa kila kipengele, huunganisha kitambulisho cha kipengele, lebo, na maelezo (maoni) ili kuunda uwakilishi wa maandishi. Maandishi haya yabadilishwa kisha kuwa ufumbuzi wa vekta wa mchemuko mkuu ambao unaonyesha maana yake ya kiufundi. Ufumbuzi huu huhifadhiwa katika duka la vekta la FAISS la kila mtiririko pamoja na metadata kuhusu aina ya kipengele, ontolojia ya chanzo, na ufafanuzi kamili. Mpakuzi hugundua kiotomatiki mchemuko wa ufumbuzi kutoka kwa majibu ya kwanza ya ufumbuzi. + +**Miamala Muhimu**: +Unda uwakilishi wa maandishi kutoka kwa kitambulisho cha kipengele, lebo, na maoni +Zunda ufumbuzi kupitia EmbeddingsClientSpec (ukitumia asyncio.gather kwa usindikaji wa kikundi) +Hifadhi ufumbuzi na metadata kamili katika duka la vekta la FAISS +Indexi kwa ontolojia, aina ya kipengele, na kitambulisho cha kipengele kwa upatikanaji wa ufanisi +Gundua kiotomatiki mchemuko wa ufumbuzi kwa upangaji wa duka la vekta +Shirikisha modeli za ufumbuzi za kila mtiririko na maduka ya vekta yanayojitegemea + +**Mahali pa Utekelezaji**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_embedder.py` + +#### 3. Mchakato wa Nakala (Kigawanyishi Sentensi) + +**Madhumuni**: Huondoa vipande vya nakala katika sehemu ndogo kwa utangamano wa ontolojia. + +**Utekelezaji**: +Mchakato wa Nakala hutumia NLTK kwa utambaji wa sentensi na utambulisho wa POS ili kugawanya vipande vya nakala vinavyoingia katika sentensi. Inashughulikia utangamano wa toleo la NLTK kwa kujaribu kupakua `punkt_tab` na `averaged_perceptron_tagger_eng`, na kutoa nafasi kwa matoleo ya zamani ikiwa ni lazima. Kila kipande cha nakala kigawanywa katika sentensi binafsi ambazo zinaweza kulinganishwa kwa kujitegemea na vipengele vya ontolojia. + +**Miamala Muhimu**: +Gawa nakala katika sentensi kwa kutumia utambaji wa sentensi wa NLTK +Shirikisha utangamano wa toleo la NLTK (punkt_tab vs punkt) +Unda vitu vya TextSegment na nakala na maelezo ya nafasi +Saidia sentensi kamili na vipande vya mtu binafsi + +**Mahali pa Utekelezaji**: `trustgraph-flow/trustgraph/extract/kg/ontology/text_processor.py` + +#### 4. Mchagua wa Ontolojia + +**Madhumuni**: Hutambua sehemu muhimu zaidi ya vipengele vya ontolojia kwa kipande cha sasa cha nakala. + +**Utekelezaji**: +Mchagua wa Ontolojia hufanya utangamano wa kiufundi kati ya sehemu za nakala na vipengele vya ontolojia kwa kutumia utafutaji wa ufanisi wa vekta wa FAISS. Kwa kila sentensi kutoka kwa kipande cha nakala, huunda ufumbuzi na hufuatilia duka la vekta kwa vipengele vya ontolojia vinavyolingana kwa ufanisi kwa kutumia ufanisi wa cosine na kizingiti kinachoweza kusanidiwa (kiasi 0.3). Baada ya kukusanya vipengele vyote muhimu, hufanya utatuzi kamili wa utegemezi: ikiwa darasa lilitajwa, madarasa yake ya wazazi hujumuishwa; ikiwa sifa ilitajwa, madarasa yake ya uwanja na safu huongezwa. Zaidi ya hayo, kwa kila darasa lililochaguliwa, hujumuisha kiotomatiki **sifa zote ambazo zinarejelea darasa hilo** katika uwanja au safu yake. Hii inahakikisha kuwa uondoaji una upatikanaji wa sifa zote muhimu za uhusiano. + +**Operesheni Muhimu**: +Tengeneza embeddings kwa kila sehemu ya maandishi (sentensi) +Fanya utafutaji wa jirani wa karibu (k-nearest neighbor) katika hifadhi ya vector ya FAISS (top_k=10, threshold=0.3) +Tumia kikomo cha ufanano ili kuchuja mechi dhaifu +Tatua utegemezi (madarasa ya wazazi, nyanja, mipaka) +**Jumuisha moja kwa moja sifa zote zinazohusiana na madarasa yaliyochaguliwa** (mechi ya nyanja/mipaka) +Jenga sehemu ndogo ya ontology inayofaa na uhusiano wote unaohitajika +Ondoa vipengele ambavyo huonekana mara nyingi + +**Mahali pa Utendaji**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_selector.py` + +#### 5. Uundaji wa Maagizo + +**Madhumuni**: Huunda maagizo yaliyo na muundo ambayo huongoza LLM ili kuchimbua tu triples zinazolingana na ontology. + +**Utendaji**: +Huduma ya uchimbaji hutumia kiolezo cha Jinja2 kilicho pakuliwa kutoka `ontology-prompt.md` ambayo inaandika sehemu ndogo ya ontology na maandishi kwa uchimbaji wa LLM. Kiolezo hicho huendelea mara kwa mara juu ya madarasa, sifa za vitu, na sifa za aina ya data kwa kutumia sintaksia ya Jinja2, na kuwasilisha kila moja pamoja na maelezo yake, nyanja, mipaka, na uhusiano wa kishati. Maagizo hayo yana sheria kali kuhusu kutumia vipengele vya ontology vilivyotolewa pekee na huomba muundo wa pato la JSON kwa upangaji thabiti. + +**Operesheni Muhimu**: +Tumia kiolezo cha Jinja2 na marudio juu ya vipengele vya ontology +Andika madarasa na uhusiano wa wazazi (subclass_of) na maoni +Andika sifa na vikwazo vya nyanja/mipaka na maoni +Jumuisha sheria wazi za uchimbaji na mahitaji ya muundo wa pato +Piga simu huduma ya maagizo na kitambulisho cha kiolezo "extract-with-ontologies" + +**Mahali pa Kiolezo**: `ontology-prompt.md` +**Mahali pa Utendaji**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` (mbinu ya build_extraction_variables) + +#### 6. Huduma Kuu ya Uchimbaji + +**Madhumuni**: Inadhihirisha vipengele vyote ili kufanya uchimbaji kamili wa triples kulingana na ontology. + +**Utendaji**: +Huduma Kuu ya Uchimbaji (KgExtractOntology) ni safu ya upangaji ambayo inasimamia mtiririko kamili wa uchimbaji. Inatumia mtindo wa TrustGraph's FlowProcessor na usanidi wa kila mtiririko. Wakati sasisho la usanidi wa ontology linapofika, inaanzisha au inasasisha vipengele vya mtiririko (mji wa ontology, mchimbaji, mchakato wa maandishi, mchagua). Wakati kipande cha maandishi kinapofika kwa uchunguzi, inadhihirisha mstari wa kazi: kugawanya maandishi katika sehemu, kutafuta vipengele muhimu vya ontology kupitia utafutaji wa vector, kuunda maagizo ya kikomo, kupiga simu huduma ya maagizo, kuchanganua na kuthibitisha jibu, kuunda triples za ufafanuzi wa ontology, na kutoa triples za yaliyomo na mandhari ya vitu. + +**Mstari wa Kazi wa Uchimbaji**: +1. Pokea kipande cha maandishi kupitia folyo ya chunks-input +2. Anzisha vipengele vya mtiririko ikiwa ni lazima (kwa kipande cha kwanza au sasisho la usanidi) +3. Gawa maandishi katika sentensi kwa kutumia NLTK +4. Tafuta hifadhi ya vector ya FAISS ili kupata dhana muhimu za ontology +5. Jenga sehemu ndogo ya ontology na ujumuishaji wa moja kwa moja wa sifa +6. Jenga mbadala wa Jinja2-templated +7. Piga simu huduma ya maagizo na kiolezo cha extract-with-ontologies +8. Changanisha jibu la JSON katika triples zilizopangwa +9. Thibitisha triples na upanue URI hadi URI kamili ya ontology +10. Jenga triples za ufafanuzi wa ontology (madarasa na sifa na lebo/maoni/nyanja/mipaka) +11. Jenga mandhari ya vitu kutoka kwa triples zote +12. Toa kwa folyo za triples na entity-contexts + +**Vipengele Muhimu**: +Hifadhi za vector za kila mtiririko inayounga mkono modeli tofauti za uchimbaji +Sasisho ya ontology iliyoendeshwa na tukio kupitia folyo ya config-update +Upanuzi wa moja kwa moja wa URI kwa kutumia URI za ontology +Vipengele vya ontology vilivyoongezwa kwenye grafu ya maarifa na metadata kamili +Mandhari ya vitu inajumuisha vipengele vya yaliyomo na ontology + +**Mahali pa Utendaji**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` + +### Usanidi + +Huduma hutumia mbinu ya kawaida ya usanidi ya TrustGraph na hoja za mstari wa amri: + +```bash +kg-extract-ontology \ + --id kg-extract-ontology \ + --pulsar-host localhost:6650 \ + --input-queue chunks \ + --config-input-queue config-update \ + --output-queue triples \ + --entity-contexts-output-queue entity-contexts +``` + +**Vigezo Muhimu vya Usanidi**: +`similarity_threshold`: 0.3 (kiwango chachilia, kinaweza kusanidiwa katika programu) +`top_k`: 10 (idadi ya vipengele vya ontolojia ambavyo vitapatikana kwa kila sehemu) +`vector_store`: FAIISS IndexFlatIP kwa kila mtiririko na vipimo ambavyo vitapatikana kiotomatiki +`text_processor`: NLTK na utambuzi wa sentensi ya punkt_tab +`prompt_template`: "extract-with-ontologies" (template ya Jinja2) + +**Usanidi wa Ontolojia**: +Ontolojia huzamilishwa moja kwa moja kupitia folyo ya config-update yenye aina="ontology". + +### Mtiririko wa Data + +1. **Awamu ya Uanzishaji** (kwa kila mtiririko): + Pokea usanidi wa ontolojia kupitia folyo ya config-update + Changanua JSON ya ontolojia katika vitu vya OntologyClass na OntologyProperty + Zizalisha embeddings kwa vipengele vyote vya ontolojia kwa kutumia EmbeddingsClientSpec + Hifadhi embeddings katika duka la vector la FAISS kwa kila mtiririko + Gundua vipimo vya embedding kutoka kwa majibu ya kwanza + +2. **Awamu ya Utoaji** (kwa kila sehemu): + Pokea sehemu kutoka kwa folyo ya chunks-input + Gawanya sehemu katika sentensi kwa kutumia NLTK + Hesabu embeddings kwa kila sentensi + Tafuta duka la vector la FAISS kwa vipengele muhimu vya ontolojia + Unda subset ya ontolojia na ujumuishaji wa kiotomatiki wa sifa + Unda vigezo vya template ya Jinja2 na maandishi na ontolojia + Piga huduma ya prompt na template ya extract-with-ontologies + Changanisha majibu ya JSON na uthibitishe triples + Panua URIs kwa kutumia URIs za ontolojia + Zizalisha triples za ufafanuzi wa ontolojia + Unda muktadha wa vitu kutoka kwa triples zote + Tuma kwa folyo za triples na entity-contexts + +### Duka la Vector la Kumbukumbu + +**Madhumuni**: Hutoa utafutaji wa haraka wa ufanano, unaotegemea kumbukumbu kwa utangamano wa vipengele vya ontolojia. + +**Utekelezaji: FAISS** + +Mfumo hutumia **FAISS (Facebook AI Similarity Search)** na IndexFlatIP kwa utafutaji wa usawa wa cosine. Vipengele muhimu: + +**IndexFlatIP**: Utafutaji wa usawa wa cosine kwa kutumia bidhaa ya ndani +**Uugunduzi wa kiotomatiki**: Vipimo vinatambuliwa kutoka kwa majibu ya kwanza ya embedding +**Maduka ya kila mtiririko**: Kila mtiririko una duka la vector linalojitegemea kwa modeli tofauti za embedding +**Urekebishaji**: Vector zote zimefanywa kuwa sawa kabla ya kuingizwa +**Operesheni za kundi**: Kuongeza kikundi kwa upakiaji wa awali wa ontolojia + +**Mahali pa Utekelezaji**: `trustgraph-flow/trustgraph/extract/kg/ontology/vector_store.py` + +### Algoritimu ya Uchaguzi wa Subset ya Ontolojia + +**Madhumuni**: Inachagua kwa moja kwa moja sehemu muhimu zaidi ya ontolojia kwa kila sehemu ya maandishi. + +**Hatua za Algoritimu**: + +1. **Umgawaji wa Maandishi**: + Gawa sehemu ya pembeni katika sentensi kwa kutumia utambuzi wa sentensi ya NLP + Toa maneno muhimu, maneno muhimu, na vitu vilivyotajwa kutoka kwa kila sentensi + Unda muundo wa kishati wa sehemu ukiendeleza muktadha + +2. **Uzalishaji wa Embedding**: + Zizalisha embeddings ya vector kwa kila sehemu ya maandishi (sentensi na maneno) + Tumia modeli sawa ya embedding kama ilivyotumika kwa vipengele vya ontolojia + Hifadhi embeddings kwa sehemu zinazorudiwa ili kuboresha utendaji + +3. **Utafiti wa Ufanano**: + Kwa kila embedding ya sehemu ya maandishi, tafuta duka la vector + Rudisha vipengele 10 bora (e.g., 10) vinavyofanana na ontolojia + Tumia kizuia cha ufanano (e.g., 0.7) kuchuja mechi dhaifu + Jumuisha matokeo kote katika sehemu zote, ukihesabu masafa ya mechi + +4. **Suluhisho la Utendaji**: + Kwa kila darasa lililochaguliwa, jumuisha madarasa yote ya wazazi hadi mizizi + Kwa kila sifa iliyochaguliwa, jumuisha madarasa yake ya uwanja na upeo + Kwa sifa za kinyume, hakikisha kuwa mwelekeo wote wamejumuishwa + Ongeza madarasa sawa ikiwa zipo katika ontolojia + +5. **Uundaji wa Subset**: + Ondoa vipengele vilivyo na marudio huku ukiendeleza uhusiano + Panga katika madarasa, sifa za kitu, na sifa za aina ya data + Hakikisha kuwa vikwazo vyote na uhusiano vimehifadhiwa + Unda mini-ontolojia inayojitegemea ambayo ni halali na kamili + +**Mfano wa Uelekezaji**: +Ikiwa kuna maandishi: "Mbwa mweusi alimfuatilia paka mweupe kwenye mti." +Sehemu: ["mbwa mweusi", "paka mweupe", "mti", "alifuatilia"] +Vipengele vilivyolingana: [mbwa (darasa), paka (darasa), wanyama (mzazi), hufuatia (sifa)] +Utendaji: [wanyama (mzazi wa mbwa na paka), viumbehai (mzazi wa wanyama)] +Subset ya mwisho: Mini-ontolojia kamili na hierarkia ya wanyama na uhusiano wa kufuatilia + +### Uthibitisho wa Triples + +**Madhumuni**: Inahakikisha kwamba triples zote zilizotolewa zinaendana kikamilifu na vikwazo vya ontolojia. + +**Algoritimu ya Uthibitisho**: + +1. **Uthibiti wa Darasa**: + Hakikisha kwamba vitu ni mifano ya madarasa yaliyoundwa katika sehemu ya ontolojia. + Kwa sifa za vitu, hakikisha kwamba vitu pia ni mifano halali ya madarasa. + Angalia majina ya madarasa dhidi ya kamusi ya madarasa ya ontolojia. + Shirudia safu za madarasa - mifano ya madarasa ya chini yanafaa kwa sheria za darasa kuu. + +2. **Uthibiti wa Sifa**: + Thibitisha kwamba manukuu yanalingana na sifa katika sehemu ya ontolojia. + Tofautisha kati ya sifa za vitu (kitu hadi kitu) na sifa za aina ya data (kitu hadi literal). + Hakikisha kwamba majina ya sifa yanalingana kabisa (kikumbukie nafasi ikiwa ipo). + +3. **Uchunguzi wa Doman/Safu**: + Kwa kila sifa inayotumika kama manukuu, pata domania na safu yake. + Hakikisha kwamba aina ya kitu inalingana au inameridia aina ya domania ya sifa. + Hakikisha kwamba aina ya kitu inalingana au inameridia aina ya safu ya sifa. + Kwa sifa za aina ya data, hakikisha kwamba kitu ni literal ya aina ya XSD inayofaa. + +4. **Uthibiti wa Idadi**: + Fuatilia idadi ya matumizi ya sifa kwa kila kitu. + Angalia idadi ya chini - hakikisha kwamba sifa zinazohitajika zipo. + Angalia idadi ya juu - hakikisha kwamba sifa haitumiki mara nyingi sana. + Kwa sifa za kazi, hakikisha kwamba kuna thamani moja tu kwa kila kitu. + +5. **Uthibiti wa Aina ya Data**: + Tafsiri maadili ya literal kulingana na aina zao zilizotangazwa za XSD. + Thibitisha kwamba nambari za integer ni nambari halali, tarehe zinaumbwa vizuri, n.k. + Angalia muundo wa maandishi ikiwa sheria za regex zimefafuliwa. + Hakikisha kwamba URI zimeumbwa vizuri kwa aina za xsd:anyURI. + +**Mfano wa Uthibiti**: +Kifurushi: ("Buddy", "ana-miliki", "John") +Angalia kwamba "Buddy" imewekwa kama darasa ambalo linaweza kuwa na sifa ya "ana-miliki". +Angalia kwamba "ana-miliki" ipo katika ontolojia. +Thibitisha sheria ya domania: kitu lazima kiwe cha aina ya "Mbwa" au darasa la chini. +Thibitisha sheria ya safu: kitu lazima kiwe cha aina ya "Mtu" au darasa la chini. +Ikiwa halali, iongeze kwenye pato; ikiwa halali, rekodi ukiukaji na epuka. + +## Mlinganisho wa Utendaji + +### Mikakati ya Ubora + +1. **Uficha wa Kuweka**: Hifadhi maadili yaliyowekwa kwa sehemu za maandishi ambazo hutumiwa mara kwa mara. +2. **Uchakataji wa Kundi**: Chakata sehemu nyingi kwa wakati mmoja. +3. **Ufichuaji wa Faharasa**: Tumia algorimu za jirani za karibu za takriban kwa ontolojia kubwa. +4. **Uboreshaji wa Ombi**: Punguza saizi ya ombi kwa kujumuisha tu vipengele muhimu vya ontolojia. +5. **Uficha wa Matokeo**: Hifadhi matokeo ya uondoaji kwa vipande sawa. + +### Urahisi + +**Upanuzi wa Afakasi**: Mifumo mingi ya utoaji inayoshiriki kumbukumbu ya ontolojia. +**Umgawanyaji wa Ontolojia**: Gawanya ontolojia kubwa kwa kulingana na eneo. +**Uchakataji wa Msururu**: Chakata vipande kadri vinavyofika bila kuunganisha. +**Usimamizi wa Kumbukumbu**: Usafishaji wa mara kwa mara wa vipimo visivyotumika. + +## Usimamizi wa Madosa + +### Hali za Kushindwa + +1. **Ontolojia Zinazokosekana**: Tumia utoaji usio na kikomo. +2. **Ushindwa wa Huduma ya Vipimo**: Tumia vipimo vilivyohifadhiwa au epuka utoaji wa maana. +3. **Kutofa kwa Huduma ya Maagizo**: Jaribu tena kwa kuongeza muda polepole. +4. **Muundo Usio sahihi wa Triples**: Rekodi na epuka triples zilizoharibika. +5. **Utangamano wa Ontolojia**: Ripoti migogoro na tumia vipengele sahihi zaidi. + +### Ufuatiliaji + +Vipimo muhimu vya kufuatilia: + +Muda wa kupakia ontolojia na matumizi ya kumbukumbu. +Muda wa kuunda vipimo. +Utendaji wa utafutaji wa vector. +Muda wa majibu ya huduma ya maagizo. +Usahihi wa utoaji wa triples. +Kiwango cha utangamano wa ontolojia. + +## Njia ya Uhamishaji + +### Kutoka kwa Vifaa vya Utoaji Vilivyopo + +1. **Uendeshaji Sambamba**: Endesha pamoja na vifaa vya utoaji vilivyopo awali. +2. **Upanuzi Polepole**: Anzisha na aina mahususi za hati. +3. **Ulinganisho wa Ubora**: Linganisha ubora wa matokeo na vifaa vya utoaji vilivyopo. +4. **Uhamisho Kamili**: Badilisha vifaa vya utoaji vilivyopo baada ya ubora kuthibitishwa. + +### Maendeleo ya Ontolojia + +1. **Anzisha kutoka kwa Vipengele Vilivyopo**: Unda ontolojia za awali kutoka kwa maarifa iliyopo. +2. **Uboreshaji wa Mara kwa Mara**: Boresha kulingana na mifumo ya utoaji. +3. **Uhakiki wa Mtaalamu wa Lugha**: Thibitisha na wataalamu wa somo. +4. **Uboreshaji Unaoendelea**: Sasisha kulingana na maoni ya utoaji. + +## Huduma ya Uulizaje inayohusiana na Ontolojia + +### Maelezo + +Huduma ya uulizaje inayohusiana na ontolojia hutoa njia nyingi za uulizaje ili kusaidia hifadhi tofauti za grafu. Inatumia maarifa ya ontolojia kwa majibu sahihi na ya maana ya maswali katika hifadhi za Cassandra (kupitia SPARQL) na hifadhi za grafu zinazotumia Cypher (Neo4j, Memgraph, FalkorDB). + +**Vipengele vya Huduma**: +`onto-query-sparql`: Hubadilisha lugha ya asili kuwa SPARQL kwa Cassandra. +`sparql-cassandra`: Safu ya uulizaje ya SPARQL kwa Cassandra inayotumia rdflib. +`onto-query-cypher`: Hubadilisha lugha ya asili kuwa Cypher kwa hifadhi za grafu. +`cypher-executor`: Utendeshaji wa uulizaje wa Cypher kwa Neo4j/Memgraph/FalkorDB. + +### Usanifu + +``` + ┌─────────────────┐ + │ User Query │ + └────────┬────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Question │────▶│ Sentence │ + │ Analyser │ │ Splitter │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Ontology │────▶│ Vector │ + │ Matcher │ │ Store │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Backend Router │ + └────────┬────────┘ + │ + ┌───────────┴───────────┐ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ onto-query- │ │ onto-query- │ + │ sparql │ │ cypher │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ SPARQL │ │ Cypher │ + │ Generator │ │ Generator │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ sparql- │ │ cypher- │ + │ cassandra │ │ executor │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ Cassandra │ │ Neo4j/Memgraph/ │ + │ │ │ FalkorDB │ + └────────┬────────┘ └────────┬────────┘ + │ │ + └────────────┬───────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Answer │────▶│ Prompt │ + │ Generator │ │ Service │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Final Answer │ + └─────────────────┘ +``` + +### Mchakato wa Uchunguzi wa Maswali + +#### 1. Mchambuzi wa Maswali + +**Madhumuni**: Huainisha maswali ya mtumiaji katika vipengele vya maana kwa ajili ya utangamano wa ontolojia. + +**Maelezo ya Algoritimu**: +Mchambuzi wa Maswali huchukua swali la lugha ya asili ambalo limeingia na hulifanya iwe sehemu za maana kwa kutumia mbinu sawa ya ugawaji wa sentensi kama ilivyo kwenye mchakato wa uondoaji. Hutambua vitu, uhusiano, na vikwazo muhimu ambavyo yameelezwa katika swali. Kila sehemu inachambuliwa kwa aina ya swali (ukweli, jumlisho, kulinganisha, n.k.) na muundo unaotarajiwa wa jibu. Uainishaji huu husaidia kutambua sehemu zipi za ontolojia ambazo ni muhimu zaidi kwa kujibu swali. + +**Utendaji Muhimu**: +Gawa swali katika sentensi na maneno +Tambua aina na nia ya swali +Toa vitu na uhusiano uliotajwa +Gundua vikwazo na vichujio katika swali +Tambua muundo unaotarajiwa wa jibu + +#### 2. Kichunguzi cha Ontolojia kwa Maswali + +**Madhumuni**: Hutambua sehemu muhimu ya ontolojia inayohitajika kujibu swali. + +**Maelezo ya Algoritimu**: +Kichunguzi hiki ni kama Kichunguzi cha Ontolojia katika mchakato wa uondoaji, lakini kimeboreshwa kwa ajili ya kujibu maswali. Kichunguzi hicho hutengeneza maandishi (embeddings) kwa sehemu za swali na kutafuta katika hifadhi ya maandishi vipengele muhimu vya ontolojia. Hata hivyo, linazingatia kutafuta dhana ambazo zitakuwa muhimu kwa uundaji wa swali badala ya uondoaji. Huongeza uteuzi ili kujumuisha sifa zinazohusiana ambazo zinaweza kuvinjwa wakati wa uchunguzi wa grafu, hata kama hazijaelezwa wazi katika swali. Kwa mfano, ikiwa swali ni kuhusu "wafanyakazi," linaweza kujumuisha sifa kama vile "hufanya kazi kwa," "husaidia," na "huripoti kwa" ambazo zinaweza kuwa muhimu kwa kupata habari kuhusu wafanyakazi. + +**Mbinu ya Ulinganisho**: +Tengeneza maandishi ya sehemu za swali +Tafuta dhana za ontolojia zilizotajwa moja kwa moja +Jumuisha sifa zinazounganisha madarasa yaliyotajwa +Ongeza sifa za kinyume na zinazohusiana kwa ajili ya uvinjaji +Jumuisha madarasa ya wazazi/watoto kwa maswali ya kishirikina +Unda sehemu ya ontolojia iliyo na umakini wa swali + +#### 3. Kijaribu cha Nyuma (Backend Router) + +**Madhumuni**: Hupeleka maswali kwenye njia inayofaa ya utekelezaji wa swali kulingana na usanidi. + +**Maelezo ya Algoritimu**: +Kijaribu cha Nyuma huchunguza usanidi wa mfumo ili kubaini ambayo ya mifumo ya nyuma (backends) inafanya kazi (Cassandra au Cypher-based). Hupeleka swali na sehemu ya ontolojia kwenye huduma inayofaa ya uundaji wa swali. Kijaribu hicho pia kinaweza kusaidia usambazaji wa maswali kwenye mifumo ya nyuma mingi au mitaratibu ya dharura ikiwa mfumo wa nyuma mkuu haupatikani. + +**Mantiki ya Upelekeshaji**: +Angalia aina ya mfumo wa nyuma iliyosanidiwa kutoka kwa mipangilio ya mfumo +Peleka kwenye `onto-query-sparql` kwa mifumo ya nyuma ya Cassandra +Peleka kwenye `onto-query-cypher` kwa Neo4j/Memgraph/FalkorDB +Saidia usanidi wa mifumo ya nyuma mingi na usambazaji wa maswali +Shirikisha matukio ya dharura na usambazaji wa maswali + +#### 4. Uundaji wa Swali la SPARQL (`onto-query-sparql`) + +**Madhumuni**: Hubadilisha maswali ya lugha ya asili kuwa maswali ya SPARQL kwa utekelezaji katika Cassandra. + +**Maelezo ya Algoritimu**: +Mgenuzi wa swali la SPARQL huchukua swali na sehemu ya ontolojia na huunda swali la SPARQL lililoboreshwa kwa utekelezaji katika mfumo wa nyuma wa Cassandra. Hutumia huduma ya maagizo (prompt) na kiolezo maalum cha SPARQL ambacho kinajumuisha maana ya RDF/OWL. Mgenuzi hufahamu muundo wa SPARQL kama vile njia za sifa, vifungu vya hiari, na vichujio ambavyo vinaweza kubadilishwa kwa ufanisi katika operesheni za Cassandra. + +**Kiolezo cha Maagizo ya Uundaji wa SPARQL**: +``` +Generate a SPARQL query for the following question using the provided ontology. + +ONTOLOGY CLASSES: +{classes} + +ONTOLOGY PROPERTIES: +{properties} + +RULES: +- Use proper RDF/OWL semantics +- Include relevant prefixes +- Use property paths for hierarchical queries +- Add FILTER clauses for constraints +- Optimise for Cassandra backend + +QUESTION: {question} + +SPARQL QUERY: +``` + +#### 5. Uzalishaji wa Uliza wa Cypher (`onto-query-cypher`) + +**Madhumuni**: Hubadilisha maswali ya lugha ya asili kuwa uliza za Cypher kwa hifadhidata za grafu. + +**Maelezo ya Algoritimu**: +Mzalishaji wa uliza wa Cypher huunda uliza za Cypher ambazo zimeboreshwa kwa Neo4j, Memgraph, na FalkorDB. Huunganisha madarasa ya ontolojia na lebo za node na sifa na uhusiano, kwa kutumia sintaksia ya utambuzi wa Cypher. Mzalishaji unajumuisha maboresho maalum ya Cypher kama vile vidokezo vya mwelekeo wa uhusiano, matumizi ya fahirisi, na vidokezo vya upangaji wa uliza. + +**Sampuli ya Kiolezo ya Kuomba Uliza wa Cypher**: +``` +Generate a Cypher query for the following question using the provided ontology. + +NODE LABELS (from classes): +{classes} + +RELATIONSHIP TYPES (from properties): +{properties} + +RULES: +- Use MATCH patterns for graph traversal +- Include WHERE clauses for filters +- Use aggregation functions when needed +- Optimise for graph database performance +- Consider index hints for large datasets + +QUESTION: {question} + +CYPHER QUERY: +``` + +#### 6. Injini ya Ufuatiliaji wa SPARQL-Cassandra (`sparql-cassandra`) + +**Madhumuni**: Inafanya kazi ya utekelezaji wa maswali ya SPARQL dhidi ya Cassandra kwa kutumia Python rdflib. + +**Maelezo ya Algoritimu**: +Injini ya SPARQL-Cassandra inatekeleza kichakataji cha SPARQL kwa kutumia maktaba ya Python's rdflib pamoja na hifadhi maalum ya Cassandra. Inatengeneza mifumo ya grafu ya SPARQL kuwa maswali ya CQL ya Cassandra, huku ikiwezesha uunganisho, vichujio, na jumlishaji. Injini hii inahifadhi uhusiano kati ya RDF na Cassandra ambao unahifadhi muundo wa maana huku ukiwezesha utendakazi bora kwa mfumo wa uhifadhi wa safu za Cassandra. + +**Vipengele vya Utendakazi**: +Utendakazi wa interface ya rdflib kwa Cassandra +Usaidizi wa maswali ya SPARQL 1.1 pamoja na mifumo ya kawaida +Tafsiri bora ya mifumo ya tatu kuwa CQL +Usaidizi wa njia za mali na maswali ya kimtindo +Uhamisho wa matokeo kwa data kubwa +Uunganishaji wa kikao na kuhifadhi maswali + +**Mfano wa Tafsiri**: +```sparql +SELECT ?animal WHERE { + ?animal rdf:type :Animal . + ?animal :hasOwner "John" . +} +``` +Huuandika maswali bora ya Cassandra kwa kutumia fahirisi na funguo za partition. + +#### 7. Mfumo wa Utendaji wa Maswali ya Cypher (`cypher-executor`) + +**Madhumuni**: Hufanya maswali ya Cypher dhidi ya Neo4j, Memgraph, na FalkorDB. + +**Maelezo ya Algoritimu**: +Mfumo wa utendaji wa Cypher hutoa kiolesura cha pamoja kwa kutekeleza maswali ya Cypher katika hifadhi tofauti za data za grafu. Inashughulikia itifaki maalum za muunganisho wa hifadhidata, vidokezo vya uboreshaji wa maswali, na utaratibu wa kawaida wa umbizo wa matokeo. Mfumo huu unajumuisha utaratibu wa kujaribu tena, udhibiti wa muunganisho, na usimamizi wa miamala unaofaa kwa kila aina ya hifadhidata. + +**Usaidizi wa Hifadhidata Mbalimbali**: +**Neo4j**: Itifaki ya Bolt, kazi za miamala, vidokezo vya fahirisi +**Memgraph**: Itifaki maalum, matokeo ya utiririshaji, maswali ya uchambuzi +**FalkorDB**: Marekebisho ya itifaki ya Redis, uboreshaji wa kumbukumbu + +**Vipengele vya Utendaji**: +Usimamizi wa muunganisho usio tegemea hifadhidata +Uthibitisho wa maswali na ukaguzi wa sintaksia +Utumiaji wa muda na vikwazo vya rasilimali +Urekebishaji na utiririshaji wa matokeo +Ufuatiliaji wa utendaji kwa kila aina ya hifadhidata +Uhamisho wa kiotomatiki kati ya mifano ya hifadhidata + +#### 8. Mjenzi wa Majibu + +**Madhumuni**: Huunda jibu la lugha ya asili kutoka kwa matokeo ya maswali. + +**Maelezo ya Algoritimu**: +Mjenzi wa Majibu huchukua matokeo ya maswali yaliyopangwa na swali la awali, kisha hutumia huduma ya matangazo ili kuunda jibu kamili. Tofauti na majibu rahisi yanayotegemea vipengele, hutumia LLM (Large Language Model) ili kuchambua data ya grafu katika muktadha wa swali, na kushughulikia uhusiano tata, jumlisho, na utabiri. Mjenzi anaweza kueleza hoja zake kwa kurejelea muundo wa ontolojia na triples maalum zilizopatikana kutoka kwa grafu. + +**Mchakato wa Uundaji wa Majibu**: +Huunda matokeo ya maswali katika muktadha uliopangwa +Jumuisha maelezo muhimu ya ontolojia kwa uwazi +Unda matangazo na swali na matokeo +Huunda jibu la lugha ya asili kupitia LLM +Thibitisha jibu dhidi ya nia ya swali +Ongeza marejeleo kwa vitu maalum vya grafu ikiwa inahitajika + +### Uunganisho na Huduma Zilizopo + +#### Uhusiano na GraphRAG + +**Inakamilisha**: onto-query hutoa usahihi wa semantic huku GraphRAG hutoa matoleo mapana +**Infrastraki Iliyoshiriki**: Zote mbili hutumia grafu ya maarifa na huduma sawa za matangazo +**Uelekezaji wa Maswali**: Mfumo unaweza kuelekeza maswali kwa huduma inayofaa zaidi kulingana na aina ya swali +**Njia ya Mchanganyiko**: Inaweza kuchanganya mbinu zote mbili kwa majibu kamili + +#### Uhusiano na Utoaji wa OntoRAG + +**Ontolojia Zilizoshiriki**: Hutumia mipangilio sawa ya ontolojia iliyopakuliwa na kg-extract-ontology +**Hifadhi ya Vector Iliyoshiriki**: Inatumia embeddings za kumbukumbu kutoka kwa huduma ya uundaji +**Semantics Sawa**: Maswali hufanya kazi kwenye grafu zilizojengwa na vikwazo sawa vya ontolojia + +### Mifano ya Maswali + +#### Mfano 1: Swali la Kieleleku +**Swali**: "Wanyama gani ni wanyamapori?" +**Ulinganisho wa Ontolojia**: [wanyama, wanyamapori, subClassOf] +**Swali Lililoundwa**: +```cypher +MATCH (a:animal)-[:subClassOf*]->(m:mammal) +RETURN a.name +``` + +#### Mfano wa 2: Ulinganisho wa Maswali +**Swali**: "Ni nyaraka zipi ambazo ziliandikwa na John Smith?" +**Ulinganisho wa Dhana**: [hati, mtu, aliyeandika] +**Swali Lililoundwa**: +```cypher +MATCH (d:document)-[:has-author]->(p:person {name: "John Smith"}) +RETURN d.title, d.date +``` + +#### Mfano wa 3: Uchunguzi wa Uunganishaji +**Swali**: "Paka wana miguu mingapi?" +**Ulinganisho wa Dhana**: [paka, idadi-ya-miguu (sifa ya aina ya data)] +**Uchunguzi Ulioundwa**: +```cypher +MATCH (c:cat) +RETURN c.name, c.number_of_legs +``` + +### Usanidi + +```yaml +onto-query: + embedding_model: "text-embedding-3-small" + vector_store: + shared_with_extractor: true # Reuse kg-extract-ontology's store + query_builder: + model: "gpt-4" + temperature: 0.1 + max_query_length: 1000 + graph_executor: + timeout: 30000 # ms + max_results: 1000 + answer_generator: + model: "gpt-4" + temperature: 0.3 + max_tokens: 500 +``` + +### Uboreshaji wa Utendaji + +#### Uboreshaji wa Maswali + +**Uondoo wa Ontolojia**: Jumuisha tu vipengele muhimu vya ontolojia katika maagizo. +**Kuhifadhi Maswali Yanayoulizwa Mara kwa Mara**: Hifadhi maswali yanayoulizwa mara kwa mara na maswali yao. +**Kuhifadhi Matokeo**: Hifadhi matokeo kwa maswali sawa ndani ya muda maalum. +**Uchakataji wa Kundi**: Shughulikia maswali mengi yanayohusiana katika utafutaji mmoja wa chati. + +#### Masuala ya Ukuaji + +**Utendakazi Uliohusishwa**: Panga maswali madogo katika sehemu tofauti za chati. +**Matokeo ya Kuongezeka**: Tuma matokeo kwa data kubwa. +**Usawa wa Mizigo**: Sogeza mzigo wa maswali katika huduma tofauti. +**Makundi ya Rasilimali**: Dhibiti makundi ya muunganisho kwa hifadhia za chati. + +### Usimamizi wa Madhira + +#### Hali za Kushindwa + +1. **Uundaji Usiofaa wa Swali**: Rudi kwenye GraphRAG au utafutaji rahisi wa neno. +2. **Utangamano Usiofaa wa Ontolojia**: Panua utafutaji hadi sehemu pana ya ontolojia. +3. **Kukata Tamaa kwa Swali**: Rahisisha swali au ongeza muda wa kutuma. +4. **Matokeo Nyembamba**: Pendekeza marekebisho ya swali au maswali yanayohusiana. +5. **Kushindwa kwa Huduma ya LLM**: Tumia maswali yaliyohifadhiwa au majibu ya msingi ya kigeuzi. + +### Viashiria vya Ufuatiliaji + +Usambazaji wa ugumu wa swali. +Ukubwa wa sehemu za ontolojia. +Kiwango cha mafanikio ya uundaji wa swali. +Muda wa utekelezaji wa swali la chati. +Alama za ubora wa jibu. +Viwango vya kufanikiwa kwa uhifadhi. +Masafa ya madhira kwa aina. + +## Uboresho wa Baadaye + +1. **Ujifunzaji wa Ontolojia**: Panua ontolojia moja kwa moja kulingana na mifumo ya uundaji. +2. **Upeo wa Umoja**: Toa alama za umoja kwa vipengele vilivyoundwa. +3. **Uundaji wa Maelezo**: Toa sababu kwa uundaji wa vipengele. +4. **Ujifunzaji Kamili**: Omba uthibitisho wa binadamu kwa uundaji usio wa uhakika. + +## Masuala ya Usalama + +1. **Kuzuia Uingizwaji wa Maagizo**: Safisha maandishi ya sehemu kabla ya uundaji wa agizo. +2. **Mipaka ya Rasilimali**: Punguza matumizi ya kumbukumbu kwa hifadhi ya vekta. +3. **Kikomo cha Kasi**: Punguza ombi la uundaji kwa kila mteja. +4. **Uandikaji wa Ufuatiliaji**: Fuatilia ombi na matokeo ya uundaji. + +## Mkakati wa Majaribio + +### Majaribio ya Kitengo + +Mpakuzi wa ontolojia na muundo tofauti. +Uundaji na uhifadhi wa vekta. +Algorithmu za kutenganisha sentensi. +Hesabu za ufanano wa vekta. +Uchakataji na uthibitisho wa vipengele. + +### Majaribio ya Uunganisho + +Msururu kamili wa uundaji. +Uunganisho wa huduma ya usanidi. +Mwingiliano wa huduma ya agizo. +Usimamizi wa uundaji wa wakati mmoja. + +### Majaribio ya Utendaji + +Usimamizi wa ontolojia kubwa (madarasa 1000+). +Uchakataji wa kundi la juu. +Matumizi ya kumbukumbu chini ya mzigo. +Viwango vya kuchelewesha. + +## Mpango wa Utoaji + +### Muhtasari + +Mfumo wa OntoRAG utatolewa katika awamu nne kuu, na kila awamu itatoa thamani ya hatua kwa hatua huku ikijenga mfumo kamili. Mpango huo unalenga kuanzisha uwezo wa msingi wa uundaji kwanza, kisha kuongeza utendakazi wa swali, kisha uboreshaji na vipengele vya hali ya juu. + +### Awamu ya 1: Msingi na Uundaji wa Msingi + +**Lengo**: Kuanzisha mstari wa msingi wa uundaji unaoongozwa na ontolojia na utangamano wa vekta rahisi. + +#### Hatua ya 1.1: Msingi wa Usimamizi wa Ontolojia +Tengeneza mpakuzi wa usanidi wa ontolojia (`OntologyLoader`). +Pata na thibitisha miundo ya JSON ya ontolojia. +Unda hifadhi ya ontolojia ya ndani na mifumo ya ufikiaji. +Tengeneza utaratibu wa kusasisha ontolojia. + +**Vigezo vya Mafanikio**: +Pakia na pata usanidi wa ontolojia. +Thibitisha muundo na utangamano wa ontolojia. +Shiriki ontolojia nyingi. + +#### Hatua ya 1.2: Utumiaji wa Hifadhi ya Vektas +Tengeneza hifadhi ya vekta rahisi inayotumia NumPy kama mfano wa awali. +Ongeza utumiaji wa hifadhi ya vekta ya FAISS. +Unda utaratibu wa kiwango cha hifadhi ya vekta. +Tengeneza utafutaji wa ufanano na viwango vinavyoweza kusanidi. + +**Vigezo vya Mafanikio**: +Kuhifadhi na kurejesha ujazo (embeddings) kwa ufanisi. +Kufanya utafutaji wa ufanano kwa latensi ya chini ya <100ms. +Kusaidia mifumo ya NumPy na FAISS. + +#### Hatua ya 1.3: Mchakato wa Ujazo wa Ontolojia +Kuunganisha na huduma ya ujazo. +Kutekeleza kipengele cha `OntologyEmbedder`. +Kutoa ujazo kwa vipengele vyote vya ontolojia. +Kuhifadhi ujazo pamoja na metadata katika hifadhi ya vekta. + +**Vigezo vya Mafanikio**: +Kutoa ujazo kwa madarasa na sifa. +Kuhifadhi ujazo pamoja na metadata sahihi. +Kujenga upya ujazo wakati wa sasisho za ontolojia. + +#### Hatua ya 1.4: Vipengele vya Uchunguzi wa Nakala +Kutekeleza mgawaji wa sentensi kwa kutumia NLTK/spaCy. +Kuchukua maneno na vitambulisho. +Kuunda hierarkia ya sehemu za nakala. +Kutoa ujazo kwa sehemu za nakala. + +**Vigezo vya Mafanikio**: +Kugawanya nakala katika sentensi kwa usahihi. +Kuchukua maneno yenye maana. +Kuhifadhi uhusiano wa muktadha. + +#### Hatua ya 1.5: Algoritimu ya Uchaguzi wa Ontolojia +Kutekeleza utangamano kati ya nakala na ontolojia. +Kuunda utatuzi wa utegemezi kwa vipengele vya ontolojia. +Kuunda subseti ndogo na muunganisho. +Kuboresha utendaji wa utengenezaji wa subseti. + +**Vigezo vya Mafanikio**: +Kuchagua vipengele muhimu vya ontolojia kwa usahihi wa >80%. +Kuunganisha utegemezi wote muhimu. +Kutoa subseti katika <500ms. + +#### Hatua ya 1.6: Huduma ya Msingi ya Utoaji +Kutekeleza uundaji wa ombi la utoaji. +Kuunganisha na huduma ya ombi. +Kuchanganua na kuthibitisha majibu ya triplet. +Kuunda mwisho wa huduma ya `kg-extract-ontology`. + +**Vigezo vya Mafanikio**: +Kutoa triplets inayolingana na ontolojia. +Kuthibitisha triplets zote dhidi ya ontolojia. +Kushughulikia makosa ya utoaji kwa utulivu. + +### Awamu ya 2: Utendaji wa Mfumo wa Umasilifu + +**Lengo**: Kuongeza uwezo wa masilifu unaoegemea kwenye ontolojia, kwa usaidizi wa mifumo mingi. + +#### Hatua ya 2.1: Vipengele vya Msingi ya Umasilifu +Kutekeleza mchanganuzi wa swali. +Kuunda mlinganishi wa ontolojia kwa masilifu. +Kurekebisha utafutaji wa vekta kwa muktadha wa masilifu. +Kuunda kipengele cha kutoa masilifu. + +**Vigezo vya Mafanikio**: +Kuchambua maswali katika vipengele vya semantic. +Kulinganisha maswali na vipengele muhimu vya ontolojia. +Kutoa masilifu kwa mfumo unaofaa. + +#### Hatua ya 2.2: Utendaji wa Njia ya SPARQL +Kutekeleza huduma ya `onto-query-sparql`. +Kuunda jenereta ya swali la SPARQL kwa kutumia LLM. +Kuunda vipatterno vya ombi kwa utengenezaji wa SPARQL. +Kuthibitisha sintaksia iliyoundwa ya SPARQL. + +**Vigezo vya Mafanikio**: +Kutoa maswali valid ya SPARQL. +Kutumia mitindo ya SPARQL inayofaa. +Kushughulikia aina ngumu za maswali. + +#### Hatua ya 2.3: Injini ya SPARQL-Cassandra +Kutekeleza interface ya Hifadhi ya rdflib kwa Cassandra. +Kuunda mtafsiri wa swali la CQL. +Kuboresha utangamano wa muundo wa triplet. +Kushughulikia umbizo la matokeo ya SPARQL. + +**Vigezo vya Mafanikio**: +Kutekeleza maswali ya SPARQL kwenye Cassandra. +Kusaidia mitindo ya kawaida ya SPARQL. +Kurudisha matokeo katika umbizo la kawaida. + +#### Hatua ya 2.4: Utendaji wa Njia ya Cypher +Kutekeleza huduma ya `onto-query-cypher`. +Kuunda jenereta ya swali la Cypher kwa kutumia LLM. +Kuunda vipatterno vya ombi kwa utengenezaji wa Cypher. +Kuthibitisha sintaksia iliyoundwa ya Cypher. + +**Vigezo vya Mafanikio**: +Kutoa maswali valid ya Cypher. +Kutumia mitindo ya grafu inayofaa. +Kusaidia Neo4j, Memgraph, FalkorDB. + +#### Hatua ya 2.5: Mfumo wa Utendaji wa Cypher +Implement multi-database Cypher executor +Support Bolt protocol (Neo4j/Memgraph) +Support Redis protocol (FalkorDB) +Handle result normalization + +**Success Criteria**: +Execute Cypher on all target databases +Handle database-specific differences +Maintain connection pools efficiently + +#### Step 2.6: Answer Generation +Implement answer generator component +Create prompts for answer synthesis +Format query results for LLM consumption +Generate natural language answers + +**Success Criteria**: +Generate accurate answers from query results +Maintain context from original question +Provide clear, concise responses + +### Phase 3: Optimization and Robustness + +**Goal**: Optimize performance, add caching, improve error handling, and enhance reliability. + +#### Step 3.1: Performance Optimization +Implement embedding caching +Add query result caching +Optimize vector search with FAISS IVF indexes +Implement batch processing for embeddings + +**Success Criteria**: +Reduce average query latency by 50% +Support 10x more concurrent requests +Maintain sub-second response times + +#### Step 3.2: Advanced Error Handling +Implement comprehensive error recovery +Add fallback mechanisms between query paths +Create retry logic with exponential backoff +Improve error logging and diagnostics + +**Success Criteria**: +Gracefully handle all failure scenarios +Automatic failover between backends +Detailed error reporting for debugging + +#### Step 3.3: Monitoring and Observability +Add performance metrics collection +Implement query tracing +Create health check endpoints +Add resource usage monitoring + +**Success Criteria**: +Track all key performance indicators +Identify bottlenecks quickly +Monitor system health in real-time + +#### Step 3.4: Configuration Management +Implement dynamic configuration updates +Add configuration validation +Create configuration templates +Support environment-specific settings + +**Success Criteria**: +Update configuration without restart +Validate all configuration changes +Support multiple deployment environments + +### Phase 4: Advanced Features + +**Goal**: Add sophisticated capabilities for production deployment and enhanced functionality. + +#### Step 4.1: Multi-Ontology Support +Implement ontology selection logic +Support cross-ontology queries +Handle ontology versioning +Create ontology merge capabilities + +**Success Criteria**: +Query across multiple ontologies +Handle ontology conflicts +Support ontology evolution + +#### Step 4.2: Intelligent Query Routing +Implementa njia za msingi kulingana na utendaji +Ongeza uchambuzi wa utata wa swali +Unda algoriti za njia zinazobadilika +Saidia vipimo vya A/B kwa njia + +**Vigezo vya Mafanikio**: +Pata njia za maswali kwa ufanisi +Jifunze kutoka kwa utendaji wa maswali +Boresha njia kwa muda + +#### Hatua ya 4.3: Vipengele vya Uvunaji Vilivyoendelezwa +Ongeza alama za uaminifu kwa vitu +Leta utengenezaji wa maelezo +Unda mzunguko wa maoni kwa uboreshaji +Saidia ujifunzaji wa hatua kwa hatua + +**Vigezo vya Mafanikio**: +Toa alama za uaminifu +Eleza maamuzi ya uvunaji +Boresha kwa ufanisi + +#### Hatua ya 4.4: Uimarishaji wa Uzalishaji +Ongeza kikomo cha kasi +Leta uthibitishaji/idhinishaji +Unda automatisering ya usakinishaji +Ongeza nakala na urejesho + +**Vigezo vya Mafanikio**: +Usalama unaofaa kwa uzalishaji +Mfumo wa usakinishaji uliyo na automatisering +Uwezo wa urejesho wa majanga + +### Hatua za Utoaji + +1. **Hatua ya 1** (Mwisho wa Awamu ya 1): Uvunaji wa msingi unaoendeshwa na ontolojia unafanya kazi +2. **Hatua ya 2** (Mwisho wa Awamu ya 2): Mfumo kamili wa maswali na njia za SPARQL na Cypher +3. **Hatua ya 3** (Mwisho wa Awamu ya 3): Mfumo uliopunguzwa, thabiti, na unaoendelea kufaa kwa majaribio +4. **Hatua ya 4** (Mwisho wa Awamu ya 4): Mfumo unaofaa kwa uzalishaji na vipengele vilivyoendelezwa + +### Kupunguza Hatari + +#### Hatari za Kiufundi +**Uwezo wa Hifadhi ya Vektor**: Anza na NumPy, uhamishie kwa FAISS hatua kwa hatua +**Ukamavu wa Uundaji wa Maswali**: Leta uthibitisho na njia mbadala +**Ulinganishi wa Backend**: Jaribu kwa uangalifu na kila aina ya hifadhidata +**Vizuizi vya Utendaji**: Fafanua mapema na mara kwa mara, boresha kwa hatua kwa hatua + +#### Hatari za Uendeshaji +**Ubora wa Ontolojia**: Leta uthibitisho na ukaguzi wa utangamano +**Utegemezi wa Huduma**: Ongeza vituo vya mzunguko na njia mbadala +**Hadhara za Rasilimali**: Fuatilia na weka mipaka inayofaa +**Utangamano wa Data**: Leta ushughulikiaji sahihi wa miamala + +### Viashiria vya Mafanikio + +#### Viashiria vya Mafanikio ya Awamu ya 1 +Ukamavu wa uvunaji: >90% utangamano wa ontolojia +Njia ya usindikaji: <1 sekunde kwa sehemu +Muda wa kupakia ontolojia: <10 sekunde +Latensi ya utafutaji wa vektor: <100ms + +#### Viashiria vya Mafanikio ya Awamu ya 2 +Njia ya mafanikio ya swali: >95% +Latensi ya swali: <2 sekunde kwa jumla +Ulinganishi wa backend: 100% kwa hifadhidata zilizolengwa +Ukamavu wa jibu: >85% kulingana na data iliyopo + +#### Viashiria vya Mafanikio ya Awamu ya 3 +Muda wa mfumo: >99.9% +Njia ya urejesho wa makosa: >95% +Njia ya hit ya kumbukumbu: >60% +Watumiaji wengi: >100 + +#### Viashiria vya Mafanikio ya Awamu ya 4 +Maswali ya ontolojia nyingi: Yameunganishwa kikamilifu +Uboreshaji wa njia: Kupunguzwa kwa latensi ya 30% +Ukamavu wa alama: >90% +Usakinishaji wa uzalishaji: Masasisho bila kukatizwa + +## Marejeleo + +[Lugha ya Ontolojia ya Wavuti ya OWL 2](https://www.w3.org/TR/owl2-overview/) +[Usanifu wa GraphRAG](https://github.com/microsoft/graphrag) +[Transformers za Sentensi](https://www.sbert.net/) +[Utafiti wa Vektor wa FAISS](https://github.com/facebookresearch/faiss) +[Maktaba ya NLP ya spaCy](https://spacy.io/) +[Dokumenti ya rdflib](https://rdflib.readthedocs.io/) +[Itifaki ya Neo4j Bolt](https://neo4j.com/docs/bolt/current/) diff --git a/docs/tech-specs/ontorag.tr.md b/docs/tech-specs/ontorag.tr.md new file mode 100644 index 00000000..c520adc8 --- /dev/null +++ b/docs/tech-specs/ontorag.tr.md @@ -0,0 +1,1067 @@ +# OntoRAG: Ontolojiye Dayalı Bilgi Çıkarma ve Sorgulama Teknik Özellikleri + +## Genel Bakış + +OntoRAG, yapılandırılmamış metinden bilgi üçlülerinin çıkarılması ve elde edilen bilgi grafiğinin sorgulanması sırasında sıkı semantik tutarlılığı sağlayan, ontoloji odaklı bir bilgi çıkarma ve sorgulama sistemidir. GraphRAG'e benzer, ancak resmi ontoloji kısıtlamalarıyla, OntoRAG, çıkarılan tüm üçlülerin önceden tanımlanmış ontolojik yapılara uygun olmasını sağlar ve semantik olarak bilinçli sorgulama yetenekleri sunar. + +Sistem, hem çıkarma hem de sorgulama işlemlerinde ilgili ontoloji alt kümelerini dinamik olarak seçmek için vektör benzerliği eşleştirmesi kullanır, bu da odaklı ve bağlamsal olarak uygun işleme sağlarken semantik geçerliliği korur. + +**Servis Adı**: `kg-extract-ontology` + +## Hedefler + +**Ontolojiye Uygun Çıkarma**: Çıkarılan tüm üçlülerin yüklenen ontolojilere kesinlikle uygun olmasını sağlamak +**Dinamik Bağlam Seçimi**: Her parça için ilgili ontoloji alt kümelerini seçmek için gömülmeleri kullanmak +**Semantik Tutarlılık**: Sınıf hiyerarşilerini, özellik alanlarını/aralıklarını ve kısıtlamaları korumak +**Verimli İşleme**: Hızlı ontoloji öğesi eşleştirmesi için bellek içi vektör depoları kullanmak +**Ölçeklenebilir Mimari**: Farklı alanlara sahip çoklu eşzamanlı ontolojileri desteklemek + +## Arka Plan + +Mevcut bilgi çıkarma hizmetleri (`kg-extract-definitions`, `kg-extract-relationships`), resmi kısıtlamalar olmadan çalışır ve potansiyel olarak tutarsız veya uyumsuz üçlüler üretebilir. OntoRAG, bunu şunları yaparak ele alır: + +1. Geçerli sınıfları ve özellikleri tanımlayan resmi ontolojileri yüklemek +2. Metin içeriğini ilgili ontoloji öğeleriyle eşleştirmek için gömülmeleri kullanmak +3. Çıkarma işleminin yalnızca ontolojiye uygun üçlüler üretmesini sağlamak +4. Çıkarılan bilginin semantik olarak doğrulanmasını sağlamak + +Bu yaklaşım, sinirsel çıkarmanın esnekliğini, resmi bilgi gösteriminin titizliğiyle birleştirir. + +## Teknik Tasarım + +### Mimari + +OntoRAG sistemi aşağıdaki bileşenlerden oluşur: + +``` +┌─────────────────┐ +│ Configuration │ +│ Service │ +└────────┬────────┘ + │ Ontologies + ▼ +┌─────────────────┐ ┌──────────────┐ +│ kg-extract- │────▶│ Embedding │ +│ ontology │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ │ + ▼ ▼ +┌─────────────────┐ ┌──────────────┐ +│ In-Memory │◀────│ Ontology │ +│ Vector Store │ │ Embedder │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Sentence │────▶│ Chunker │ +│ Splitter │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Ontology │────▶│ Vector │ +│ Selector │ │ Search │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Prompt │────▶│ Prompt │ +│ Constructor │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ +│ Triple Output │ +└─────────────────┘ +``` + +### Bileşen Detayları + +#### 1. Ontoloji Yükleyici + +**Amaç**: Ontoloji yapılandırmalarını olay odaklı güncellemeler kullanarak yapılandırma hizmetinden alır ve ayrıştırır. + +**Uygulama**: +Ontoloji Yükleyici, olay odaklı ontoloji yapılandırma güncellemelerini almak için TrustGraph'in ConfigPush kuyruğunu kullanır. "ontoloji" türünde bir yapılandırma öğesi eklendiğinde veya değiştirildiğinde, yükleyici yapılandırma-güncelleme kuyrusu aracılığıyla güncellemeyi alır ve meta veriler, sınıflar, nesne özellikleri ve veri türü özellikleri içeren JSON yapısını ayrıştırır. Bu ayrıştırılmış ontolojiler, çıkarma işlemi sırasında verimli bir şekilde erişilebilen yapılandırılmış nesneler olarak bellekte saklanır. + +**Temel İşlemler**: +Ontoloji türündeki yapılandırmalar için config-update kuyruğuna abone olun +JSON ontoloji yapılarını OntologyClass ve OntologyProperty nesnelerine ayrıştırın +Ontoloji yapısını ve tutarlılığını doğrulayın +Ayrıştırılmış ontolojileri hızlı erişim için bellekte önbelleğe alın +Akışa özgü vektör depolarıyla akışa özel işleme yapın + +**Uygulama Konumu**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_loader.py` + +#### 2. Ontoloji Gömücüsü + +**Amaç**: Tüm ontoloji öğeleri için vektör gömüleri oluşturarak semantik benzerlik eşleştirmesini etkinleştirir. + +**Uygulama**: +Ontoloji Gömücüsü, yüklenen ontolojilerdeki her öğeyi (sınıflar, nesne özellikleri ve veri türü özellikleri) işler ve EmbeddingsClientSpec hizmetini kullanarak vektör gömüleri oluşturur. Her öğe için, öğenin tanımlayıcısını, etiketlerini ve açıklamasını (yorum) birleştirerek bir metin gösterimi oluşturur. Bu metin daha sonra, semantik anlamını yakalayan yüksek boyutlu bir vektör gömüsüne dönüştürülür. Bu gömüler, öğe türü, kaynak ontoloji ve tam tanım hakkında meta verilerle birlikte, akışa özel bir bellek içi FAISS vektör deposunda saklanır. Gömücü, ilk gömü yanıtından gömü boyutunu otomatik olarak algılar. + +**Temel İşlemler**: +Öğenin kimliklerinden, etiketlerinden ve yorumlarından metin gösterimleri oluşturun +Toplu işleme için asyncio.gather kullanarak EmbeddingsClientSpec aracılığıyla gömüler oluşturun +Gömüleri kapsamlı meta verilerle FAISS vektör deposunda saklayın +Verimli erişim için ontolojiye, öğe türüne ve öğe kimliğine göre indeksleyin +Vektör deposu başlatması için gömü boyutlarını otomatik olarak algılayın +Bağımsız vektör depolarıyla akışa özel gömü modelleriyle çalışın + +**Uygulama Konumu**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_embedder.py` + +#### 3. Metin İşleyici (Cümle Ayırıcı) + +**Amaç**: Ontoloji eşleştirmesi için hassas bir şekilde metin parçalarını ince taneli segmentlere ayırır. + +**Uygulama**: +Metin İşleyici, gelen metin parçalarını cümlelere ayırmak ve POS etiketlemesi yapmak için NLTK'yi kullanır. NLTK sürüm uyumluluğunu, `punkt_tab` ve `averaged_perceptron_tagger_eng`'i indirmeye çalışarak ve gerekirse eski sürümlere geri dönerek yönetir. Her metin parçası, ontoloji öğeleriyle bağımsız olarak eşleştirilebilen ayrı cümlelere bölünür. + +**Temel İşlemler**: +NLTK cümle ayrıştırması kullanarak metni cümlelere ayırın +NLTK sürüm uyumluluğunu yönetin (punkt_tab vs punkt) +Metin ve konum bilgileriyle TextSegment nesneleri oluşturun +Hem tam cümleleri hem de ayrı parçaları destekleyin + +**Uygulama Konumu**: `trustgraph-flow/trustgraph/extract/kg/ontology/text_processor.py` + +#### 4. Ontoloji Seçici + +**Amaç**: Mevcut metin parçası için en alakalı ontoloji öğesi alt kümesini belirler. + +**Uygulama**: +Ontoloji Seçici, metin segmentleri ile ontoloji öğeleri arasında semantik eşleştirme yapmak için FAISS vektör benzerlik araması kullanır. Metin parçasındaki her cümle için, bir gömü oluşturur ve vektör deposunda en benzer ontoloji öğelerini yapılandırılabilir bir eşik değeri (varsayılan 0,3) ile kosinüs benzerliği kullanarak arar. Tüm ilgili öğeler toplandıktan sonra, kapsamlı bir bağımlılık çözümlemesi yapılır: bir sınıf seçilirse, üst sınıfları dahil edilir; bir özellik seçilirse, etki alanı ve aralık sınıfları eklenir. Ek olarak, seçilen her sınıf için, **o sınıfa referans veren tüm özellikleri** (etki alanı veya aralık olarak) otomatik olarak dahil eder. Bu, çıkarmanın ilgili tüm ilişki özelliklerine erişmesini sağlar. + +**Temel İşlemler**: +Her metin parçasının (cümlelerin) gömülme değerlerini oluşturun. +FAISS vektör deposunda k-en yakın komşu araması yapın (top_k=10, eşik=0.3). +Zayıf eşleşmeleri filtrelemek için benzerlik eşiği uygulayın. +Bağımlılıkları çözün (üst sınıflar, etki alanları, aralıklar). +**Seçilen sınıflarla ilgili tüm özellikleri otomatik olarak dahil edin** (etki alanı/aralık eşleşmesi). +Tüm gerekli ilişkilerle tutarlı bir ontoloji alt kümesi oluşturun. +Birden çok kez görünen öğeleri yinelenenleri kaldırın. + +**Uygulama Konumu**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_selector.py` + +#### 5. İstek Oluşturma + +**Amaç**: LLM'yi yalnızca ontolojiye uygun üçlüleri çıkarması için yönlendiren yapılandırılmış istekler oluşturur. + +**Uygulama**: +Çıkarma hizmeti, `ontology-prompt.md`'dan yüklenen bir Jinja2 şablonu kullanır ve bu şablon, ontoloji alt kümesini ve LLM tarafından çıkarım için kullanılan metni biçimlendirir. Şablon, Jinja2 sözdizimini kullanarak sınıflar, nesne özellikleri ve veri türü özellikleri üzerinde dinamik olarak yineleme yapar ve her birini açıklamaları, etki alanları, aralıkları ve hiyerarşik ilişkileriyle birlikte sunar. İstek, yalnızca sağlanan ontoloji öğelerinin kullanılması konusunda kesin kurallar içerir ve tutarlı ayrıştırma için JSON çıktı biçimi talep eder. + +**Temel İşlemler**: +Ontoloji öğeleri üzerinde döngüler içeren Jinja2 şablonunu kullanın. +Üst sınıf ilişkileri (subclass_of) ve yorumlarla sınıfları biçimlendirin. +Etki alanı/aralık kısıtlamaları ve yorumlarla özellikleri biçimlendirin. +Açık çıkarma kuralları ve çıktı biçimi gereksinimleri ekleyin. +"extract-with-ontologies" şablonuyla istek hizmetini çağırın. + +**Şablon Konumu**: `ontology-prompt.md` +**Uygulama Konumu**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` (build_extraction_variables metodu) + +#### 6. Ana Çıkarma Hizmeti + +**Amaç**: Uçtan uca, ontolojiye dayalı üçlü çıkarma işlemini gerçekleştirmek için tüm bileşenleri koordine eder. + +**Uygulama**: +Ana Çıkarma Hizmeti (KgExtractOntology), eksiksiz çıkarma iş akışını yöneten orkestrasyon katmanıdır. Her akış için bileşen başlatmayı kullanan TrustGraph'ın FlowProcessor kalıbını kullanır. Bir ontoloji yapılandırma güncellemesi geldiğinde, akışa özgü bileşenleri (ontoloji yükleyici, gömücü, metin işlemcisi, seçici) başlatır veya günceller. Bir metin parçası işlenmek üzere geldiğinde, aşağıdaki adımları koordine eder: metni segmentlere ayırmak, vektör araması yoluyla ilgili ontoloji öğelerini bulmak, kısıtlı bir istek oluşturmak, istek hizmetini çağırmak, yanıtı ayrıştırmak ve doğrulamak, ontoloji tanım üçlüleri oluşturmak ve hem içerik üçlülerini hem de varlık bağlamlarını yayınlamak. + +**Çıkarma İş Akışı**: +1. Metin parçasını chunks-input kuyruğu aracılığıyla alın. +2. Gerekirse akış bileşenlerini başlatın (ilk parça veya yapılandırma güncellemesinde). +3. Metni NLTK kullanarak cümlelere ayırın. +4. İlgili ontoloji kavramlarını bulmak için FAISS vektör deposunda arama yapın. +5. Otomatik özellik dahil etme ile ontoloji alt kümesini oluşturun. +6. Jinja2 şablonlu istek değişkenlerini oluşturun. +7. extract-with-ontologies şablonuyla istek hizmetini çağırın. +8. JSON yanıtını yapılandırılmış üçlülere ayrıştırın. +9. Üçlüleri doğrulayın ve URI'ları tam ontoloji URI'lerine genişletin. +10. Sınıflar ve özellikler (etiketler/yorumlar/etki alanları/aralıklar) ile ontoloji tanım üçlülerini oluşturun. +11. Tüm üçlülerden varlık bağlamlarını oluşturun. +12. Üçlüleri ve varlık-bağlamlarını kuyruklara yayınlayın. + +**Temel Özellikler**: +Farklı gömme modellerini destekleyen akış içi vektör depoları. +config-update kuyruğu aracılığıyla olay odaklı ontoloji güncellemeleri. +Ontoloji URI'lerini kullanarak otomatik URI genişletme. +Ontoloji öğeleri, tüm meta verilerle birlikte bilgi grafiğine eklenir. +Varlık bağlamları hem içerik hem de ontoloji öğelerini içerir. + +**Uygulama Konumu**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` + +### Yapılandırma + +Bu hizmet, komut satırı argümanlarıyla TrustGraph'ın standart yapılandırma yaklaşımını kullanır: + +```bash +kg-extract-ontology \ + --id kg-extract-ontology \ + --pulsar-host localhost:6650 \ + --input-queue chunks \ + --config-input-queue config-update \ + --output-queue triples \ + --entity-contexts-output-queue entity-contexts +``` + +**Temel Yapılandırma Parametreleri**: +`similarity_threshold`: 0.3 (varsayılan, kod içinde yapılandırılabilir) +`top_k`: 10 (her segment için alınacak ontoloji öğelerinin sayısı) +`vector_store`: Otomatik olarak algılanan boyutlara sahip Per-flow FAISS IndexFlatIP +`text_processor`: NLTK ile punkt_tab cümle tokenizasyonu +`prompt_template`: "extract-with-ontologies" (Jinja2 şablonu) + +**Ontoloji Yapılandırması**: +Ontolojiler, "ontology" türü ile yapılandırma güncelleme kuyruğu aracılığıyla dinamik olarak yüklenir. + +### Veri Akışı + +1. **Başlangıç Aşaması** (her akış için): + Yapılandırma güncelleme kuyruğu aracılığıyla ontoloji yapılandırmasını alın + Ontoloji JSON'unu OntologyClass ve OntologyProperty nesnelerine ayrıştırın + Tüm ontoloji öğeleri için EmbeddingsClientSpec kullanarak gömülme oluşturun + Gömülmeleri her akış için FAISS vektör deposunda saklayın + İlk yanıttan gömülme boyutlarını otomatik olarak algılayın + +2. **Çıkarma Aşaması** (her parça için): + chunks-input kuyruğundan bir parça alın + Parçayı NLTK kullanarak cümlelere bölün + Her cümle için gömülmeler hesaplayın + İlgili ontoloji öğelerini bulmak için FAISS vektör deposunda arama yapın + Otomatik özellik eklemeli ontoloji alt kümesi oluşturun + Metin ve ontoloji ile Jinja2 şablon değişkenlerini oluşturun + extract-with-ontologies şablonu ile istem hizmetini çağırın + JSON yanıtını ayrıştırın ve üçlüleri doğrulayın + URI'ları ontoloji URI'lerini kullanarak genişletin + Ontoloji tanım üçlülerini oluşturun + Tüm üçlülerden varlık bağlamlarını oluşturun + üçlüler ve varlık-bağlamları kuyruklarına yayınlayın + +### Bellek İçi Vektör Deposu + +**Amaç**: Ontoloji öğesi eşleştirmesi için hızlı, bellek tabanlı benzerlik araması sağlar. + +**Uygulama: FAISS** + +Sistem, tam kosinüs benzerliği araması için **FAISS (Facebook AI Similarity Search)** ve IndexFlatIP kullanır. Temel özellikler: + +**IndexFlatIP**: İç çarpım kullanarak tam kosinüs benzerliği araması +**Otomatik algılama**: Boyut, ilk gömülme yanıtından belirlenir +**Per-flow depoları**: Her akış, farklı gömülme modelleri için bağımsız bir vektör deposuna sahiptir +**Normalleştirme**: Tüm vektörler dizine eklenmeden önce normalleştirilir +**Toplu işlemler**: Başlangıç ontoloji yüklemesi için verimli toplu ekleme + +**Uygulama Konumu**: `trustgraph-flow/trustgraph/extract/kg/ontology/vector_store.py` + +### Ontoloji Alt Kümesi Seçim Algoritması + +**Amaç**: Her metin parçası için ontolojinin ilgili en küçük bölümünü dinamik olarak seçer. + +**Detaylı Algoritma Adımları**: + +1. **Metin Segmentasyonu**: + Giriş parçasını NLP cümle algılama kullanarak cümlelere bölün + Her cümleden isim öbeklerini, fiil öbeklerini ve adlandırılmış varlıkları çıkarın + Bağlamı koruyan hiyerarşik bir segmentler yapısı oluşturun + +2. **Gömülme Oluşturma**: + Her metin segmenti (cümleler ve öbekler) için vektör gömülmeleri oluşturun + Ontoloji öğeleri için kullanılan aynı gömülme modelini kullanın + Tekrarlayan segmentler için performansı artırmak için gömülmeleri önbelleğe alın + +3. **Benzerlik Araması**: + Her metin segmenti gömülmesi için vektör deposunda arama yapın + En benzer ontoloji öğelerinin en üst N tanesini (örneğin, 10) alın + Zayıf eşleşmeleri filtrelemek için bir benzerlik eşiği (örneğin, 0.7) uygulayın + Tüm segmentler genelinde sonuçları toplayın ve eşleşme sıklıklarını izleyin + +4. **Bağımlılık Çözümü**: + Seçilen her sınıf için, köke kadar tüm üst sınıfları yinelemeli olarak dahil edin + Seçilen her özellik için, alan ve aralık sınıflarını dahil edin + Ters özellikler için, her iki yönü de dahil edin + Ontolojide mevcutsa, eşdeğer sınıfları ekleyin + +5. **Alt Küme Oluşturma**: + Toplanan öğeleri ilişkileri korurken yinelenenleri kaldırın + Sınıflara, nesne özelliklerine ve veri türü özelliklerine göre düzenleyin + Tüm kısıtlamaların ve ilişkilerin korunmasını sağlayın + Geçerli ve eksiksiz olan kendi kendine yeterli bir mini-ontoloji oluşturun + +**Örnek İnceleme**: +Verilen metin: "Kahverengi köpek, beyaz kedinin ağacın tepesine doğru koştuğunu gördü." +Segmentler: ["kahverengi köpek", "beyaz kedi", "ağaç", "koştu"] +Eşleşen öğeler: [köpek (sınıf), kedi (sınıf), hayvan (üst sınıf), koşar (özellik)] +Bağımlılıklar: [hayvan (köpek ve kedinin üst sınıfı), canlı (hayvanın üst sınıfı)] +Sonuç alt kümesi: Hayvan hiyerarşisi ve koşma ilişkisi ile eksiksiz mini-ontoloji + +### Üçlü Doğrulama + +**Amaç**: Çıkarılan tüm üçlülerin ontoloji kısıtlamalarına kesinlikle uygun olduğundan emin olun. + +**Doğrulama Algoritması**: + +1. **Sınıf Doğrulama**: + Konuların, ontoloji alt kümesinde tanımlanan sınıfların örnekleri olduğundan emin olun. + Nesne özellikleri için, nesnelerin de geçerli sınıf örnekleri olduğundan emin olun. + Sınıf adlarını, ontolojinin sınıf sözlüğü ile karşılaştırın. + Sınıf hiyerarşilerini işleyin - alt sınıfların örnekleri, üst sınıf kısıtlamaları için geçerlidir. + +2. **Özellik Doğrulama**: + Öncüllerin, ontoloji alt kümesindeki özelliklerle eşleştiğinden emin olun. + Varlıklar arası nesne özellikleri ile varlıklardan literal değerlere olan veri tipi özellikleri arasındaki farkı belirtin. + Özellik adlarının tam olarak eşleştiğinden emin olun (varsa ad alanını dikkate alın). + +3. **Alan/Aralık Kontrolü**: + Kullanılan her özellik için, alanını ve aralığını alın. + Konunun türünün, özelliğin alanıyla eşleştiğinden veya ondan türediğinden emin olun. + Nesnenin türünün, özelliğin aralığıyla eşleştiğinden veya ondan türediğinden emin olun. + Veri tipi özellikleri için, nesnenin doğru XSD türünde bir literal olduğundan emin olun. +Veri tipi özellikleri için, nesnenin doğru XSD türünde bir literal olduğundan emin olun +4. **Kardinalite Doğrulama**: + Her konu için özellik kullanım sayılarını takip edin. + Minimum kardinaliteyi kontrol edin - gerekli özelliklerin mevcut olduğundan emin olun. + Maksimum kardinaliteyi kontrol edin - özelliğin çok fazla kullanılmadığından emin olun. + Fonksiyonel özellikler için, her konu için en fazla bir değer olduğundan emin olun. + +5. **Veri Tipi Doğrulama**: + Literal değerleri, bildirilen XSD türlerine göre ayrıştırın. + Tamsayıların geçerli sayılar olduğundan, tarihlerinin doğru biçimlendirildiğinden emin olun, vb. + Regex kısıtlamaları tanımlanmışsa, dize kalıplarını kontrol edin. + URI'lerin xsd:anyURI türleri için doğru biçimlendirildiğinden emin olun. + +**Doğrulama Örneği**: +Üçlü: ("Buddy", "has-owner", "John") +"Buddy"nin, "has-owner" özelliğine sahip olabilen bir sınıf olarak tanımlandığından emin olun. +"has-owner" özelliğinin ontolojide olduğundan emin olun. +Alan kısıtlamasını doğrulayın: konu, "Pet" türünde veya bir alt türünde olmalıdır. +Aralık kısıtlamasını doğrulayın: nesne, "Person" türünde veya bir alt türünde olmalıdır. +Geçerliyse, çıktıya ekleyin; geçersizse, ihlali günlüğe kaydedin ve atlayın. + +## Performans Hususları + +### Optimizasyon Stratejileri + +1. **Gömülü Önbellekleme**: Sık kullanılan metin segmentleri için gömülmeleri önbelleğe alın. +2. **Toplu İşleme**: Birden fazla segmenti paralel olarak işleyin. +3. **Vektör Deposu İndeksleme**: Büyük ontolojiler için yaklaşık en yakın komşu algoritmalarını kullanın. +4. **İstem Optimizasyonu**: Yalnızca gerekli ontoloji öğelerini dahil ederek istem boyutunu en aza indirin. +5. **Sonuç Önbellekleme**: Aynı parçalar için çıkarma sonuçlarını önbelleğe alın. + +### Ölçeklenebilirlik + +**Yatay Ölçekleme**: Paylaşılan ontoloji önbelleğine sahip çoklu çıkarıcı örneği. +**Ontoloji Bölümleme**: Büyük ontolojileri alanlara göre bölün. +**Akışlı İşleme**: Parçalara toplu olarak işlem yapmadan geldikçe işleyin. +**Bellek Yönetimi**: Kullanılmayan gömülmelerin periyodik olarak temizlenmesi. + +## Hata Yönetimi + +### Başarısızlık Senaryoları + +1. **Eksik Ontolojiler**: Kısıtlanmamış çıkarma işlemine geri dönün. +2. **Gömme Hizmeti Hatası**: Önbelleğe alınmış gömülmeleri kullanın veya semantik eşleşmeyi atlayın. +3. **İstem Hizmeti Zaman Aşımı**: Üstel geri alma ile yeniden deneyin. +4. **Geçersiz Üçlü Biçimi**: Hatalı üçlüleri günlüğe kaydedin ve atlayın. +5. **Ontoloji Tutarsızlıkları**: Çakışmaları bildirin ve en spesifik geçerli öğeleri kullanın. + +### İzleme + +İzlenecek temel ölçütler: + +Ontoloji yükleme süresi ve bellek kullanımı +Gömme oluşturma gecikmesi +Vektör arama performansı +İstem hizmeti yanıt süresi +Üçlü çıkarma doğruluğu +Ontoloji uyumluluk oranı + +## Geçiş Yolu + +### Mevcut Çıkarıcılardan + +1. **Paralel Çalışma**: Başlangıçta mevcut çıkarıcılarla birlikte çalıştırın. +2. **Aşamalı Dağıtım**: Belirli belge türleriyle başlayın. +3. **Kalite Karşılaştırması**: Çıktı kalitesini mevcut çıkarıcılarla karşılaştırın. +4. **Tam Geçiş**: Kalite doğrulandığında mevcut çıkarıcıları değiştirin. + +### Ontoloji Geliştirme + +1. **Mevcut Bilgilerden Başlatma**: Başlangıç ontolojilerini mevcut bilgilerden oluşturun. +2. **Yinelemeli İyileştirme**: Çıkarma kalıplarına göre iyileştirin. +3. **Alan Uzmanı İncelemesi**: Konu uzmanlarıyla doğrulayın. +4. **Sürekli İyileştirme**: Çıkarma geri bildirimine göre güncelleyin. + +## Ontolojiye Duyarlı Sorgu Hizmeti + +### Genel Bakış + +Ontolojiye duyarlı sorgu hizmeti, farklı arka uç grafik depolarını desteklemek için çoklu sorgu yolu sağlar. Cassandra (SPARQL aracılığıyla) ve Cypher tabanlı grafik depoları (Neo4j, Memgraph, FalkorDB) için hem hassas hem de semantik olarak bilinçli soru yanıtlama için ontoloji bilgisini kullanır. + +**Hizmet Bileşenleri**: +`onto-query-sparql`: Doğal dili, Cassandra için SPARQL'e dönüştürür. +`sparql-cassandra`: Cassandra için rdflib kullanarak SPARQL sorgu katmanı. +`onto-query-cypher`: Doğal dili, grafik veritabanları için Cypher'a dönüştürür. +`cypher-executor`: Neo4j, Memgraph, FalkorDB için Cypher sorgu katmanı. + +### Mimari + +``` + ┌─────────────────┐ + │ User Query │ + └────────┬────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Question │────▶│ Sentence │ + │ Analyser │ │ Splitter │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Ontology │────▶│ Vector │ + │ Matcher │ │ Store │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Backend Router │ + └────────┬────────┘ + │ + ┌───────────┴───────────┐ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ onto-query- │ │ onto-query- │ + │ sparql │ │ cypher │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ SPARQL │ │ Cypher │ + │ Generator │ │ Generator │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ sparql- │ │ cypher- │ + │ cassandra │ │ executor │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ Cassandra │ │ Neo4j/Memgraph/ │ + │ │ │ FalkorDB │ + └────────┬────────┘ └────────┬────────┘ + │ │ + └────────────┬───────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Answer │────▶│ Prompt │ + │ Generator │ │ Service │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Final Answer │ + └─────────────────┘ +``` + +### Sorgu İşleme Hattı + +#### 1. Soru Analizörü + +**Amaç**: Kullanıcı sorularını, ontoloji eşleştirmesi için anlamsal bileşenlere ayırır. + +**Algoritma Açıklaması**: +Soru Analizörü, gelen doğal dil sorgusunu alır ve çıkarma hattında kullanılan aynı cümle bölme yaklaşımıyla anlamlı segmentlere böler. Soruda bahsedilen temel varlıkları, ilişkileri ve kısıtlamaları belirler. Her segment, soru türü (olaysal, toplama, karşılaştırma vb.) ve beklenen cevap formatı açısından analiz edilir. Bu ayrıştırma, soruyu yanıtlamak için ontolojinin hangi bölümlerinin en alakalı olduğunu belirlemeye yardımcı olur. + +**Temel İşlemler**: +Soruyu cümlelere ve ifadelere ayırın +Soru türünü ve amacını belirleyin +Bahsedilen varlıkları ve ilişkileri çıkarın +Sorudaki kısıtlamaları ve filtreleri tespit edin +Beklenen cevap formatını belirleyin + +#### 2. Sorgular İçin Ontoloji Eşleştirici + +**Amaç**: Soruyu yanıtlamak için gereken ilgili ontoloji alt kümesini belirler. + +**Algoritma Açıklaması**: +Çıkarma hattının Ontoloji Seçici'sine benzer, ancak soru yanıtlama için optimize edilmiştir. Eşleştirici, soru segmentleri için gömülme değerleri oluşturur ve ilgili ontoloji öğelerini vektör deposunda arar. Ancak, sorgu oluşturma için yararlı olacak kavramları bulmaya odaklanır, çıkarma işlemine değil. Grafiği keşfederken bahsedilmeyen ancak ilgili olabilecek ilgili özellikleri de seçime dahil eder. Örneğin, "çalışanlar" hakkında bir soru sorulursa, çalışan bilgileri bulmak için ilgili olabilecek "çalışır", "yönetir" ve "rapor verir" gibi özellikleri de içerebilir. + +**Eşleştirme Stratejisi**: +Soru segmentlerini gömülme değerlerine dönüştürün +Doğrudan bahsedilen ontoloji kavramlarını bulun +Bahsedilen sınıfları birbirine bağlayan özellikleri dahil edin +Gezinme için ters ve ilgili özellikleri ekleyin +Hiyerarşik sorgular için üst/alt sınıfları dahil edin +Sorgu odaklı bir ontoloji bölümü oluşturun + +#### 3. Arka Uç Yönlendirici + +**Amaç**: Sorguları, yapılandırmaya göre uygun arka uç özel sorgu yoluna yönlendirir. + +**Algoritma Açıklaması**: +Arka Uç Yönlendirici, sistem yapılandırmasını inceleyerek hangi grafik arka ucunun (Cassandra veya Cypher tabanlı) etkin olduğunu belirler. Soruyu ve ontoloji bölümünü uygun sorgu oluşturma hizmetine yönlendirir. Yönlendirici, birincil arka uç kullanılamıyorsa, aynı zamanda birden fazla arka uç arasında yük dengeleme veya yedekleme mekanizmalarını da destekleyebilir. + +**Yönlendirme Mantığı**: +Sistem ayarlarından yapılandırılmış arka uç türünü kontrol edin +Cassandra arka uçları için `onto-query-sparql`'a yönlendirin +Neo4j/Memgraph/FalkorDB için `onto-query-cypher`'a yönlendirin +Sorgu dağıtımı ile çoklu arka uç yapılandırmalarını destekleyin +Arıza ve yük dengeleme senaryolarını işleyin + +#### 4. SPARQL Sorgu Oluşturma (`onto-query-sparql`) + +**Amaç**: Doğal dil sorularını, Cassandra üzerinde yürütme için SPARQL sorgularına dönüştürür. + +**Algoritma Açıklaması**: +SPARQL sorgu oluşturucu, soruyu ve ontoloji bölümünü alır ve Cassandra arka ucu üzerinde yürütülmek üzere optimize edilmiş bir SPARQL sorgusu oluşturur. RDF/OWL semantiğini içeren, SPARQL'e özel bir şablon kullanan bir istem hizmeti kullanır. Oluşturucu, Cassandra işlemleriyle verimli bir şekilde çevrilebilen özellik yolları, isteğe bağlı ifadeler ve filtreler gibi SPARQL kalıplarını anlar. + +**SPARQL Oluşturma İstem Şablonu**: +``` +Generate a SPARQL query for the following question using the provided ontology. + +ONTOLOGY CLASSES: +{classes} + +ONTOLOGY PROPERTIES: +{properties} + +RULES: +- Use proper RDF/OWL semantics +- Include relevant prefixes +- Use property paths for hierarchical queries +- Add FILTER clauses for constraints +- Optimise for Cassandra backend + +QUESTION: {question} + +SPARQL QUERY: +``` + +#### 5. Şifre Sorgu Üretimi (`onto-query-cypher`) + +**Amaç**: Doğal dil sorularını, grafik veritabanları için Şifre sorgularına dönüştürür. + +**Algoritma Açıklaması**: +Şifre sorgu üreticisi, Neo4j, Memgraph ve FalkorDB için optimize edilmiş yerel Şifre sorguları oluşturur. Ontoloji sınıflarını düğüm etiketlerine ve özellikleri ilişkilerle eşler, Şifre'nin desen eşleştirme sözdizimini kullanır. Üretici, ilişki yönü ipuçları, indeks kullanımı ve sorgu planlama ipuçları gibi Şifre'ye özgü optimizasyonları içerir. + +**Şifre Üretim İstem Şablonu**: +``` +Generate a Cypher query for the following question using the provided ontology. + +NODE LABELS (from classes): +{classes} + +RELATIONSHIP TYPES (from properties): +{properties} + +RULES: +- Use MATCH patterns for graph traversal +- Include WHERE clauses for filters +- Use aggregation functions when needed +- Optimise for graph database performance +- Consider index hints for large datasets + +QUESTION: {question} + +CYPHER QUERY: +``` + +#### 6. SPARQL-Cassandra Sorgu Motoru (`sparql-cassandra`) + +**Amaç**: Python rdflib kullanarak Cassandra'ya karşı SPARQL sorgularını yürütür. + +**Algoritma Açıklaması**: +SPARQL-Cassandra motoru, Python'ın rdflib kütüphanesini ve özel bir Cassandra arka uç depolama alanını kullanan bir SPARQL işlemcisi uygular. SPARQL grafik desenlerini, birleştirmeleri, filtreleri ve toplama işlemlerini işleyerek uygun Cassandra CQL sorgularına dönüştürür. Motor, semantik yapıyı korurken Cassandra'nın sütun ailesi depolama modeline göre optimizasyon sağlayan bir RDF-Cassandra eşleme sürdürür. + +**Uygulama Özellikleri**: +Cassandra için rdflib Store arayüzü uygulaması +Yaygın desenlerle SPARQL 1.1 sorgu desteği +Üçlü desenlerin CQL'ye verimli çevirisi +Özellik yolları ve hiyerarşik sorgular için destek +Büyük veri kümeleri için sonuç akışı +Bağlantı havuzu ve sorgu önbelleği + +**Örnek Çeviri**: +```sparql +SELECT ?animal WHERE { + ?animal rdf:type :Animal . + ?animal :hasOwner "John" . +} +``` +İndeksleri ve bölüm anahtarlarını kullanan, optimize edilmiş Cassandra sorgularına çevrilir. + +#### 7. Cypher Sorgu Yürütücüsü (`cypher-executor`) + +**Amaç**: Neo4j, Memgraph ve FalkorDB'ye karşı Cypher sorgularını yürütür. + +**Algoritma Açıklaması**: +Cypher yürütücüsü, farklı grafik veritabanları arasında Cypher sorgularını yürütmek için birleşik bir arayüz sağlar. Veritabanına özgü bağlantı protokollerini, sorgu optimizasyonu ipuçlarını ve sonuç biçimi normalizasyonunu işler. Yürütücü, her veritabanı türü için uygun olan yeniden deneme mantığını, bağlantı havuzunu ve işlem yönetimini içerir. + +**Çoklu Veritabanı Desteği**: +**Neo4j**: Bolt protokolü, işlem fonksiyonları, indeks ipuçları +**Memgraph**: Özel protokol, akışlı sonuçlar, analitik sorgular +**FalkorDB**: Redis protokolü adaptasyonu, bellek içi optimizasyonlar + +**Yürütme Özellikleri**: +Veritabanından bağımsız bağlantı yönetimi +Sorgu doğrulaması ve sözdizimi kontrolü +Zaman aşımı ve kaynak limiti uygulama +Sonuç sayfalama ve akış +Veritabanı türüne göre performans izleme +Veritabanı örnekleri arasında otomatik geçiş + +#### 8. Cevap Oluşturucu + +**Amaç**: Sorgu sonuçlarından doğal bir dil cevabı oluşturur. + +**Algoritma Açıklaması**: +Cevap Oluşturucu, yapılandırılmış sorgu sonuçlarını ve orijinal soruyu alır, ardından kapsamlı bir cevap oluşturmak için istem hizmetini kullanır. Basit şablon tabanlı yanıtlardan farklı olarak, grafik verilerini sorunun bağlamında yorumlamak için bir LLM kullanır, karmaşık ilişkileri, toplamaları ve çıkarımları işler. Oluşturucu, ontoloji yapısına ve grafikten alınan belirli üçlülere başvurarak akıl yürütmesini açıklayabilir. + +**Cevap Oluşturma Süreci**: +Sorgu sonuçlarını yapılandırılmış bir bağlama dönüştürür +Açıklık için ilgili ontoloji tanımlarını ekler +Soru ve sonuçlarla bir istem oluşturur +LLM aracılığıyla doğal dil cevabı oluşturur +Cevabı sorgu amacına göre doğrular +Gerekirse belirli grafik varlıklarına alıntılar ekler + +### Mevcut Hizmetlerle Entegrasyon + +#### GraphRAG ile İlişki + +**Tamamlayıcı**: onto-query semantik hassasiyet sağlarken, GraphRAG geniş kapsamlı bir kapsama sahiptir. +**Paylaşılan Altyapı**: Her ikisi de aynı bilgi grafiğini ve istem hizmetlerini kullanır. +**Sorgu Yönlendirmesi**: Sistem, sorunun türüne göre sorguları en uygun hizmete yönlendirebilir. +**Hibrit Mod**: Kapsamlı cevaplar için her iki yaklaşımı da birleştirebilir. + +#### OntoRAG Çıkarma ile İlişki + +**Paylaşılan Ontolojiler**: kg-extract-ontology tarafından yüklenen aynı ontoloji yapılandırmalarını kullanır. +**Paylaşılan Vektör Deposu**: Çıkarma hizmetinden alınan bellek içi gömülmeleri yeniden kullanır. +**Tutarlı Semantikler**: Sorgular, aynı ontolojik kısıtlamalarla oluşturulmuş grafikler üzerinde çalışır. + +### Sorgu Örnekleri + +#### Örnek 1: Basit Varlık Sorgusu +**Soru**: "Hangi hayvanlar memelidir?" +**Ontoloji Eşleşmesi**: [hayvan, memeli, subClassOf] +**Oluşturulan Sorgu**: +```cypher +MATCH (a:animal)-[:subClassOf*]->(m:mammal) +RETURN a.name +``` + +#### Örnek 2: İlişki Sorgusu +**Soru**: "Hangi belgeler John Smith tarafından yazılmıştır?" +**Ontoloji Eşleşmesi**: [belge, kişi, yazarıdır] +**Oluşturulan Sorgu**: +```cypher +MATCH (d:document)-[:has-author]->(p:person {name: "John Smith"}) +RETURN d.title, d.date +``` + +#### Örnek 3: Toplama Sorgusu +**Soru**: "Kedilerin kaç tane bacağı vardır?" +**Ontoloji Eşleşmesi**: [kedi, bacak sayısı (veri tipi özelliği)] +**Oluşturulan Sorgu**: +```cypher +MATCH (c:cat) +RETURN c.name, c.number_of_legs +``` + +### Yapılandırma + +```yaml +onto-query: + embedding_model: "text-embedding-3-small" + vector_store: + shared_with_extractor: true # Reuse kg-extract-ontology's store + query_builder: + model: "gpt-4" + temperature: 0.1 + max_query_length: 1000 + graph_executor: + timeout: 30000 # ms + max_results: 1000 + answer_generator: + model: "gpt-4" + temperature: 0.3 + max_tokens: 500 +``` + +### Performans Optimizasyonları + +#### Sorgu Optimizasyonu + +**Ontoloji Budama**: Sadece gerekli ontoloji öğelerini istemlerde kullanın. +**Sorgu Önbelleği**: Sıkça sorulan soruları ve sorgularını önbelleğe alın. +**Sonuç Önbelleği**: Aynı sorgular için sonuçları belirli bir zaman aralığında saklayın. +**Toplu İşleme**: Birden fazla ilgili soruyu tek bir grafik geçişiyle işleyin. + +#### Ölçeklenebilirlik Hususları + +**Dağıtık Çalıştırma**: Alt sorguları grafik bölümlerine göre paralel hale getirin. +**Artan Sonuçlar**: Büyük veri kümeleri için sonuçları akış şeklinde gönderin. +**Yük Dengeleme**: Sorgu yükünü birden fazla hizmet örneğine dağıtın. +**Kaynak Havuzları**: Grafik veritabanlarına bağlantı havuzlarını yönetin. + +### Hata Yönetimi + +#### Hata Senaryoları + +1. **Geçersiz Sorgu Oluşturma**: GraphRAG'e veya basit anahtar kelime aramasına geri dönün. +2. **Ontoloji Uyuşmazlığı**: Aramayı daha geniş bir ontoloji alt kümesine genişletin. +3. **Sorgu Zaman Aşımı**: Sorguyu basitleştirin veya zaman aşımı süresini artırın. +4. **Boş Sonuçlar**: Sorguyu yeniden formüle etmeyi veya ilgili soruları önerin. +5. **LLM Hizmeti Hatası**: Önbelleğe alınmış sorguları veya şablon tabanlı yanıtları kullanın. + +### İzleme Metrikleri + +Soru karmaşıklığı dağılımı +Ontoloji bölüm boyutları +Sorgu oluşturma başarı oranı +Grafik sorgu yürütme süresi +Cevap kalitesi puanları +Önbellek isabet oranları +Hata frekansları (türlere göre) + +## Gelecek Geliştirmeler + +1. **Ontoloji Öğrenimi**: Çıkarma kalıplarına göre ontolojileri otomatik olarak genişletin. +2. **Güvenilirlik Puanlama**: Çıkarılan üçlülere güvenilirlik puanları atayın. +3. **Açıklama Oluşturma**: Üçlü çıkarma için gerekçeler sağlayın. +4. **Aktif Öğrenme**: Belirsiz çıkarmalar için insan doğrulaması isteyin. + +## Güvenlik Hususları + +1. **İstem Enjeksiyonu Önleme**: İstem oluşturulmadan önce parça metnini temizleyin. +2. **Kaynak Limitleri**: Vektör deposu için bellek kullanımını sınırlayın. +3. **Hız Sınırlama**: İstem başına çıkarma isteklerini sınırlayın. +4. **Denetim Kaydı**: Tüm çıkarma isteklerini ve sonuçlarını izleyin. + +## Test Stratejisi + +### Birim Testleri + +Çeşitli formatlarda ontoloji yükleyici +Gömme oluşturma ve depolama +Cümle bölme algoritmaları +Vektör benzerliği hesaplamaları +Üçlü ayrıştırma ve doğrulama + +### Entegrasyon Testleri + +Uçtan uca çıkarma hattı +Yapılandırma hizmeti entegrasyonu +İstem hizmeti etkileşimi +Eşzamanlı çıkarma işleme + +### Performans Testleri + +Büyük ontoloji işleme (1000+ sınıf) +Yüksek hacimli parça işleme +Yük altında bellek kullanımı +Gecikme ölçümleri + +## Teslimat Planı + +### Genel Bakış + +OntoRAG sistemi, her fazda kademeli değer sağlayan ve tamamlanmış sisteme doğru ilerleyen dört ana fazda teslim edilecektir. Plan, öncelikle temel çıkarma yeteneklerini, ardından sorgu işlevselliğini ve ardından optimizasyonları ve gelişmiş özellikleri eklemeyi hedeflemektedir. + +### 1. Faz: Temel ve Temel Çıkarma + +**Hedef**: Basit vektör eşleştirmesiyle temel, ontoloji odaklı çıkarma hattını kurun. + +#### 1. Adım: Ontoloji Yönetimi Temeli +Ontoloji yapılandırma yükleyici uygulayın (`OntologyLoader`). +Ontoloji JSON yapılarını ayrıştırın ve doğrulayın. +Bellekte ontoloji depolama ve erişim kalıplarını oluşturun. +Ontoloji yenileme mekanizmasını uygulayın. + +**Başarı Kriterleri**: +Ontoloji yapılandırmalarını başarıyla yükleyin ve ayrıştırın. +Ontoloji yapısını ve tutarlılığını doğrulayın. +Birden fazla eşzamanlı ontolojiyi işleyin. + +#### 2. Adım: Vektör Deposu Uygulaması +Başlangıç prototipi olarak basit NumPy tabanlı bir vektör deposu uygulayın. +FAISS vektör deposu uygulamasını ekleyin. +Vektör deposu arayüzü soyutlamasını oluşturun. +Yapılandırılabilir eşiklerle benzerlik araması uygulayın. + +**Başarı Kriterleri**: +Gömme vektörlerini verimli bir şekilde depola ve geri yükle +<100ms gecikmeyle benzerlik araması yap +NumPy ve FAISS arka uçlarını destekle + +#### 1.3 Adımı: Ontoloji Gömme İşlem Hattı +Gömme hizmetiyle entegre ol +`OntologyEmbedder` bileşenini uygula +Tüm ontoloji öğeleri için gömmeler oluştur +Vektör deposunda meta verilerle birlikte gömmeleri depola + +**Başarı Kriterleri**: +Sınıflar ve özellikler için gömmeler oluştur +Uygun meta verilerle birlikte gömmeleri depola +Ontoloji güncellemelerinde gömmeleri yeniden oluştur + +#### 1.4 Adımı: Metin İşleme Bileşenleri +NLTK/spaCy kullanarak cümle bölücü uygula +Cümleleri ve adlandırılmış varlıkları çıkar +Metin segmenti hiyerarşisi oluştur +Metin segmentleri için gömmeler oluştur + +**Başarı Kriterleri**: +Metni doğru bir şekilde cümlelere böl +Anlamlı cümleleri çıkar +Bağlam ilişkilerini koru + +#### 1.5 Adımı: Ontoloji Seçim Algoritması +Metin ve ontoloji arasındaki benzerlik eşleştirmesini uygula +Ontoloji öğeleri için bağımlılık çözümlemesi oluştur +Minimal, tutarlı ontoloji alt kümeleri oluştur +Alt küme oluşturma performansını optimize et + +**Başarı Kriterleri**: +İlgili ontoloji öğelerini >%80 doğrulukla seç +Tüm gerekli bağımlılıkları dahil et +Alt kümeleri <500ms içinde oluştur + +#### 1.6 Adımı: Temel Çıkarma Hizmeti +Çıkarma için istem oluşturma uygula +İstem hizmetiyle entegre ol +Üçlü yanıtları ayrıştır ve doğrula +`kg-extract-ontology` hizmet uç noktası oluştur + +**Başarı Kriterleri**: +Ontolojiye uygun üçlüler çıkar +Tüm üçlüleri ontolojiye göre doğrula +Çıkarma hatalarını düzgün bir şekilde işle + +### 2. Aşama: Sorgu Sistemi Uygulaması + +**Amaç**: Çoklu arka uç desteğiyle ontolojiye duyarlı sorgu yetenekleri ekle. + +#### 2.1 Adımı: Sorgu Temel Bileşenleri +Soru analizörünü uygula +Sorgular için ontoloji eşleştirici oluştur +Vektör aramayı sorgu bağlamı için uyarlayın +Arka uç yönlendirici bileşeni oluştur + +**Başarı Kriterleri**: +Soruları anlamsal bileşenlere ayır +Soruları ilgili ontoloji öğelerine eşleştir +Sorguları uygun arka uca yönlendir + +#### 2.2 Adımı: SPARQL Yolu Uygulaması +`onto-query-sparql` hizmetini uygula +LLM kullanarak SPARQL sorgu oluşturucu oluştur +SPARQL oluşturma için istem şablonları geliştir +Oluşturulan SPARQL sözdizimini doğrula + +**Başarı Kriterleri**: +Geçerli SPARQL sorguları oluştur +Uygun SPARQL kalıplarını kullan +Karmaşık sorgu türlerini işle + +#### 2.3 Adımı: SPARQL-Cassandra Motoru +Cassandra için rdflib Store arayüzünü uygula +CQL sorgu çevirmeni oluştur +Üçlü kalıp eşleştirmesini optimize et +SPARQL sonuç biçimlendirmesini işle + +**Başarı Kriterleri**: +SPARQL sorgularını Cassandra üzerinde çalıştır +Yaygın SPARQL kalıplarını destekle +Sonuçları standart biçimde döndür + +#### 2.4 Adımı: Cypher Yolu Uygulaması +`onto-query-cypher` hizmetini uygula +LLM kullanarak Cypher sorgu oluşturucu oluştur +Cypher oluşturma için istem şablonları geliştir +Oluşturulan Cypher sözdizimini doğrula + +**Başarı Kriterleri**: +Geçerli Cypher sorguları oluştur +Uygun grafik kalıplarını kullan +Neo4j, Memgraph, FalkorDB'yi destekle + +#### 2.5 Adımı: Cypher Yürütücü +Çoklu veritabanı Cypher yürütücüsünü uygulayın +Bolt protokolünü destekleyin (Neo4j/Memgraph) +Redis protokolünü destekleyin (FalkorDB) +Sonuç normalleştirmesini yönetin + +**Başarı Kriterleri**: +Cypher'ı tüm hedef veritabanlarında çalıştırın +Veritabanına özgü farklılıkları ele alın +Bağlantı havuzlarını verimli bir şekilde koruyun + +#### 2. Adım: Cevap Üretimi +Cevap üretici bileşenini uygulayın +Cevap sentezi için istemler oluşturun +Sorgu sonuçlarını LLM'nin kullanabileceği bir formata dönüştürün +Doğal dil cevapları oluşturun + +**Başarı Kriterleri**: +Sorgu sonuçlarından doğru cevaplar üretin +Orijinal sorudan bağlamı koruyun +Açık, öz cevaplar sağlayın + +### 3. Aşama: Optimizasyon ve Güvenilirlik + +**Amaç**: Performansı optimize edin, önbellekleme ekleyin, hata yönetimini iyileştirin ve güvenilirliği artırın. + +#### 3.1 Adım: Performans Optimizasyonu +Gömme önbelleklemesini uygulayın +Sorgu sonucu önbelleklemesini ekleyin +FAISS IVF indeksleriyle vektör aramayı optimize edin +Gömme işlemleri için toplu işleme uygulayın + +**Başarı Kriterleri**: +Ortalama sorgu gecikmesini %50 azaltın +10 kat daha fazla eşzamanlı istek destekleyin +Saniyeden daha kısa yanıt sürelerini koruyun + +#### 3.2 Adım: Gelişmiş Hata Yönetimi +Kapsamlı bir hata kurtarma mekanizması uygulayın +Sorgu yolları arasında yedekleme mekanizmaları ekleyin +Üstel geri çekilme ile yeniden deneme mantığı oluşturun +Hata günlüğünü ve tanılama bilgilerini iyileştirin + +**Başarı Kriterleri**: +Tüm hata senaryolarını sorunsuz bir şekilde ele alın +Arka uçlar arasında otomatik geçiş +Hata ayıklama için ayrıntılı hata raporlama + +#### 3.3 Adım: İzleme ve Gözlemlenebilirlik +Performans metrikleri toplama ekleyin +Sorgu izlemeyi uygulayın +Sağlık kontrol uç noktaları oluşturun +Kaynak kullanımı izlemeyi ekleyin + +**Başarı Kriterleri**: +Tüm önemli performans göstergelerini izleyin +Engelleri hızlı bir şekilde belirleyin +Sistem sağlığını gerçek zamanlı olarak izleyin + +#### 3.4 Adım: Yapılandırma Yönetimi +Dinamik yapılandırma güncellemelerini uygulayın +Yapılandırma doğrulama ekleyin +Yapılandırma şablonları oluşturun +Ortam özelinde ayarlara destek sağlayın + +**Başarı Kriterleri**: +Yapılandırmayı yeniden başlatmadan güncelleyin +Tüm yapılandırma değişikliklerini doğrulayın +Birden çok dağıtım ortamını destekleyin + +### 4. Aşama: Gelişmiş Özellikler + +**Amaç**: Üretim dağıtımı ve gelişmiş işlevsellik için sofistike yetenekler ekleyin. + +#### 4.1 Adım: Çoklu Ontoloji Desteği +Ontoloji seçimi mantığını uygulayın +Çapraz ontoloji sorgularını destekleyin +Ontoloji sürümlemesini yönetin +Ontoloji birleştirme yetenekleri oluşturun + +**Başarı Kriterleri**: +Birden çok ontoloji üzerinde sorgu yapın +Ontoloji çakışmalarını ele alın +Ontoloji evrimini destekleyin + +#### 4.2 Adım: Akıllı Sorgu Yönlendirme +Performans odaklı yönlendirme uygulayın +Sorgu karmaşıklığı analizini ekleyin +Adaptif yönlendirme algoritmaları oluşturun +Yollar için A/B testlerini destekleyin + +**Başarı Kriterleri**: +Sorguları en uygun şekilde yönlendirin +Sorgu performansından öğrenin +Yönlendirmeyi zamanla iyileştirin + +#### 4.3. Adım: Gelişmiş Çıkarma Özellikleri +Üçlüler için güvenilirlik puanı ekleyin +Açıklama oluşturma uygulayın +İyileştirme için geri bildirim döngüleri oluşturun +Artımlı öğrenmeyi destekleyin + +**Başarı Kriterleri**: +Güvenilirlik puanları sağlayın +Çıkarma kararlarını açıklayın +Doğruluğu sürekli olarak iyileştirin + +#### 4.4. Adım: Üretim Hazırlığı +Hız sınırlaması ekleyin +Kimlik doğrulama/yetkilendirme uygulayın +Dağıtım otomasyonu oluşturun +Yedekleme ve kurtarma ekleyin + +**Başarı Kriterleri**: +Üretim için uygun güvenlik +Otomatikleştirilmiş dağıtım hattı +Afet kurtarma yeteneği + +### Teslimat Aşamaları + +1. **Aşama 1** (1. Aşamanın Sonu): Temel, ontoloji odaklı çıkarma işleminin çalışır durumda olması +2. **Aşama 2** (2. Aşamanın Sonu): Hem SPARQL hem de Cypher yollarına sahip tam sorgu sistemi +3. **Aşama 3** (3. Aşamanın Sonu): Optimize edilmiş, sağlam sistem, üretim ortamına hazır +4. **Aşama 4** (4. Aşamanın Sonu): Gelişmiş özelliklere sahip, üretim için hazır sistem + +### Risk Azaltma + +#### Teknik Riskler +**Vektör Depolama Ölçeklenebilirliği**: NumPy ile başlayın, FAISS'e kademeli olarak geçin +**Sorgu Oluşturma Doğruluğu**: Doğrulama ve yedekleme mekanizmaları uygulayın +**Arka Uç Uyumluluğu**: Her veritabanı türüyle kapsamlı bir şekilde test edin +**Performans Engelleri**: Erken ve sık sık profil oluşturun, yinelemeli olarak optimize edin + +#### İşletim Riskleri +**Ontoloji Kalitesi**: Doğrulama ve tutarlılık kontrolü uygulayın +**Hizmet Bağımlılıkları**: Devre kesiciler ve yedeklemeler ekleyin +**Kaynak Kısıtlamaları**: İzleyin ve uygun limitler ayarlayın +**Veri Tutarlılığı**: Uygun işlem yönetimi uygulayın + +### Başarı Metrikleri + +#### 1. Aşama Başarı Metrikleri +Çıkarma doğruluğu: %90'ın üzerinde ontoloji uyumluluğu +İşleme hızı: Parça başına <1 saniye +Ontoloji yükleme süresi: <10 saniye +Vektör arama gecikmesi: <100 ms + +#### 2. Aşama Başarı Metrikleri +Sorgu başarı oranı: %95'in üzerinde +Sorgu gecikmesi: Uçtan uca <2 saniye +Arka uç uyumluluğu: Hedef veritabanları için %100 +Cevap doğruluğu: Mevcut verilere göre %85'in üzerinde + +#### 3. Aşama Başarı Metrikleri +Sistem çalışma süresi: >%99.9 +Hata kurtarma oranı: >%95 +Önbellek isabet oranı: >%60 +Eşzamanlı kullanıcılar: >100 + +#### 4. Aşama Başarı Metrikleri +Çoklu ontoloji sorguları: Tamamen destekleniyor +Yönlendirme optimizasyonu: Gecikmede %30 azalma +Güvenilirlik puanı doğruluğu: >%90 +Üretim dağıtımı: Sıfır kesintiyle güncellemeler + +## Referanslar + +[OWL 2 Web Ontology Language](https://www.w3.org/TR/owl2-overview/) +[GraphRAG Architecture](https://github.com/microsoft/graphrag) +[Sentence Transformers](https://www.sbert.net/) +[FAISS Vector Search](https://github.com/facebookresearch/faiss) +[spaCy NLP Library](https://spacy.io/) +[rdflib Documentation](https://rdflib.readthedocs.io/) +[Neo4j Bolt Protocol](https://neo4j.com/docs/bolt/current/) diff --git a/docs/tech-specs/ontorag.zh-cn.md b/docs/tech-specs/ontorag.zh-cn.md new file mode 100644 index 00000000..3ea73344 --- /dev/null +++ b/docs/tech-specs/ontorag.zh-cn.md @@ -0,0 +1,1067 @@ +# OntoRAG: 基于本体的知识提取和查询技术规范 + +## 概述 + +OntoRAG 是一个基于本体的知识提取和查询系统,它在从非结构化文本中提取知识三元组以及查询结果知识图谱的过程中,强制执行严格的语义一致性。类似于 GraphRAG,但具有正式的本体约束,OntoRAG 确保所有提取的三元组都符合预定义的本体结构,并提供具有语义意识的查询功能。 + +该系统使用向量相似性匹配,动态选择相关的本体子集,用于提取和查询操作,从而实现专注于上下文相关的处理,同时保持语义有效性。 + +**服务名称**: `kg-extract-ontology` + +## 目标 + +**符合本体的提取**: 确保所有提取的三元组严格符合加载的本体。 +**动态上下文选择**: 使用嵌入向量来选择每个文本块相关的本体子集。 +**语义一致性**: 维护类层次结构、属性域/范围以及约束。 +**高效处理**: 使用内存中的向量存储,以实现快速的本体元素匹配。 +**可扩展架构**: 支持多个并发的本体,具有不同的领域。 + +## 背景 + +当前的知识提取服务 (`kg-extract-definitions`, `kg-extract-relationships`) 在没有正式约束的情况下运行,这可能会产生不一致或不兼容的三元组。OntoRAG 通过以下方式解决此问题: + +1. 加载正式的本体,定义有效的类和属性。 +2. 使用嵌入向量将文本内容与相关的本体元素进行匹配。 +3. 限制提取,仅产生符合本体的三元组。 +4. 提供对提取知识的语义验证。 + +这种方法结合了神经网络提取的灵活性和正式知识表示的严谨性。 + +## 技术设计 + +### 架构 + +OntoRAG 系统由以下组件组成: + +``` +┌─────────────────┐ +│ Configuration │ +│ Service │ +└────────┬────────┘ + │ Ontologies + ▼ +┌─────────────────┐ ┌──────────────┐ +│ kg-extract- │────▶│ Embedding │ +│ ontology │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ │ + ▼ ▼ +┌─────────────────┐ ┌──────────────┐ +│ In-Memory │◀────│ Ontology │ +│ Vector Store │ │ Embedder │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Sentence │────▶│ Chunker │ +│ Splitter │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Ontology │────▶│ Vector │ +│ Selector │ │ Search │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ ┌──────────────┐ +│ Prompt │────▶│ Prompt │ +│ Constructor │ │ Service │ +└────────┬────────┘ └──────────────┘ + │ + ▼ +┌─────────────────┐ +│ Triple Output │ +└─────────────────┘ +``` + +### 组件详情 + +#### 1. 本体加载器 + +**目的**: 使用事件驱动的更新,从配置服务检索和解析本体配置。 + +**实现**: +本体加载器使用 TrustGraph 的 ConfigPush 队列接收事件驱动的本体配置更新。当类型为“本体”的配置元素被添加或修改时,加载器通过 config-update 队列接收更新,并解析包含元数据、类、对象属性和数据类型属性的 JSON 结构。这些解析的本体存储在内存中,作为结构化的对象,以便在提取过程中高效访问。 + +**主要操作**: +订阅 config-update 队列,用于本体类型配置 +将 JSON 本体结构解析为 OntologyClass 和 OntologyProperty 对象 +验证本体结构和一致性 +将解析的本体缓存到内存中,以便快速访问 +使用 flow-specific 向量存储,处理每个流程的数据 + +**实现位置**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_loader.py` + +#### 2. 本体嵌入器 + +**目的**: 为所有本体元素创建向量嵌入,以实现语义相似性匹配。 + +**实现**: +本体嵌入器处理加载的本体中的每个元素(类、对象属性和数据类型属性),并使用 EmbeddingsClientSpec 服务生成向量嵌入。对于每个元素,它将元素的标识符、标签和描述(注释)组合成文本表示。然后,将此文本转换为高维向量嵌入,以捕获其语义含义。这些嵌入存储在每个流程的内存 FAISS 向量存储中,以及有关元素类型、源本体和完整定义的元数据。嵌入器会自动从第一个嵌入响应中检测嵌入维度。 + +**主要操作**: +从元素 ID、标签和注释创建文本表示 +通过 EmbeddingsClientSpec 生成嵌入(使用 asyncio.gather 进行批量处理) +将嵌入以及全面的元数据存储在 FAISS 向量存储中 +按本体、元素类型和元素 ID 进行索引,以便高效检索 +自动检测嵌入维度,用于向量存储初始化 +使用独立的向量存储,处理每个流程的嵌入模型 + +**实现位置**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_embedder.py` + +#### 3. 文本处理器(句子分割器) + +**目的**: 将文本块分解为细粒度的片段,以便进行精确的本体匹配。 + +**实现**: +文本处理器使用 NLTK 进行句子分词和词性标注,将传入的文本块分解为句子。它通过尝试下载 `punkt_tab` 和 `averaged_perceptron_tagger_eng` 来处理 NLTK 版本兼容性,如果需要,可以回退到较旧的版本。每个文本块被拆分为独立的句子,这些句子可以独立地与本体元素进行匹配。 + +**主要操作**: +使用 NLTK 句子分词,将文本拆分为句子 +处理 NLTK 版本兼容性(punkt_tab vs punkt) +创建包含文本和位置信息的 TextSegment 对象 +支持完整的句子和单独的块 + +**实现位置**: `trustgraph-flow/trustgraph/extract/kg/ontology/text_processor.py` + +#### 4. 本体选择器 + +**目的**: 识别当前文本块中最相关的本体元素子集。 + +**实现**: +本体选择器使用 FAISS 向量相似性搜索,在文本片段和本体元素之间执行语义匹配。对于文本块中的每个句子,它生成一个嵌入,并在向量存储中搜索最相似的本体元素,使用具有可配置阈值(默认值为 0.3)的余弦相似度。在收集所有相关元素后,它执行全面的依赖关系解析:如果选择了类,则包含其父类;如果选择了属性,则添加其域和范围类。此外,对于每个选定的类,它会自动包含**引用该类的所有属性**(无论是其域还是范围)。这确保了提取过程可以访问所有相关的关系属性。 + +**关键操作**: +为每个文本段(句子)生成嵌入向量 +在 FAISS 向量存储中执行 k 近邻搜索(top_k=10,threshold=0.3) +应用相似度阈值以过滤弱匹配项 +解决依赖关系(父类、领域、范围) +**自动包含与所选类相关的所有属性**(领域/范围匹配) +构建包含所有必需关系的连贯本体子集 +消除多次出现的元素 + +**实现位置**: `trustgraph-flow/trustgraph/extract/kg/ontology/ontology_selector.py` + +#### 5. 提示构建 + +**目的**: 创建结构化的提示,引导 LLM 仅提取符合本体的元组。 + +**实现**: +提取服务使用从 `ontology-prompt.md` 加载的 Jinja2 模板,该模板格式化本体子集和文本以供 LLM 提取。该模板使用 Jinja2 语法动态地循环遍历类、对象属性和数据类型属性,并显示它们的描述、领域、范围和层次关系。该提示包含关于仅使用提供的本体元素的严格规则,并请求 JSON 格式的输出以进行一致的解析。 + +**关键操作**: +使用 Jinja2 模板,对本体元素进行循环 +格式化具有父关系(subclass_of)和注释的类 +格式化具有领域/范围约束和注释的属性 +包含明确的提取规则和输出格式要求 +使用模板 ID "extract-with-ontologies" 调用提示服务 + +**模板位置**: `ontology-prompt.md` +**实现位置**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` (build_extraction_variables 方法) + +#### 6. 主提取服务 + +**目的**: 协调所有组件以执行端到端的基于本体的三元组提取。 + +**实现**: +主提取服务 (KgExtractOntology) 是管理完整提取工作流程的编排层。它使用 TrustGraph 的 FlowProcessor 模式,并对每个流程进行组件初始化。当收到本体配置更新时,它会初始化或更新流程特定的组件(本体加载器、嵌入器、文本处理器、选择器)。当接收到用于处理的文本块时,它会协调管道:将文本拆分为段,通过向量搜索找到相关的本体元素,构建受约束的提示,调用提示服务,解析和验证响应,生成本体定义三元组,并发出内容三元组和实体上下文。 + +**提取管道**: +1. 通过 chunks-input 队列接收文本块 +2. 如果需要,初始化流程组件(在第一个块或配置更新时) +3. 使用 NLTK 将文本拆分为句子 +4. 搜索 FAISS 向量存储以查找相关的本体概念 +5. 构建包含自动属性包含的本体子集 +6. 构建 Jinja2 模板的提示变量 +7. 使用 extract-with-ontologies 模板调用提示服务 +8. 将 JSON 响应解析为结构化的三元组 +9. 验证三元组并扩展 URI 为完整的本体 URI +10. 生成本体定义三元组(具有标签/注释/领域/范围的类和属性) +11. 从所有三元组构建实体上下文 +12. 发送到三元组和实体上下文队列 + +**关键特性**: +每个流程的向量存储支持不同的嵌入模型 +通过 config-update 队列驱动的本体更新 +使用本体 URI 自动扩展 URI +将本体元素添加到知识图谱中,包含完整的元数据 +实体上下文包含内容和本体元素 + +**实现位置**: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py` + +### 配置 + +该服务使用 TrustGraph 的标准配置方法,通过命令行参数: + +```bash +kg-extract-ontology \ + --id kg-extract-ontology \ + --pulsar-host localhost:6650 \ + --input-queue chunks \ + --config-input-queue config-update \ + --output-queue triples \ + --entity-contexts-output-queue entity-contexts +``` + +**关键配置参数**: +`similarity_threshold`: 0.3 (默认值,可在代码中配置) +`top_k`: 10 (每个段检索的本体元素数量) +`vector_store`: Per-flow FAISS IndexFlatIP with auto-detected dimensions +`text_processor`: NLTK with punkt_tab sentence tokenization +`prompt_template`: "extract-with-ontologies" (Jinja2 模板) + +**本体配置**: +本体通过 config-update 队列以 type="ontology" 的方式动态加载。 + +### 数据流 + +1. **初始化阶段** (每个流程): + 通过 config-update 队列接收本体配置 + 将本体 JSON 解析为 OntologyClass 和 OntologyProperty 对象 + 使用 EmbeddingsClientSpec 为所有本体元素生成嵌入向量 + 将嵌入向量存储在每个流程的 FAISS 向量存储中 + 从第一个响应中自动检测嵌入维度 + +2. **提取阶段** (每个块): + 从 chunks-input 队列接收块 + 使用 NLTK 将块拆分为句子 + 计算每个句子的嵌入向量 + 在 FAISS 向量存储中搜索相关的本体元素 + 构建包含自动属性的本体子集 + 使用文本和本体构建 Jinja2 模板变量 + 使用 extract-with-ontologies 模板调用提示服务 + 解析 JSON 响应并验证三元组 + 使用本体 URI 扩展 URI + 生成本体定义三元组 + 从所有三元组构建实体上下文 + 发送到 triples 和 entity-contexts 队列 + +### 内存向量存储 + +**目的**: 为本体元素匹配提供快速、基于内存的相似性搜索。 + +**实现: FAISS** + +该系统使用 **FAISS (Facebook AI Similarity Search)**,并使用 IndexFlatIP 进行精确的余弦相似性搜索。 关键特性: + +**IndexFlatIP**: 使用内积进行精确的余弦相似性搜索 +**自动检测**: 从第一个嵌入响应确定维度 +**每个流程的存储**: 每个流程都有独立的向量存储,用于不同的嵌入模型 +**归一化**: 在索引之前,所有向量都进行归一化 +**批量操作**: 适用于初始本体加载的高效批量添加 + +**实现位置**: `trustgraph-flow/trustgraph/extract/kg/ontology/vector_store.py` + +### 本体子集选择算法 + +**目的**: 动态地为每个文本块选择本体中最小的相关部分。 + +**详细算法步骤**: + +1. **文本分割**: + 使用 NLP 句子检测将输入块拆分为句子 + 从每个句子中提取名词短语、动词短语和命名实体 + 创建一个层次结构,保留上下文的段落 + +2. **嵌入生成**: + 为每个文本段(句子和短语)生成向量嵌入 + 使用与本体元素相同的嵌入模型 + 缓存重复段的嵌入,以提高性能 + +3. **相似性搜索**: + 对于每个文本段嵌入,搜索向量存储 + 检索最相似的 k 个(例如,10)本体元素 + 应用相似性阈值(例如,0.7)以过滤弱匹配 + 汇总所有段的结果,跟踪匹配频率 + +4. **依赖关系解析**: + 对于每个选定的类,递归地包含所有父类,直到根类 + 对于每个选定的属性,包含其域和范围类 + 对于反向属性,确保包含两个方向 + 如果本体中存在等效类,则添加它们 + +5. **子集构建**: + 在保留关系的同时,对收集的元素进行去重 + 组织为类、对象属性和数据类型属性 + 确保所有约束和关系都得到保留 + 创建一个自包含的迷你本体,该本体是有效且完整的 + +**示例演示**: +给定的文本: "The brown dog chased the white cat up the tree." +段落: ["brown dog", "white cat", "tree", "chased"] +匹配的元素: [dog (class), cat (class), animal (parent), chases (property)] +依赖关系: [animal (dog 和 cat 的父类), lifeform (animal 的父类)] +最终子集: 包含 animal 层次结构和 chase 关系的完整迷你本体 + +### 三元组验证 + +**目的**: 确保所有提取的三元组严格符合本体约束。 + +**验证算法**: + +1. **类验证 (Class Validation)**: + 验证主体是否是本体子集中定义的类的实例。 + 对于对象属性,验证对象是否也是有效的类实例。 + 检查类名是否与本体的类字典匹配。 + 处理类层次结构 - 子类的实例对于父类的约束有效。 + +2. **属性验证 (Property Validation)**: + 确认谓词是否对应于本体子集中的属性。 + 区分对象属性(实体到实体)和数据类型属性(实体到字面量)。 + 验证属性名称是否完全匹配(如果存在,则考虑命名空间)。 + +3. **域/范围检查 (Domain/Range Checking)**: + 对于每个用作谓语的属性,检索其域和范围。 + 验证主体的类型是否匹配或继承自属性的域。 + 验证对象的类型是否匹配或继承自属性的范围。 + 对于数据类型属性,验证对象是否是具有正确 XSD 类型的字面量。 + +4. **基数验证 (Cardinality Validation)**: + 跟踪每个主体属性的使用计数。 + 检查最小基数 - 确保必需的属性存在。 + 检查最大基数 - 确保属性未被使用太多次。 + 对于函数属性,确保每个主体最多有一个值。 + +5. **数据类型验证 (Datatype Validation)**: + 根据其声明的 XSD 类型解析字面值。 + 验证整数是否为有效数字,日期是否格式正确等。 + 检查字符串模式,如果定义了正则表达式约束。 + 确保 URI 对于 xsd:anyURI 类型是格式正确的。 + +**验证示例 (Validation Example)**: +三元组: ("Buddy", "has-owner", "John") +检查 "Buddy" 是否被标记为可以具有 "has-owner" 属性的类。 +检查 "has-owner" 是否存在于本体中。 +验证域约束:主体必须是 "Pet" 类型或子类型。 +验证范围约束:对象必须是 "Person" 类型或子类型。 +如果有效,则添加到输出;如果无效,则记录违规并跳过。 + +## 性能考虑 (Performance Considerations) + +### 优化策略 (Optimisation Strategies) + +1. **嵌入缓存 (Embedding Caching)**: 缓存常用文本片段的嵌入。 +2. **批量处理 (Batch Processing)**: 并行处理多个片段。 +3. **向量存储索引 (Vector Store Indexing)**: 使用近似最近邻算法进行大型本体。 +4. **提示优化 (Prompt Optimisation)**: 通过仅包含必要的本体元素来最小化提示大小。 +5. **结果缓存 (Result Caching)**: 缓存相同块的提取结果。 + +### 可扩展性 (Scalability) + +**水平扩展 (Horizontal Scaling)**: 具有共享本体缓存的多个提取器实例。 +**本体分区 (Ontology Partitioning)**: 通过域分割大型本体。 +**流式处理 (Streaming Processing)**: 在不进行批处理的情况下处理到达的块。 +**内存管理 (Memory Management)**: 定期清理未使用的嵌入。 + +## 错误处理 (Error Handling) + +### 故障场景 (Failure Scenarios) + +1. **缺少本体 (Missing Ontologies)**: 回退到不受约束的提取。 +2. **嵌入服务故障 (Embedding Service Failure)**: 使用缓存的嵌入或跳过语义匹配。 +3. **提示服务超时 (Prompt Service Timeout)**: 使用指数退避重试。 +4. **无效三元组格式 (Invalid Triple Format)**: 记录并跳过格式错误的元组。 +5. **本体不一致 (Ontology Inconsistencies)**: 报告冲突并使用最具体的有效元素。 + +### 监控 (Monitoring) + +需要跟踪的关键指标: + +本体加载时间和内存使用情况。 +嵌入生成延迟。 +向量搜索性能。 +提示服务响应时间。 +三元组提取准确性。 +本体符合性率。 + +## 迁移路径 (Migration Path) + +### 从现有提取器 (From Existing Extractors) + +1. **并行运行 (Parallel Operation)**: 初始阶段与现有提取器并行运行。 +2. **逐步推广 (Gradual Rollout)**: 从特定文档类型开始。 +3. **质量比较 (Quality Comparison)**: 将输出质量与现有提取器进行比较。 +4. **完全迁移 (Full Migration)**: 在验证质量后,替换现有提取器。 + +### 本体开发 (Ontology Development) + +1. **从现有知识生成初始本体 (Bootstrap from Existing)**: 从现有知识生成初始本体。 +2. **基于提取模式进行迭代改进 (Iterative Refinement)**: 基于提取模式进行迭代改进。 +3. **领域专家审查 (Domain Expert Review)**: 由领域专家进行验证。 +4. **基于提取反馈进行持续改进 (Continuous Improvement)**: 基于提取反馈进行持续改进。 + +## 基于本体的查询服务 (Ontology-Sensitive Query Service) + +### 概述 (Overview) + +基于本体的查询服务提供多种查询路径,以支持不同的后端图存储。它利用本体知识,为 Cassandra(通过 SPARQL)和基于 Cypher 的图存储(Neo4j、Memgraph、FalkorDB)提供精确、语义化的问答功能。 + +**服务组件 (Service Components)**: +`onto-query-sparql`: 将自然语言转换为 Cassandra 的 SPARQL。 +`sparql-cassandra`: 用于 Cassandra 的 rdflib 的 SPARQL 查询层。 +`onto-query-cypher`: 将自然语言转换为图数据库的 Cypher。 +`cypher-executor`: 用于 Neo4j/Memgraph/FalkorDB 的 Cypher 查询执行。 + +### 架构 + +``` + ┌─────────────────┐ + │ User Query │ + └────────┬────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Question │────▶│ Sentence │ + │ Analyser │ │ Splitter │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Ontology │────▶│ Vector │ + │ Matcher │ │ Store │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Backend Router │ + └────────┬────────┘ + │ + ┌───────────┴───────────┐ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ onto-query- │ │ onto-query- │ + │ sparql │ │ cypher │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ SPARQL │ │ Cypher │ + │ Generator │ │ Generator │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ sparql- │ │ cypher- │ + │ cassandra │ │ executor │ + └────────┬────────┘ └────────┬────────┘ + │ │ + ▼ ▼ + ┌─────────────────┐ ┌─────────────────┐ + │ Cassandra │ │ Neo4j/Memgraph/ │ + │ │ │ FalkorDB │ + └────────┬────────┘ └────────┬────────┘ + │ │ + └────────────┬───────────────┘ + │ + ▼ + ┌─────────────────┐ ┌──────────────┐ + │ Answer │────▶│ Prompt │ + │ Generator │ │ Service │ + └────────┬────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Final Answer │ + └─────────────────┘ +``` + +### 查询处理流程 + +#### 1. 问题分析器 + +**目的**: 将用户问题分解为语义组件,用于本体匹配。 + +**算法描述**: +问题分析器接收输入的自然语言问题,并使用与提取流程相同的句子分割方法将其分解为有意义的片段。它识别问题中提到的关键实体、关系和约束。每个片段都用于分析问题类型(事实、聚合、比较等)以及预期的答案格式。这种分解有助于确定本体的哪些部分最相关,以回答问题。 + +**主要操作**: +将问题拆分为句子和短语 +识别问题类型和意图 +提取提到的实体和关系 +检测问题中的约束和过滤器 +确定预期的答案格式 + +#### 2. 用于查询的本体匹配器 + +**目的**: 识别回答问题所需的相关的本体子集。 + +**算法描述**: +与提取流程中的本体选择器类似,但针对问题解答进行了优化。匹配器为问题片段生成嵌入向量,并在向量存储中搜索相关的本体元素。但是,它侧重于找到用于查询构造的概念,而不是提取。它扩展选择范围,包括可能在图探索过程中被遍历的关联属性,即使这些属性没有明确地在问题中提到。例如,如果询问“员工”,它可能包括“工作单位”、“管理”、“汇报”等属性,这些属性可能与查找员工信息相关。 + +**匹配策略**: +嵌入问题片段 +查找直接提到的本体概念 +包含连接到提到的类的属性 +添加反向和相关属性以进行遍历 +包含父/子类以进行层次查询 +构建面向查询的本体分区 + +#### 3. 后端路由器 + +**目的**: 根据配置,将查询路由到适当的后端特定的查询路径。 + +**算法描述**: +后端路由器检查系统配置以确定哪个图后端处于活动状态(Cassandra 或 Cypher 驱动)。它将问题和本体分区路由到适当的查询生成服务。路由器还可以支持跨多个后端进行负载平衡,或者在主后端不可用时提供回退机制。 + +**路由逻辑**: +检查系统设置中配置的后端类型 +路由到 `onto-query-sparql` 用于 Cassandra 后端 +路由到 `onto-query-cypher` 用于 Neo4j/Memgraph/FalkorDB +支持具有查询分发的多个后端配置 +处理故障转移和负载平衡场景 + +#### 4. SPARQL 查询生成 (`onto-query-sparql`) + +**目的**: 将自然语言问题转换为 SPARQL 查询,以便在 Cassandra 上执行。 + +**算法描述**: +SPARQL 查询生成器接收问题和本体分区,并构造一个针对 Cassandra 后端优化的 SPARQL 查询。它使用带有 SPARQL 特定模板的提示服务,该模板包含 RDF/OWL 语义。该生成器理解 SPARQL 模式,例如属性路径、可选子句和过滤器,这些模式可以有效地转换为 Cassandra 操作。 + +**SPARQL 生成提示模板**: +``` +Generate a SPARQL query for the following question using the provided ontology. + +ONTOLOGY CLASSES: +{classes} + +ONTOLOGY PROPERTIES: +{properties} + +RULES: +- Use proper RDF/OWL semantics +- Include relevant prefixes +- Use property paths for hierarchical queries +- Add FILTER clauses for constraints +- Optimise for Cassandra backend + +QUESTION: {question} + +SPARQL QUERY: +``` + +#### 5. Cypher 查询生成 (`onto-query-cypher`) + +**目的**: 将自然语言问题转换为用于图数据库的 Cypher 查询。 + +**算法描述**: +Cypher 查询生成器创建针对 Neo4j、Memgraph 和 FalkorDB 优化的原生 Cypher 查询。它将本体类映射到节点标签,并将属性映射到关系,使用 Cypher 的模式匹配语法。该生成器包含 Cypher 专有的优化,例如关系方向提示、索引使用和查询计划提示。 + +**Cypher 生成提示模板**: +``` +Generate a Cypher query for the following question using the provided ontology. + +NODE LABELS (from classes): +{classes} + +RELATIONSHIP TYPES (from properties): +{properties} + +RULES: +- Use MATCH patterns for graph traversal +- Include WHERE clauses for filters +- Use aggregation functions when needed +- Optimise for graph database performance +- Consider index hints for large datasets + +QUESTION: {question} + +CYPHER QUERY: +``` + +#### 6. SPARQL-Cassandra 查询引擎 (`sparql-cassandra`) + +**目的**: 使用 Python rdflib 对 Cassandra 执行 SPARQL 查询。 + +**算法描述**: +SPARQL-Cassandra 引擎使用 Python 的 rdflib 库实现了一个 SPARQL 处理器,并具有自定义的 Cassandra 后端存储。它将 SPARQL 图模式转换为适当的 Cassandra CQL 查询,处理连接、过滤器和聚合。该引擎维护一个 RDF 到 Cassandra 的映射,该映射保留了语义结构,同时针对 Cassandra 的列族存储模型进行了优化。 + +**实现特性**: +用于 Cassandra 的 rdflib Store 接口实现 +支持常见的 SPARQL 1.1 查询模式 +将三元组模式高效地转换为 CQL +支持属性路径和分层查询 +用于大型数据集的结果流式传输 +连接池和查询缓存 + +**示例翻译**: +```sparql +SELECT ?animal WHERE { + ?animal rdf:type :Animal . + ?animal :hasOwner "John" . +} +``` +将其翻译为针对 Cassandra 的优化查询,利用索引和分区键。 + +#### 7. Cypher 查询执行器 (`cypher-executor`) + +**目的**: 对 Neo4j、Memgraph 和 FalkorDB 执行 Cypher 查询。 + +**算法描述**: +Cypher 执行器提供了一个统一的接口,用于在不同的图数据库上执行 Cypher 查询。它处理特定于数据库的连接协议、查询优化提示以及结果格式标准化。执行器包括针对每种数据库类型的重试逻辑、连接池和事务管理。 + +**多数据库支持**: +**Neo4j**: Bolt 协议、事务函数、索引提示 +**Memgraph**: 自定义协议、流式结果、分析查询 +**FalkorDB**: Redis 协议适配、内存优化 + +**执行特性**: +数据库无关的连接管理 +查询验证和语法检查 +超时和资源限制强制 +结果分页和流式传输 +按数据库类型进行性能监控 +数据库实例之间的自动故障转移 + +#### 8. 答案生成器 + +**目的**: 从查询结果中合成自然语言答案。 + +**算法描述**: +答案生成器接收结构化的查询结果和原始问题,然后使用提示服务生成一个全面的答案。与简单的基于模板的响应不同,它使用 LLM 来在问题的上下文中解释图数据,处理复杂的关联、聚合和推断。生成器可以通过引用本体结构和从图中检索的特定三元组来解释其推理过程。 + +**答案生成过程**: +将查询结果格式化为结构化上下文 +包含相关的本体定义以提高清晰度 +构建包含问题和结果的提示 +通过 LLM 生成自然语言答案 +验证答案是否符合查询意图 +如果需要,添加指向特定图实体的引用 + +### 与现有服务的集成 + +#### 与 GraphRAG 的关系 + +**互补**: onto-query 提供语义精度,而 GraphRAG 提供广泛的覆盖范围 +**共享基础设施**: 两者都使用相同的知识图谱和提示服务 +**查询路由**: 系统可以根据问题类型将查询路由到最合适的服务 +**混合模式**: 可以结合两种方法来获得全面的答案 + +#### 与 OntoRAG 提取的关系 + +**共享本体**: 使用与 kg-extract-ontology 加载的相同的本体配置 +**共享向量存储**: 重用提取服务中的内存嵌入 +**一致的语义**: 查询在具有相同本体约束的图上运行 + +### 查询示例 + +#### 示例 1: 简单实体查询 +**问题**: "哪些动物是哺乳动物?" +**本体匹配**: [animal, mammal, subClassOf] +**生成的查询**: +```cypher +MATCH (a:animal)-[:subClassOf*]->(m:mammal) +RETURN a.name +``` + +#### 示例 2:关系查询 +**问题**: "哪些文档是由 John Smith 撰写的?" +**本体匹配**: [document, person, has-author] +**生成的查询**: +```cypher +MATCH (d:document)-[:has-author]->(p:person {name: "John Smith"}) +RETURN d.title, d.date +``` + +#### 示例 3:聚合查询 +**问题**: "猫有多少条腿?" +**本体匹配**: [猫, 腿的数量 (数据类型属性)] +**生成的查询**: +```cypher +MATCH (c:cat) +RETURN c.name, c.number_of_legs +``` + +### 配置 + +```yaml +onto-query: + embedding_model: "text-embedding-3-small" + vector_store: + shared_with_extractor: true # Reuse kg-extract-ontology's store + query_builder: + model: "gpt-4" + temperature: 0.1 + max_query_length: 1000 + graph_executor: + timeout: 30000 # ms + max_results: 1000 + answer_generator: + model: "gpt-4" + temperature: 0.3 + max_tokens: 500 +``` + +### 性能优化 + +#### 查询优化 + +**本体图剪枝**: 仅在提示中包含必要的本体图元素 +**查询缓存**: 缓存常见问题及其查询 +**结果缓存**: 存储相同查询的结果,并在指定时间窗口内 +**批量处理**: 使用单次图遍历处理多个相关问题 + +#### 可扩展性考虑 + +**分布式执行**: 在图分区上并行化子查询 +**增量结果**: 为大型数据集流式传输结果 +**负载均衡**: 在多个服务实例之间分配查询负载 +**资源池**: 管理到图数据库的连接池 + +### 错误处理 + +#### 故障场景 + +1. **无效查询生成**: 回退到 GraphRAG 或简单的关键词搜索 +2. **本体图不匹配**: 扩展搜索范围到更广泛的本体图子集 +3. **查询超时**: 简化查询或增加超时时间 +4. **无结果**: 建议重新构建查询或提供相关问题 +5. **LLM 服务故障**: 使用缓存的查询或基于模板的响应 + +### 监控指标 + +问题复杂性分布 +本体图分区大小 +查询生成成功率 +图查询执行时间 +答案质量分数 +缓存命中率 +按类型划分的错误频率 + +## 未来增强功能 + +1. **本体图学习**: 根据提取模式自动扩展本体图 +2. **置信度评分**: 为提取的三元组分配置信度分数 +3. **解释生成**: 提供三元组提取的推理 +4. **主动学习**: 请求人工验证不确定的提取结果 + +## 安全性考虑 + +1. **防止提示注入**: 在构建提示之前,清理文本块 +2. **资源限制**: 限制向量存储的内存使用量 +3. **速率限制**: 限制每个客户端的提取请求 +4. **审计日志**: 跟踪所有提取请求和结果 + +## 测试策略 + +### 单元测试 + +带各种格式的本体图加载器 +嵌入式生成和存储 +句子分割算法 +向量相似度计算 +三元组解析和验证 + +### 集成测试 + +端到端提取管道 +配置服务集成 +提示服务交互 +并发提取处理 + +### 性能测试 + +处理大型本体图(1000+ 个类) +处理大量文本块 +负载下的内存使用情况 +延迟基准测试 + +## 发布计划 + +### 概述 + +OntoRAG 系统将分四个主要阶段交付,每个阶段都提供增量价值,并逐步构建到完整的系统。 该计划侧重于首先建立核心提取功能,然后添加查询功能,然后是优化和高级功能。 + +### 第一阶段:基础和核心提取 + +**目标**: 建立基于本体图驱动的基本提取管道,并使用简单的向量匹配。 + +#### 第一步:本体图管理基础 +实现本体图配置加载器 (`OntologyLoader`) +解析和验证本体图 JSON 结构 +创建内存中的本体图存储和访问模式 +实现本体图刷新机制 + +**成功标准**: +成功加载和解析本体图配置 +验证本体图结构和一致性 +处理多个并发本体图 + +#### 第二步:向量存储实现 +实现简单的基于 NumPy 的向量存储作为初始原型 +添加 FAISS 向量存储实现 +创建向量存储接口抽象 +实现具有可配置阈值的相似度搜索 + +**成功标准**: +高效地存储和检索嵌入向量 +以<100毫秒的延迟执行相似性搜索 +支持NumPy和FAISS后端 + +#### 步骤 1.3:本体嵌入管道 +与嵌入服务集成 +实现 `OntologyEmbedder` 组件 +为所有本体元素生成嵌入向量 +将嵌入向量及其元数据存储在向量存储中 + +**成功标准**: +为类和属性生成嵌入向量 +存储带有适当元数据的嵌入向量 +在本体更新时重建嵌入向量 + +#### 步骤 1.4:文本处理组件 +使用NLTK/spaCy实现句子分割器 +提取短语和命名实体 +创建文本段层级结构 +为文本段生成嵌入向量 + +**成功标准**: +准确地将文本分割成句子 +提取有意义的短语 +维护上下文关系 + +#### 步骤 1.5:本体选择算法 +实现文本与本体之间的相似性匹配 +构建本体元素的依赖关系解析 +创建最小的、连贯的本体子集 +优化子集生成性能 + +**成功标准**: +使用>80%的精度选择相关的本体元素 +包含所有必要的依赖项 +在<500毫秒内生成子集 + +#### 步骤 1.6:基本提取服务 +实现用于提取的提示构建 +与提示服务集成 +解析和验证三元组响应 +创建 `kg-extract-ontology` 服务端点 + +**成功标准**: +提取符合本体的三元组 +验证所有三元组与本体 +优雅地处理提取错误 + +### 第二阶段:查询系统实现 + +**目标**: 添加具有对多个后端支持的本体感知查询功能。 + +#### 步骤 2.1:查询基础组件 +实现问题分析器 +创建用于查询的本体匹配器 +调整向量搜索以适应查询上下文 +构建后端路由器组件 + +**成功标准**: +将问题分析成语义组件 +将问题与相关的本体元素匹配 +将查询路由到适当的后端 + +#### 步骤 2.2:SPARQL路径实现 +实现 `onto-query-sparql` 服务 +使用LLM创建SPARQL查询生成器 +开发用于SPARQL生成的提示模板 +验证生成的SPARQL语法 + +**成功标准**: +生成有效的SPARQL查询 +使用适当的SPARQL模式 +处理复杂的查询类型 + +#### 步骤 2.3:SPARQL-Cassandra引擎 +为Cassandra实现rdflib Store接口 +创建CQL查询翻译器 +优化三元组模式匹配 +处理SPARQL结果格式 + +**成功标准**: +在Cassandra上执行SPARQL查询 +支持常见的SPARQL模式 +以标准格式返回结果 + +#### 步骤 2.4:Cypher路径实现 +实现 `onto-query-cypher` 服务 +使用LLM创建Cypher查询生成器 +开发用于Cypher生成的提示模板 +验证生成的Cypher语法 + +**成功标准**: +生成有效的Cypher查询 +使用适当的图模式 +支持Neo4j、Memgraph、FalkorDB + +#### 步骤 2.5:Cypher执行器 +Implement multi-database Cypher executor +Support Bolt protocol (Neo4j/Memgraph) +Support Redis protocol (FalkorDB) +Handle result normalization + +**Success Criteria**: +Execute Cypher on all target databases +Handle database-specific differences +Maintain connection pools efficiently + +#### Step 2.6: Answer Generation +Implement answer generator component +Create prompts for answer synthesis +Format query results for LLM consumption +Generate natural language answers + +**Success Criteria**: +Generate accurate answers from query results +Maintain context from original question +Provide clear, concise responses + +### Phase 3: Optimization and Robustness + +**Goal**: Optimize performance, add caching, improve error handling, and enhance reliability. + +#### Step 3.1: Performance Optimization +Implement embedding caching +Add query result caching +Optimize vector search with FAISS IVF indexes +Implement batch processing for embeddings + +**Success Criteria**: +Reduce average query latency by 50% +Support 10x more concurrent requests +Maintain sub-second response times + +#### Step 3.2: Advanced Error Handling +Implement comprehensive error recovery +Add fallback mechanisms between query paths +Create retry logic with exponential backoff +Improve error logging and diagnostics + +**Success Criteria**: +Gracefully handle all failure scenarios +Automatic failover between backends +Detailed error reporting for debugging + +#### Step 3.3: Monitoring and Observability +Add performance metrics collection +Implement query tracing +Create health check endpoints +Add resource usage monitoring + +**Success Criteria**: +Track all key performance indicators +Identify bottlenecks quickly +Monitor system health in real-time + +#### Step 3.4: Configuration Management +Implement dynamic configuration updates +Add configuration validation +Create configuration templates +Support environment-specific settings + +**Success Criteria**: +Update configuration without restart +Validate all configuration changes +Support multiple deployment environments + +### Phase 4: Advanced Features + +**Goal**: Add sophisticated capabilities for production deployment and enhanced functionality. + +#### Step 4.1: Multi-Ontology Support +Implement ontology selection logic +Support cross-ontology queries +Handle ontology versioning +Create ontology merge capabilities + +**Success Criteria**: +Query across multiple ontologies +Handle ontology conflicts +Support ontology evolution + +#### Step 4.2: Intelligent Query Routing +Implement performance-based routing +Add query complexity analysis +Create adaptive routing algorithms +Support A/B testing for paths + +**Success Criteria**: +Route queries optimally +Learn from query performance +Improve routing over time + +#### Step 4.3: Advanced Extraction Features +Add confidence scoring for triples +Implement explanation generation +Create feedback loops for improvement +Support incremental learning + +**Success Criteria**: +Provide confidence scores +Explain extraction decisions +Continuously improve accuracy + +#### Step 4.4: Production Hardening +Add rate limiting +Implement authentication/authorization +Create deployment automation +Add backup and recovery + +**Success Criteria**: +Production-ready security +Automated deployment pipeline +Disaster recovery capability + +### Delivery Milestones + +1. **Milestone 1** (End of Phase 1): Basic ontology-driven extraction operational +2. **Milestone 2** (End of Phase 2): Full query system with both SPARQL and Cypher paths +3. **Milestone 3** (End of Phase 3): Optimized, robust system ready for staging +4. **Milestone 4** (End of Phase 4): Production-ready system with advanced features + +### Risk Mitigation + +#### Technical Risks +**Vector Store Scalability**: Start with NumPy, migrate to FAISS gradually +**Query Generation Accuracy**: Implement validation and fallback mechanisms +**Backend Compatibility**: Test extensively with each database type +**Performance Bottlenecks**: Profile early and often, optimize iteratively + +#### Operational Risks +**Ontology Quality**: Implement validation and consistency checking +**Service Dependencies**: Add circuit breakers and fallbacks +**Resource Constraints**: Monitor and set appropriate limits +**Data Consistency**: Implement proper transaction handling + +### Success Metrics + +#### Phase 1 Success Metrics +Extraction accuracy: >90% ontology conformance +Processing speed: <1 second per chunk +Ontology load time: <10 seconds +Vector search latency: <100ms + +#### Phase 2 Success Metrics +Query success rate: >95% +Query latency: <2 seconds end-to-end +Backend compatibility: 100% for target databases +Answer accuracy: >85% based on available data + +#### Phase 3 Success Metrics +System uptime: >99.9% +Error recovery rate: >95% +Cache hit rate: >60% +Concurrent users: >100 + +#### Phase 4 Success Metrics +Multi-ontology queries: Fully supported +Routing optimization: 30% latency reduction +Confidence scoring accuracy: >90% +Production deployment: Zero-downtime updates + +## References + +[OWL 2 Web Ontology Language](https://www.w3.org/TR/owl2-overview/) +[GraphRAG Architecture](https://github.com/microsoft/graphrag) +[Sentence Transformers](https://www.sbert.net/) +[FAISS Vector Search](https://github.com/facebookresearch/faiss) +[spaCy NLP Library](https://spacy.io/) +[rdflib Documentation](https://rdflib.readthedocs.io/) +[Neo4j Bolt Protocol](https://neo4j.com/docs/bolt/current/) diff --git a/docs/tech-specs/openapi-spec.ar.md b/docs/tech-specs/openapi-spec.ar.md new file mode 100644 index 00000000..db1a6c3d --- /dev/null +++ b/docs/tech-specs/openapi-spec.ar.md @@ -0,0 +1,231 @@ +# مواصفات OpenAPI - المواصفات الفنية + +## الهدف + +إنشاء مواصفات OpenAPI 3.1 شاملة وقابلة للتطوير لواجهة TrustGraph REST API التي: +توثق جميع نقاط النهاية REST. +تستخدم `$ref` خارجية من أجل modularity وقابلية الصيانة. +تتوافق مباشرة مع كود مترجم الرسائل. +توفر مخططات دقيقة للطلبات والاستجابات. + +## المصدر الموثوق + +يتم تعريف واجهة برمجة التطبيقات بواسطة: +**مترجمو الرسائل**: `trustgraph-base/trustgraph/messaging/translators/*.py` +**مدير الموزع**: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +**مدير نقطة النهاية**: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` + +## هيكل الدليل + +``` +openapi/ +├── openapi.yaml # Main entry point +├── paths/ +│ ├── config.yaml # Global services +│ ├── flow.yaml +│ ├── librarian.yaml +│ ├── knowledge.yaml +│ ├── collection-management.yaml +│ ├── flow-services/ # Flow-hosted services +│ │ ├── agent.yaml +│ │ ├── document-rag.yaml +│ │ ├── graph-rag.yaml +│ │ ├── text-completion.yaml +│ │ ├── prompt.yaml +│ │ ├── embeddings.yaml +│ │ ├── mcp-tool.yaml +│ │ ├── triples.yaml +│ │ ├── objects.yaml +│ │ ├── nlp-query.yaml +│ │ ├── structured-query.yaml +│ │ ├── structured-diag.yaml +│ │ ├── graph-embeddings.yaml +│ │ ├── document-embeddings.yaml +│ │ ├── text-load.yaml +│ │ └── document-load.yaml +│ ├── import-export/ +│ │ ├── core-import.yaml +│ │ ├── core-export.yaml +│ │ └── flow-import-export.yaml # WebSocket import/export +│ ├── websocket.yaml +│ └── metrics.yaml +├── components/ +│ ├── schemas/ +│ │ ├── config/ +│ │ ├── flow/ +│ │ ├── librarian/ +│ │ ├── knowledge/ +│ │ ├── collection/ +│ │ ├── ai-services/ +│ │ ├── common/ +│ │ └── errors/ +│ ├── parameters/ +│ ├── responses/ +│ └── examples/ +└── security/ + └── bearerAuth.yaml +``` + +## ربط الخدمات + +### الخدمات العامة (`/api/v1/{kind}`) +`config` - إدارة التكوين +`flow` - دورة حياة التدفق +`librarian` - مكتبة المستندات +`knowledge` - نوى المعرفة +`collection-management` - بيانات وصفية للمجموعة + +### الخدمات المستضافة على التدفق (`/api/v1/flow/{flow}/service/{kind}`) + +**الطلب/الاستجابة:** +`agent`, `text-completion`, `prompt`, `mcp-tool` +`graph-rag`, `document-rag` +`embeddings`, `graph-embeddings`, `document-embeddings` +`triples`, `objects`, `nlp-query`, `structured-query`, `structured-diag` + +**إرسال واستقبال:** +`text-load`, `document-load` + +### الاستيراد/التصدير +`/api/v1/import-core` (POST) +`/api/v1/export-core` (GET) +`/api/v1/flow/{flow}/import/{kind}` (WebSocket) +`/api/v1/flow/{flow}/export/{kind}` (WebSocket) + +### أخرى +`/api/v1/socket` (WebSocket متعدد) +`/api/metrics` (Prometheus) + +## النهج + +### المرحلة الأولى: الإعداد +1. إنشاء هيكل الدليل +2. إنشاء ملف رئيسي `openapi.yaml` مع البيانات الوصفية والخوادم والأمان +3. إنشاء مكونات قابلة لإعادة الاستخدام (أخطاء، معلمات شائعة، مخططات أمان) + +### المرحلة الثانية: المخططات الشائعة +إنشاء مخططات مشتركة تستخدم عبر الخدمات: +`RdfValue`, `Triple` - هياكل RDF/ثلاثية +`ErrorObject` - استجابة الخطأ +`DocumentMetadata`, `ProcessingMetadata` - هياكل البيانات الوصفية +المعلمات الشائعة: `FlowId`, `User`, `Collection` + +### المرحلة الثالثة: الخدمات العامة +لكل خدمة عامة (تكوين، تدفق، أمين مكتبة، معرفة، إدارة المجموعة): +1. إنشاء ملف مسار في `paths/` +2. إنشاء مخطط الطلب في `components/schemas/{service}/` +3. إنشاء مخطط الاستجابة +4. إضافة أمثلة +5. الإشارة من الملف الرئيسي `openapi.yaml` + +### المرحلة الرابعة: الخدمات المستضافة على التدفق +لكل خدمة مستضافة على التدفق: +1. إنشاء ملف مسار في `paths/flow-services/` +2. إنشاء مخططات الطلب/الاستجابة في `components/schemas/ai-services/` +3. إضافة وثائق علامة التدفق حيثما ينطبق +4. الإشارة من الملف الرئيسي `openapi.yaml` + +### المرحلة الخامسة: الاستيراد/التصدير و WebSocket +1. توثيق نقاط النهاية الأساسية للاستيراد/التصدير +2. توثيق أنماط بروتوكول WebSocket +3. توثيق نقاط نهاية استيراد/تصدير WebSocket على مستوى التدفق + +### المرحلة السادسة: التحقق من الصحة +1. التحقق من الصحة باستخدام أدوات التحقق من صحة OpenAPI +2. الاختبار باستخدام واجهة Swagger UI +3. التحقق من تغطية جميع المترجمين + +## اصطلاح تسمية الحقول + +جميع الحقول في JSON تستخدم **kebab-case**: +`flow-id`, `blueprint-name`, `doc-limit`, `entity-limit`، إلخ. + +## إنشاء ملفات المخططات + +لكل مترجم في `trustgraph-base/trustgraph/messaging/translators/`: + +1. **قراءة طريقة مترجم `to_pulsar()`** - يحدد مخطط الطلب +2. **قراءة طريقة مترجم `from_pulsar()`** - يحدد مخطط الاستجابة +3. **استخراج أسماء وأنواع الحقول** +4. **إنشاء مخطط OpenAPI** مع: + أسماء الحقول (kebab-case) + الأنواع (سلسلة، عدد صحيح، منطقي، كائن، مصفوفة) + الحقول المطلوبة + القيم الافتراضية + الأوصاف + +### مثال لعملية التعيين + +```python +# From retrieval.py DocumentRagRequestTranslator +def to_pulsar(self, data: Dict[str, Any]) -> DocumentRagQuery: + return DocumentRagQuery( + query=data["query"], # required string + user=data.get("user", "trustgraph"), # optional string, default "trustgraph" + collection=data.get("collection", "default"), # optional string, default "default" + doc_limit=int(data.get("doc-limit", 20)), # optional integer, default 20 + streaming=data.get("streaming", False) # optional boolean, default false + ) +``` + +الترجمة: + +```yaml +# components/schemas/ai-services/DocumentRagRequest.yaml +type: object +required: + - query +properties: + query: + type: string + description: Search query + user: + type: string + default: trustgraph + collection: + type: string + default: default + doc-limit: + type: integer + default: 20 + description: Maximum number of documents to retrieve + streaming: + type: boolean + default: false + description: Enable streaming responses +``` + +## الاستجابات المتدفقة + +الخدمات التي تدعم التدفق تُرجع استجابات متعددة مع العلامة `end_of_stream`: +`agent`، `text-completion`، `prompt` +`document-rag`، `graph-rag` + +قم بتوثيق هذا النمط في مخطط استجابة كل خدمة. + +## استجابات الأخطاء + +يمكن لجميع الخدمات إرجاع: +```yaml +error: + oneOf: + - type: string + - $ref: '#/components/schemas/ErrorObject' +``` + +حيث أن `ErrorObject` هو: +```yaml +type: object +properties: + type: + type: string + message: + type: string +``` + +## المراجع + +المترجمون: `trustgraph-base/trustgraph/messaging/translators/` +تعيين الموزع: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +توجيه نقطة النهاية: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` +ملخص الخدمة: `API_SERVICES_SUMMARY.md` diff --git a/docs/tech-specs/openapi-spec.es.md b/docs/tech-specs/openapi-spec.es.md new file mode 100644 index 00000000..6e03d525 --- /dev/null +++ b/docs/tech-specs/openapi-spec.es.md @@ -0,0 +1,231 @@ +# Especificación OpenAPI - Especificación Técnica + +## Objetivo + +Crear una especificación OpenAPI 3.1 completa y modular para la puerta de enlace de la API REST de TrustGraph que: +Documente todos los puntos finales REST. +Utilice `$ref` externo para la modularidad y el mantenimiento. +Se mapee directamente con el código del traductor de mensajes. +Proporcione esquemas precisos de solicitud/respuesta. + +## Fuente de la Verdad + +La API está definida por: +**Traductores de Mensajes**: `trustgraph-base/trustgraph/messaging/translators/*.py` +**Administrador del Despachador**: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +**Administrador de Puntos Finales**: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` + +## Estructura de Directorios + +``` +openapi/ +├── openapi.yaml # Main entry point +├── paths/ +│ ├── config.yaml # Global services +│ ├── flow.yaml +│ ├── librarian.yaml +│ ├── knowledge.yaml +│ ├── collection-management.yaml +│ ├── flow-services/ # Flow-hosted services +│ │ ├── agent.yaml +│ │ ├── document-rag.yaml +│ │ ├── graph-rag.yaml +│ │ ├── text-completion.yaml +│ │ ├── prompt.yaml +│ │ ├── embeddings.yaml +│ │ ├── mcp-tool.yaml +│ │ ├── triples.yaml +│ │ ├── objects.yaml +│ │ ├── nlp-query.yaml +│ │ ├── structured-query.yaml +│ │ ├── structured-diag.yaml +│ │ ├── graph-embeddings.yaml +│ │ ├── document-embeddings.yaml +│ │ ├── text-load.yaml +│ │ └── document-load.yaml +│ ├── import-export/ +│ │ ├── core-import.yaml +│ │ ├── core-export.yaml +│ │ └── flow-import-export.yaml # WebSocket import/export +│ ├── websocket.yaml +│ └── metrics.yaml +├── components/ +│ ├── schemas/ +│ │ ├── config/ +│ │ ├── flow/ +│ │ ├── librarian/ +│ │ ├── knowledge/ +│ │ ├── collection/ +│ │ ├── ai-services/ +│ │ ├── common/ +│ │ └── errors/ +│ ├── parameters/ +│ ├── responses/ +│ └── examples/ +└── security/ + └── bearerAuth.yaml +``` + +## Mapeo de Servicios + +### Servicios Globales (`/api/v1/{kind}`) +`config` - Gestión de configuración +`flow` - Ciclo de vida del flujo +`librarian` - Biblioteca de documentos +`knowledge` - Núcleos de conocimiento +`collection-management` - Metadatos de colección + +### Servicios Alojados en el Flujo (`/api/v1/flow/{flow}/service/{kind}`) + +**Solicitud/Respuesta:** +`agent`, `text-completion`, `prompt`, `mcp-tool` +`graph-rag`, `document-rag` +`embeddings`, `graph-embeddings`, `document-embeddings` +`triples`, `objects`, `nlp-query`, `structured-query`, `structured-diag` + +**Enviar y Olvidar:** +`text-load`, `document-load` + +### Importación/Exportación +`/api/v1/import-core` (POST) +`/api/v1/export-core` (GET) +`/api/v1/flow/{flow}/import/{kind}` (WebSocket) +`/api/v1/flow/{flow}/export/{kind}` (WebSocket) + +### Otros +`/api/v1/socket` (WebSocket multiplexado) +`/api/metrics` (Prometheus) + +## Enfoque + +### Fase 1: Configuración +1. Crear estructura de directorios +2. Crear el archivo principal `openapi.yaml` con metadatos, servidores, seguridad +3. Crear componentes reutilizables (errores, parámetros comunes, esquemas de seguridad) + +### Fase 2: Esquemas Comunes +Crear esquemas compartidos utilizados en todos los servicios: +`RdfValue`, `Triple` - Estructuras RDF/triple +`ErrorObject` - Respuesta de error +`DocumentMetadata`, `ProcessingMetadata` - Estructuras de metadatos +Parámetros comunes: `FlowId`, `User`, `Collection` + +### Fase 3: Servicios Globales +Para cada servicio global (configuración, flujo, biblioteca, conocimiento, gestión de colecciones): +1. Crear el archivo de ruta en `paths/` +2. Crear el esquema de solicitud en `components/schemas/{service}/` +3. Crear el esquema de respuesta +4. Agregar ejemplos +5. Referenciar desde el archivo principal `openapi.yaml` + +### Fase 4: Servicios Alojados en el Flujo +Para cada servicio alojado en el flujo: +1. Crear el archivo de ruta en `paths/flow-services/` +2. Crear los esquemas de solicitud/respuesta en `components/schemas/ai-services/` +3. Agregar la documentación de la bandera de transmisión cuando corresponda +4. Referenciar desde el archivo principal `openapi.yaml` + +### Fase 5: Importación/Exportación y WebSocket +1. Documentar los puntos finales principales de importación/exportación +2. Documentar los patrones de protocolo WebSocket +3. Documentar los puntos finales de importación/exportación WebSocket a nivel de flujo + +### Fase 6: Validación +1. Validar con herramientas de validación de OpenAPI +2. Probar con Swagger UI +3. Verificar que todos los traductores estén cubiertos + +## Convención de Nombres de Campos + +Todos los campos JSON utilizan **kebab-case**: +`flow-id`, `blueprint-name`, `doc-limit`, `entity-limit`, etc. + +## Creación de Archivos de Esquema + +Para cada traductor en `trustgraph-base/trustgraph/messaging/translators/`: + +1. **Leer el método del traductor `to_pulsar()`** - Define el esquema de solicitud +2. **Leer el método del traductor `from_pulsar()`** - Define el esquema de respuesta +3. **Extraer nombres y tipos de campos** +4. **Crear el esquema OpenAPI** con: + Nombres de campos (kebab-case) + Tipos (string, integer, boolean, object, array) + Campos obligatorios + Valores predeterminados + Descripciones + +### Ejemplo de Proceso de Mapeo + +```python +# From retrieval.py DocumentRagRequestTranslator +def to_pulsar(self, data: Dict[str, Any]) -> DocumentRagQuery: + return DocumentRagQuery( + query=data["query"], # required string + user=data.get("user", "trustgraph"), # optional string, default "trustgraph" + collection=data.get("collection", "default"), # optional string, default "default" + doc_limit=int(data.get("doc-limit", 20)), # optional integer, default 20 + streaming=data.get("streaming", False) # optional boolean, default false + ) +``` + +Traducción: + +```yaml +# components/schemas/ai-services/DocumentRagRequest.yaml +type: object +required: + - query +properties: + query: + type: string + description: Search query + user: + type: string + default: trustgraph + collection: + type: string + default: default + doc-limit: + type: integer + default: 20 + description: Maximum number of documents to retrieve + streaming: + type: boolean + default: false + description: Enable streaming responses +``` + +## Respuestas de transmisión + +Los servicios que admiten la transmisión devuelven múltiples respuestas con la bandera `end_of_stream`: +`agent`, `text-completion`, `prompt` +`document-rag`, `graph-rag` + +Documente este patrón en el esquema de respuesta de cada servicio. + +## Respuestas de error + +Todos los servicios pueden devolver: +```yaml +error: + oneOf: + - type: string + - $ref: '#/components/schemas/ErrorObject' +``` + +Donde `ErrorObject` es: +```yaml +type: object +properties: + type: + type: string + message: + type: string +``` + +## Referencias + +Traductores: `trustgraph-base/trustgraph/messaging/translators/` +Mapeo del despachador: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +Enrutamiento de puntos finales: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` +Resumen del servicio: `API_SERVICES_SUMMARY.md` diff --git a/docs/tech-specs/openapi-spec.he.md b/docs/tech-specs/openapi-spec.he.md new file mode 100644 index 00000000..6c456acd --- /dev/null +++ b/docs/tech-specs/openapi-spec.he.md @@ -0,0 +1,231 @@ +# מפרט OpenAPI - מפרט טכני + +## מטרה + +ליצור מפרט OpenAPI 3.1 מקיף ומודולרי עבור שער ה-API של TrustGraph REST, אשר: +מתעד את כל נקודות הקצה של REST +משתמש בקוד חיצוני `$ref` לצורך מודולריות ותחזוקה +מתאים ישירות לקוד מתרגם ההודעות +מספק סכימות מדויקות של בקשות/תגובות + +## מקור האמת + +ה-API מוגדר על ידי: +**מתרגמי הודעות**: `trustgraph-base/trustgraph/messaging/translators/*.py` +**מנהל ה-Dispatcher**: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +**מנהל נקודות הקצה**: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` + +## מבנה תיקיות + +``` +openapi/ +├── openapi.yaml # Main entry point +├── paths/ +│ ├── config.yaml # Global services +│ ├── flow.yaml +│ ├── librarian.yaml +│ ├── knowledge.yaml +│ ├── collection-management.yaml +│ ├── flow-services/ # Flow-hosted services +│ │ ├── agent.yaml +│ │ ├── document-rag.yaml +│ │ ├── graph-rag.yaml +│ │ ├── text-completion.yaml +│ │ ├── prompt.yaml +│ │ ├── embeddings.yaml +│ │ ├── mcp-tool.yaml +│ │ ├── triples.yaml +│ │ ├── objects.yaml +│ │ ├── nlp-query.yaml +│ │ ├── structured-query.yaml +│ │ ├── structured-diag.yaml +│ │ ├── graph-embeddings.yaml +│ │ ├── document-embeddings.yaml +│ │ ├── text-load.yaml +│ │ └── document-load.yaml +│ ├── import-export/ +│ │ ├── core-import.yaml +│ │ ├── core-export.yaml +│ │ └── flow-import-export.yaml # WebSocket import/export +│ ├── websocket.yaml +│ └── metrics.yaml +├── components/ +│ ├── schemas/ +│ │ ├── config/ +│ │ ├── flow/ +│ │ ├── librarian/ +│ │ ├── knowledge/ +│ │ ├── collection/ +│ │ ├── ai-services/ +│ │ ├── common/ +│ │ └── errors/ +│ ├── parameters/ +│ ├── responses/ +│ └── examples/ +└── security/ + └── bearerAuth.yaml +``` + +## מיפוי שירותים + +### שירותים גלובליים (`/api/v1/{kind}`) +`config` - ניהול תצורה +`flow` - מחזור חיים של זרימה +`librarian` - ספריית מסמכים +`knowledge` - ליבות ידע +`collection-management` - מטא-דאטה של אוסף + +### שירותים המאוחסנים בתוך זרימה (Flow-Hosted Services) (`/api/v1/flow/{flow}/service/{kind}`) + +**בקשה/תגובה:** +`agent`, `text-completion`, `prompt`, `mcp-tool` +`graph-rag`, `document-rag` +`embeddings`, `graph-embeddings`, `document-embeddings` +`triples`, `objects`, `nlp-query`, `structured-query`, `structured-diag` + +**שליחה והתעלמות (Fire-and-Forget):** +`text-load`, `document-load` + +### ייבוא/ייצוא +`/api/v1/import-core` (POST) +`/api/v1/export-core` (GET) +`/api/v1/flow/{flow}/import/{kind}` (WebSocket) +`/api/v1/flow/{flow}/export/{kind}` (WebSocket) + +### אחר +`/api/v1/socket` (WebSocket מרובה) +`/api/metrics` (Prometheus) + +## גישה + +### שלב 1: הגדרה +1. צור מבנה תיקיות +2. צור את הקובץ הראשי `openapi.yaml` עם מטא-דאטה, שרתים, אבטחה +3. צור רכיבים שניתנים לשימוש חוזר (שגיאות, פרמטרים נפוצים, סכימות אבטחה) + +### שלב 2: סכימות נפוצות +צור סכימות משותפות המשמשות בכל השירותים: +`RdfValue`, `Triple` - מבני RDF/טריפל +`ErrorObject` - תגובת שגיאה +`DocumentMetadata`, `ProcessingMetadata` - מבני מטא-דאטה +פרמטרים נפוצים: `FlowId`, `User`, `Collection` + +### שלב 3: שירותים גלובליים +עבור כל שירות גלובלי (תצורה, זרימה, ספרן, ידע, ניהול אוסף): +1. צור קובץ נתיב ב-`paths/` +2. צור סכימת בקשה ב-`components/schemas/{service}/` +3. צור סכימת תגובה +4. הוסף דוגמאות +5. הפנה מהקובץ הראשי `openapi.yaml` + +### שלב 4: שירותים המאוחסנים בתוך זרימה +עבור כל שירות המאוחסן בתוך זרימה: +1. צור קובץ נתיב ב-`paths/flow-services/` +2. צור סכימות בקשה/תגובה ב-`components/schemas/ai-services/` +3. הוסף תיעוד לדגל סטרימינג במידת הצורך +4. הפנה מהקובץ הראשי `openapi.yaml` + +### שלב 5: ייבוא/ייצוא ו-WebSocket +1. תעד נקודות קצה מרכזיות לייבוא/ייצוא +2. תעד תבניות פרוטוקול WebSocket +3. תעד נקודות קצה של ייבוא/ייצוא ברמת הזרימה של WebSocket + +### שלב 6: אימות +1. אמת באמצעות כלי אימות OpenAPI +2. בדוק באמצעות Swagger UI +3. ודא שכל המתרגמים מכוסים + +## מוסכמות מתן שמות לשדות + +כל השדות ב-JSON משתמשים בפורמט **kebab-case**: +`flow-id`, `blueprint-name`, `doc-limit`, `entity-limit`, וכו'. + +## יצירת קבצי סכימה + +עבור כל מתרגם ב-`trustgraph-base/trustgraph/messaging/translators/`: + +1. **קרא את שיטת המתרגם `to_pulsar()`** - מגדיר סכימת בקשה +2. **קרא את שיטת המתרגם `from_pulsar()`** - מגדיר סכימת תגובה +3. **חלץ שמות שדות וסוגים** +4. **צור סכימה של OpenAPI** עם: + שמות שדות (kebab-case) + סוגים (string, integer, boolean, object, array) + שדות חובה + ערכי ברירת מחדל + תיאורים + +### תהליך מיפוי לדוגמה + +```python +# From retrieval.py DocumentRagRequestTranslator +def to_pulsar(self, data: Dict[str, Any]) -> DocumentRagQuery: + return DocumentRagQuery( + query=data["query"], # required string + user=data.get("user", "trustgraph"), # optional string, default "trustgraph" + collection=data.get("collection", "default"), # optional string, default "default" + doc_limit=int(data.get("doc-limit", 20)), # optional integer, default 20 + streaming=data.get("streaming", False) # optional boolean, default false + ) +``` + +מתורגם ל: + +```yaml +# components/schemas/ai-services/DocumentRagRequest.yaml +type: object +required: + - query +properties: + query: + type: string + description: Search query + user: + type: string + default: trustgraph + collection: + type: string + default: default + doc-limit: + type: integer + default: 20 + description: Maximum number of documents to retrieve + streaming: + type: boolean + default: false + description: Enable streaming responses +``` + +## תגובות סטרימינג + +שירותים התומכים בסטרימינג מחזירים מספר תגובות עם הדגל `end_of_stream`: +`agent`, `text-completion`, `prompt` +`document-rag`, `graph-rag` + +יש לתעד דפוס זה בסכימת התגובות של כל שירות. + +## תגובות שגיאה + +כל השירותים יכולים להחזיר: +```yaml +error: + oneOf: + - type: string + - $ref: '#/components/schemas/ErrorObject' +``` + +היכן ש-`ErrorObject` נמצא: +```yaml +type: object +properties: + type: + type: string + message: + type: string +``` + +## הפניות + +מתרגמים: `trustgraph-base/trustgraph/messaging/translators/` +מיפוי מפיץ: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +ניתוב נקודת קצה: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` +תקציר שירות: `API_SERVICES_SUMMARY.md` diff --git a/docs/tech-specs/openapi-spec.hi.md b/docs/tech-specs/openapi-spec.hi.md new file mode 100644 index 00000000..f4dd8784 --- /dev/null +++ b/docs/tech-specs/openapi-spec.hi.md @@ -0,0 +1,231 @@ +# OpenAPI विनिर्देश - तकनीकी विनिर्देश + +## लक्ष्य + +ट्रस्टग्राफ REST API गेटवे के लिए एक व्यापक, मॉड्यूलर OpenAPI 3.1 विनिर्देश बनाना जो: +सभी REST एंडपॉइंट्स का दस्तावेजीकरण करता है +मॉड्यूलरिटी और रखरखाव के लिए बाहरी `$ref` का उपयोग करता है +सीधे संदेश अनुवाद कोड से मेल खाता है +सटीक अनुरोध/प्रतिक्रिया स्कीमा प्रदान करता है + +## सत्य का स्रोत + +API को निम्नलिखित द्वारा परिभाषित किया गया है: +**संदेश अनुवादक**: `trustgraph-base/trustgraph/messaging/translators/*.py` +**डिस्पैचर मैनेजर**: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +**एंडपॉइंट मैनेजर**: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` + +## निर्देशिका संरचना + +``` +openapi/ +├── openapi.yaml # Main entry point +├── paths/ +│ ├── config.yaml # Global services +│ ├── flow.yaml +│ ├── librarian.yaml +│ ├── knowledge.yaml +│ ├── collection-management.yaml +│ ├── flow-services/ # Flow-hosted services +│ │ ├── agent.yaml +│ │ ├── document-rag.yaml +│ │ ├── graph-rag.yaml +│ │ ├── text-completion.yaml +│ │ ├── prompt.yaml +│ │ ├── embeddings.yaml +│ │ ├── mcp-tool.yaml +│ │ ├── triples.yaml +│ │ ├── objects.yaml +│ │ ├── nlp-query.yaml +│ │ ├── structured-query.yaml +│ │ ├── structured-diag.yaml +│ │ ├── graph-embeddings.yaml +│ │ ├── document-embeddings.yaml +│ │ ├── text-load.yaml +│ │ └── document-load.yaml +│ ├── import-export/ +│ │ ├── core-import.yaml +│ │ ├── core-export.yaml +│ │ └── flow-import-export.yaml # WebSocket import/export +│ ├── websocket.yaml +│ └── metrics.yaml +├── components/ +│ ├── schemas/ +│ │ ├── config/ +│ │ ├── flow/ +│ │ ├── librarian/ +│ │ ├── knowledge/ +│ │ ├── collection/ +│ │ ├── ai-services/ +│ │ ├── common/ +│ │ └── errors/ +│ ├── parameters/ +│ ├── responses/ +│ └── examples/ +└── security/ + └── bearerAuth.yaml +``` + +## सर्विस मैपिंग + +### ग्लोबल सर्विसेज (`/api/v1/{kind}`) +`config` - कॉन्फ़िगरेशन प्रबंधन +`flow` - फ्लो लाइफसाइकिल +`librarian` - दस्तावेज़ लाइब्रेरी +`knowledge` - नॉलेज कोर +`collection-management` - कलेक्शन मेटाडेटा + +### फ्लो-होस्टेड सर्विसेज (`/api/v1/flow/{flow}/service/{kind}`) + +**अनुरोध/प्रतिक्रिया:** +`agent`, `text-completion`, `prompt`, `mcp-tool` +`graph-rag`, `document-rag` +`embeddings`, `graph-embeddings`, `document-embeddings` +`triples`, `objects`, `nlp-query`, `structured-query`, `structured-diag` + +**फायर-एंड-फॉरगेट:** +`text-load`, `document-load` + +### इम्पोर्ट/एक्सपोर्ट +`/api/v1/import-core` (POST) +`/api/v1/export-core` (GET) +`/api/v1/flow/{flow}/import/{kind}` (WebSocket) +`/api/v1/flow/{flow}/export/{kind}` (WebSocket) + +### अन्य +`/api/v1/socket` (WebSocket मल्टीप्लेक्स) +`/api/metrics` (Prometheus) + +## दृष्टिकोण + +### चरण 1: सेटअप +1. डायरेक्टरी संरचना बनाएं +2. मुख्य `openapi.yaml` बनाएं जिसमें मेटाडेटा, सर्वर, सुरक्षा शामिल हो +3. पुन: प्रयोज्य घटक बनाएं (त्रुटियां, सामान्य पैरामीटर, सुरक्षा योजनाएं) + +### चरण 2: सामान्य स्कीमा +साझा स्कीमा बनाएं जिनका उपयोग सेवाओं में किया जाता है: +`RdfValue`, `Triple` - RDF/ट्रिपल संरचनाएं +`ErrorObject` - त्रुटि प्रतिक्रिया +`DocumentMetadata`, `ProcessingMetadata` - मेटाडेटा संरचनाएं +सामान्य पैरामीटर: `FlowId`, `User`, `Collection` + +### चरण 3: ग्लोबल सर्विसेज +प्रत्येक ग्लोबल सर्विस (कॉन्फ़िग, फ्लो, लाइब्रेरियन, नॉलेज, कलेक्शन-मैनेजमेंट) के लिए: +1. `paths/` में पाथ फ़ाइल बनाएं +2. `components/schemas/{service}/` में अनुरोध स्कीमा बनाएं +3. प्रतिक्रिया स्कीमा बनाएं +4. उदाहरण जोड़ें +5. मुख्य `openapi.yaml` से संदर्भ लें + +### चरण 4: फ्लो-होस्टेड सर्विसेज +प्रत्येक फ्लो-होस्टेड सर्विस के लिए: +1. `paths/flow-services/` में पाथ फ़ाइल बनाएं +2. `components/schemas/ai-services/` में अनुरोध/प्रतिक्रिया स्कीमा बनाएं +3. जहां लागू हो, स्ट्रीमिंग फ़्लैग दस्तावेज़ जोड़ें +4. मुख्य `openapi.yaml` से संदर्भ लें + +### चरण 5: इम्पोर्ट/एक्सपोर्ट और WebSocket +1. मुख्य इम्पोर्ट/एक्सपोर्ट एंडपॉइंट्स का दस्तावेज़ बनाएं +2. WebSocket प्रोटोकॉल पैटर्न का दस्तावेज़ बनाएं +3. फ्लो-लेवल इम्पोर्ट/एक्सपोर्ट WebSocket एंडपॉइंट्स का दस्तावेज़ बनाएं + +### चरण 6: सत्यापन +1. OpenAPI सत्यापन उपकरणों के साथ सत्यापित करें +2. Swagger UI के साथ परीक्षण करें +3. सत्यापित करें कि सभी अनुवादक कवर किए गए हैं + +## फ़ील्ड नामकरण सम्मेलन + +सभी JSON फ़ील्ड **केबाब-केस** का उपयोग करते हैं: +`flow-id`, `blueprint-name`, `doc-limit`, `entity-limit`, आदि। + +## स्कीमा फ़ाइलें बनाना + +प्रत्येक अनुवादक के लिए `trustgraph-base/trustgraph/messaging/translators/`: + +1. **अनुवादक `to_pulsar()` विधि पढ़ें** - अनुरोध स्कीमा को परिभाषित करता है +2. **अनुवादक `from_pulsar()` विधि पढ़ें** - प्रतिक्रिया स्कीमा को परिभाषित करता है +3. **फ़ील्ड नाम और प्रकार निकालें** +4. **OpenAPI स्कीमा बनाएं** जिसमें: + फ़ील्ड नाम (केबाब-केस) + प्रकार (स्ट्रिंग, पूर्णांक, बूलियन, ऑब्जेक्ट, सरणी) + आवश्यक फ़ील्ड + डिफ़ॉल्ट + विवरण + +### उदाहरण मैपिंग प्रक्रिया + +```python +# From retrieval.py DocumentRagRequestTranslator +def to_pulsar(self, data: Dict[str, Any]) -> DocumentRagQuery: + return DocumentRagQuery( + query=data["query"], # required string + user=data.get("user", "trustgraph"), # optional string, default "trustgraph" + collection=data.get("collection", "default"), # optional string, default "default" + doc_limit=int(data.get("doc-limit", 20)), # optional integer, default 20 + streaming=data.get("streaming", False) # optional boolean, default false + ) +``` + +अनुवाद: + +```yaml +# components/schemas/ai-services/DocumentRagRequest.yaml +type: object +required: + - query +properties: + query: + type: string + description: Search query + user: + type: string + default: trustgraph + collection: + type: string + default: default + doc-limit: + type: integer + default: 20 + description: Maximum number of documents to retrieve + streaming: + type: boolean + default: false + description: Enable streaming responses +``` + +## स्ट्रीमिंग प्रतिक्रियाएं + +वे सेवाएं जो स्ट्रीमिंग का समर्थन करती हैं, वे `end_of_stream` ध्वज के साथ कई प्रतिक्रियाएं लौटाती हैं: +`agent`, `text-completion`, `prompt` +`document-rag`, `graph-rag` + +इस पैटर्न को प्रत्येक सेवा की प्रतिक्रिया स्कीमा में प्रलेखित करें। + +## त्रुटि प्रतिक्रियाएं + +सभी सेवाएं निम्नलिखित लौटा सकती हैं: +```yaml +error: + oneOf: + - type: string + - $ref: '#/components/schemas/ErrorObject' +``` + +जहाँ `ErrorObject` है: +```yaml +type: object +properties: + type: + type: string + message: + type: string +``` + +## संदर्भ + +अनुवादक: `trustgraph-base/trustgraph/messaging/translators/` +डिस्पैचर मैपिंग: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +एंडपॉइंट रूटिंग: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` +सेवा सारांश: `API_SERVICES_SUMMARY.md` diff --git a/docs/tech-specs/openapi-spec.pt.md b/docs/tech-specs/openapi-spec.pt.md new file mode 100644 index 00000000..c3134ecd --- /dev/null +++ b/docs/tech-specs/openapi-spec.pt.md @@ -0,0 +1,231 @@ +# Especificação OpenAPI - Especificação Técnica + +## Objetivo + +Criar uma especificação OpenAPI 3.1 abrangente e modular para o Gateway de API REST TrustGraph que: +Documenta todos os endpoints REST +Utiliza `$ref` externo para modularidade e manutenção +Mapeia diretamente para o código do tradutor de mensagens +Fornece esquemas precisos de requisição/resposta + +## Fonte da Verdade + +A API é definida por: +**Tradutores de Mensagens**: `trustgraph-base/trustgraph/messaging/translators/*.py` +**Gerenciador de Dispatcher**: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +**Gerenciador de Endpoint**: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` + +## Estrutura de Diretórios + +``` +openapi/ +├── openapi.yaml # Main entry point +├── paths/ +│ ├── config.yaml # Global services +│ ├── flow.yaml +│ ├── librarian.yaml +│ ├── knowledge.yaml +│ ├── collection-management.yaml +│ ├── flow-services/ # Flow-hosted services +│ │ ├── agent.yaml +│ │ ├── document-rag.yaml +│ │ ├── graph-rag.yaml +│ │ ├── text-completion.yaml +│ │ ├── prompt.yaml +│ │ ├── embeddings.yaml +│ │ ├── mcp-tool.yaml +│ │ ├── triples.yaml +│ │ ├── objects.yaml +│ │ ├── nlp-query.yaml +│ │ ├── structured-query.yaml +│ │ ├── structured-diag.yaml +│ │ ├── graph-embeddings.yaml +│ │ ├── document-embeddings.yaml +│ │ ├── text-load.yaml +│ │ └── document-load.yaml +│ ├── import-export/ +│ │ ├── core-import.yaml +│ │ ├── core-export.yaml +│ │ └── flow-import-export.yaml # WebSocket import/export +│ ├── websocket.yaml +│ └── metrics.yaml +├── components/ +│ ├── schemas/ +│ │ ├── config/ +│ │ ├── flow/ +│ │ ├── librarian/ +│ │ ├── knowledge/ +│ │ ├── collection/ +│ │ ├── ai-services/ +│ │ ├── common/ +│ │ └── errors/ +│ ├── parameters/ +│ ├── responses/ +│ └── examples/ +└── security/ + └── bearerAuth.yaml +``` + +## Mapeamento de Serviços + +### Serviços Globais (`/api/v1/{kind}`) +`config` - Gerenciamento de configuração +`flow` - Ciclo de vida do fluxo +`librarian` - Biblioteca de documentos +`knowledge` - Núcleos de conhecimento +`collection-management` - Metadados de coleção + +### Serviços Hospedados em Fluxo (`/api/v1/flow/{flow}/service/{kind}`) + +**Requisição/Resposta:** +`agent`, `text-completion`, `prompt`, `mcp-tool` +`graph-rag`, `document-rag` +`embeddings`, `graph-embeddings`, `document-embeddings` +`triples`, `objects`, `nlp-query`, `structured-query`, `structured-diag` + +**Enviar e Esquecer:** +`text-load`, `document-load` + +### Importação/Exportação +`/api/v1/import-core` (POST) +`/api/v1/export-core` (GET) +`/api/v1/flow/{flow}/import/{kind}` (WebSocket) +`/api/v1/flow/{flow}/export/{kind}` (WebSocket) + +### Outros +`/api/v1/socket` (WebSocket multiplexado) +`/api/metrics` (Prometheus) + +## Abordagem + +### Fase 1: Configuração +1. Criar estrutura de diretórios +2. Criar o arquivo principal `openapi.yaml` com metadados, servidores, segurança +3. Criar componentes reutilizáveis (erros, parâmetros comuns, esquemas de segurança) + +### Fase 2: Esquemas Comuns +Criar esquemas compartilhados usados em todos os serviços: +`RdfValue`, `Triple` - Estruturas RDF/triplas +`ErrorObject` - Resposta de erro +`DocumentMetadata`, `ProcessingMetadata` - Estruturas de metadados +Parâmetros comuns: `FlowId`, `User`, `Collection` + +### Fase 3: Serviços Globais +Para cada serviço global (configuração, fluxo, bibliotecário, conhecimento, gerenciamento de coleção): +1. Criar arquivo de caminho em `paths/` +2. Criar esquema de solicitação em `components/schemas/{service}/` +3. Criar esquema de resposta +4. Adicionar exemplos +5. Referenciar do arquivo principal `openapi.yaml` + +### Fase 4: Serviços Hospedados em Fluxo +Para cada serviço hospedado em fluxo: +1. Criar arquivo de caminho em `paths/flow-services/` +2. Criar esquemas de solicitação/resposta em `components/schemas/ai-services/` +3. Adicionar documentação da flag de streaming, quando aplicável +4. Referenciar do arquivo principal `openapi.yaml` + +### Fase 5: Importação/Exportação e WebSocket +1. Documentar os principais endpoints de importação/exportação +2. Documentar os padrões de protocolo WebSocket +3. Documentar os endpoints de importação/exportação WebSocket no nível do fluxo + +### Fase 6: Validação +1. Validar com ferramentas de validação OpenAPI +2. Testar com Swagger UI +3. Verificar se todos os tradutores estão cobertos + +## Convenção de Nomenclatura de Campos + +Todos os campos JSON usam **kebab-case**: +`flow-id`, `blueprint-name`, `doc-limit`, `entity-limit`, etc. + +## Criação de Arquivos de Esquema + +Para cada tradutor em `trustgraph-base/trustgraph/messaging/translators/`: + +1. **Ler o método do tradutor `to_pulsar()`** - Define o esquema de solicitação +2. **Ler o método do tradutor `from_pulsar()`** - Define o esquema de resposta +3. **Extrair nomes e tipos de campos** +4. **Criar o esquema OpenAPI** com: + Nomes de campos (kebab-case) + Tipos (string, integer, boolean, object, array) + Campos obrigatórios + Valores padrão + Descrições + +### Exemplo de Processo de Mapeamento + +```python +# From retrieval.py DocumentRagRequestTranslator +def to_pulsar(self, data: Dict[str, Any]) -> DocumentRagQuery: + return DocumentRagQuery( + query=data["query"], # required string + user=data.get("user", "trustgraph"), # optional string, default "trustgraph" + collection=data.get("collection", "default"), # optional string, default "default" + doc_limit=int(data.get("doc-limit", 20)), # optional integer, default 20 + streaming=data.get("streaming", False) # optional boolean, default false + ) +``` + +Tradução para: + +```yaml +# components/schemas/ai-services/DocumentRagRequest.yaml +type: object +required: + - query +properties: + query: + type: string + description: Search query + user: + type: string + default: trustgraph + collection: + type: string + default: default + doc-limit: + type: integer + default: 20 + description: Maximum number of documents to retrieve + streaming: + type: boolean + default: false + description: Enable streaming responses +``` + +## Respostas de Streaming + +Serviços que suportam streaming retornam múltiplas respostas com a flag `end_of_stream`: +`agent`, `text-completion`, `prompt` +`document-rag`, `graph-rag` + +Documente este padrão no esquema de resposta de cada serviço. + +## Respostas de Erro + +Todos os serviços podem retornar: +```yaml +error: + oneOf: + - type: string + - $ref: '#/components/schemas/ErrorObject' +``` + +Onde `ErrorObject` está: +```yaml +type: object +properties: + type: + type: string + message: + type: string +``` + +## Referências + +Tradutores: `trustgraph-base/trustgraph/messaging/translators/` +Mapeamento do despachante: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +Roteamento de endpoint: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` +Resumo do serviço: `API_SERVICES_SUMMARY.md` diff --git a/docs/tech-specs/openapi-spec.ru.md b/docs/tech-specs/openapi-spec.ru.md new file mode 100644 index 00000000..2a58b499 --- /dev/null +++ b/docs/tech-specs/openapi-spec.ru.md @@ -0,0 +1,231 @@ +# Спецификация OpenAPI - Техническая спецификация + +## Цель + +Создать всеобъемлющую, модульную спецификацию OpenAPI 3.1 для шлюза REST API TrustGraph, которая: +Документирует все конечные точки REST +Использует внешние `$ref` для модульности и удобства обслуживания +Непосредственно соответствует коду переводчика сообщений +Предоставляет точные схемы запросов/ответов + +## Источник истины + +API определяется следующим: +**Переводчики сообщений**: `trustgraph-base/trustgraph/messaging/translators/*.py` +**Менеджер диспетчера**: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +**Менеджер конечных точек**: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` + +## Структура каталогов + +``` +openapi/ +├── openapi.yaml # Main entry point +├── paths/ +│ ├── config.yaml # Global services +│ ├── flow.yaml +│ ├── librarian.yaml +│ ├── knowledge.yaml +│ ├── collection-management.yaml +│ ├── flow-services/ # Flow-hosted services +│ │ ├── agent.yaml +│ │ ├── document-rag.yaml +│ │ ├── graph-rag.yaml +│ │ ├── text-completion.yaml +│ │ ├── prompt.yaml +│ │ ├── embeddings.yaml +│ │ ├── mcp-tool.yaml +│ │ ├── triples.yaml +│ │ ├── objects.yaml +│ │ ├── nlp-query.yaml +│ │ ├── structured-query.yaml +│ │ ├── structured-diag.yaml +│ │ ├── graph-embeddings.yaml +│ │ ├── document-embeddings.yaml +│ │ ├── text-load.yaml +│ │ └── document-load.yaml +│ ├── import-export/ +│ │ ├── core-import.yaml +│ │ ├── core-export.yaml +│ │ └── flow-import-export.yaml # WebSocket import/export +│ ├── websocket.yaml +│ └── metrics.yaml +├── components/ +│ ├── schemas/ +│ │ ├── config/ +│ │ ├── flow/ +│ │ ├── librarian/ +│ │ ├── knowledge/ +│ │ ├── collection/ +│ │ ├── ai-services/ +│ │ ├── common/ +│ │ └── errors/ +│ ├── parameters/ +│ ├── responses/ +│ └── examples/ +└── security/ + └── bearerAuth.yaml +``` + +## Отображение сервисов + +### Глобальные сервисы (`/api/v1/{kind}`) +`config` - Управление конфигурацией +`flow` - Жизненный цикл потока +`librarian` - Библиотека документов +`knowledge` - Базы знаний +`collection-management` - Метаданные коллекции + +### Сервисы, размещенные в потоке (`/api/v1/flow/{flow}/service/{kind}`) + +**Запрос/Ответ:** +`agent`, `text-completion`, `prompt`, `mcp-tool` +`graph-rag`, `document-rag` +`embeddings`, `graph-embeddings`, `document-embeddings` +`triples`, `objects`, `nlp-query`, `structured-query`, `structured-diag` + +**Отправка и получение (Fire-and-Forget):** +`text-load`, `document-load` + +### Импорт/Экспорт +`/api/v1/import-core` (POST) +`/api/v1/export-core` (GET) +`/api/v1/flow/{flow}/import/{kind}` (WebSocket) +`/api/v1/flow/{flow}/export/{kind}` (WebSocket) + +### Другое +`/api/v1/socket` (Множественный WebSocket) +`/api/metrics` (Prometheus) + +## Подход + +### Фаза 1: Настройка +1. Создание структуры каталогов +2. Создание основного файла `openapi.yaml` с метаданными, серверами, безопасностью +3. Создание многократно используемых компонентов (ошибок, общих параметров, схем безопасности) + +### Фаза 2: Общие схемы +Создание общих схем, используемых во всех сервисах: +`RdfValue`, `Triple` - RDF/структуры троек +`ErrorObject` - Ответ об ошибке +`DocumentMetadata`, `ProcessingMetadata` - Структуры метаданных +Общие параметры: `FlowId`, `User`, `Collection` + +### Фаза 3: Глобальные сервисы +Для каждого глобального сервиса (конфигурация, поток, библиотека, знания, управление коллекцией): +1. Создание файла пути в `paths/` +2. Создание схемы запроса в `components/schemas/{service}/` +3. Создание схемы ответа +4. Добавление примеров +5. Ссылка из основного файла `openapi.yaml` + +### Фаза 4: Сервисы, размещенные в потоке +Для каждого сервиса, размещенного в потоке: +1. Создание файла пути в `paths/flow-services/` +2. Создание схем запроса/ответа в `components/schemas/ai-services/` +3. Добавление документации о флаге потоковой передачи, где это применимо +4. Ссылка из основного файла `openapi.yaml` + +### Фаза 5: Импорт/Экспорт и WebSocket +1. Документирование основных конечных точек импорта/экспорта +2. Документирование шаблонов протокола WebSocket +3. Документирование конечных точек импорта/экспорта WebSocket на уровне потока + +### Фаза 6: Валидация +1. Проверка с помощью инструментов валидации OpenAPI +2. Тестирование с помощью Swagger UI +3. Убедитесь, что все переводчики охвачены + +## Соглашение об именовании полей + +Все поля JSON используют **kebab-case**: +`flow-id`, `blueprint-name`, `doc-limit`, `entity-limit` и т. д. + +## Создание файлов схем + +Для каждого переводчика в `trustgraph-base/trustgraph/messaging/translators/`: + +1. **Прочитать метод переводчика `to_pulsar()`** - Определяет схему запроса +2. **Прочитать метод переводчика `from_pulsar()`** - Определяет схему ответа +3. **Извлечь имена и типы полей** +4. **Создать схему OpenAPI** с: + Имена полей (kebab-case) + Типы (string, integer, boolean, object, array) + Обязательные поля + Значения по умолчанию + Описания + +### Пример процесса сопоставления + +```python +# From retrieval.py DocumentRagRequestTranslator +def to_pulsar(self, data: Dict[str, Any]) -> DocumentRagQuery: + return DocumentRagQuery( + query=data["query"], # required string + user=data.get("user", "trustgraph"), # optional string, default "trustgraph" + collection=data.get("collection", "default"), # optional string, default "default" + doc_limit=int(data.get("doc-limit", 20)), # optional integer, default 20 + streaming=data.get("streaming", False) # optional boolean, default false + ) +``` + +Соответствует: + +```yaml +# components/schemas/ai-services/DocumentRagRequest.yaml +type: object +required: + - query +properties: + query: + type: string + description: Search query + user: + type: string + default: trustgraph + collection: + type: string + default: default + doc-limit: + type: integer + default: 20 + description: Maximum number of documents to retrieve + streaming: + type: boolean + default: false + description: Enable streaming responses +``` + +## Потоковые ответы + +Сервисы, поддерживающие потоковую передачу, возвращают несколько ответов с флагом `end_of_stream`: +`agent`, `text-completion`, `prompt` +`document-rag`, `graph-rag` + +Опишите эту схему в схеме ответа каждого сервиса. + +## Ответы об ошибках + +Все сервисы могут возвращать: +```yaml +error: + oneOf: + - type: string + - $ref: '#/components/schemas/ErrorObject' +``` + +Где `ErrorObject` находится: +```yaml +type: object +properties: + type: + type: string + message: + type: string +``` + +## Ссылки + +Переводчики: `trustgraph-base/trustgraph/messaging/translators/` +Отображение диспетчера: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +Маршрутизация конечных точек: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` +Обзор сервисов: `API_SERVICES_SUMMARY.md` diff --git a/docs/tech-specs/openapi-spec.sw.md b/docs/tech-specs/openapi-spec.sw.md new file mode 100644 index 00000000..47b2fd5d --- /dev/null +++ b/docs/tech-specs/openapi-spec.sw.md @@ -0,0 +1,231 @@ +# Maelezo ya Kiufundi ya OpenAPI + +## Lengo + +Kuunda maelezo kamili na yanayoweza kutenganishwa ya OpenAPI 3.1 kwa lango la API la TrustGraph ambalo: +Yanadhihirisha viungo vyote vya REST +Yanatumia `$ref` ya nje kwa utendaji na uendelevu +Yanalingana moja kwa moja na msimuaji wa ujumbe +Yanatoa muundo sahihi wa ombi/jibu + +## Chanzo cha Uhakika + +API inafafanuliwa na: +**Wasimamizi wa Tafsiri ya Ujumbe**: `trustgraph-base/trustgraph/messaging/translators/*.py` +**Meneja wa Msambazaji**: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +**Meneja wa Kikoa**: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` + +## Muundo wa Saraka + +``` +openapi/ +├── openapi.yaml # Main entry point +├── paths/ +│ ├── config.yaml # Global services +│ ├── flow.yaml +│ ├── librarian.yaml +│ ├── knowledge.yaml +│ ├── collection-management.yaml +│ ├── flow-services/ # Flow-hosted services +│ │ ├── agent.yaml +│ │ ├── document-rag.yaml +│ │ ├── graph-rag.yaml +│ │ ├── text-completion.yaml +│ │ ├── prompt.yaml +│ │ ├── embeddings.yaml +│ │ ├── mcp-tool.yaml +│ │ ├── triples.yaml +│ │ ├── objects.yaml +│ │ ├── nlp-query.yaml +│ │ ├── structured-query.yaml +│ │ ├── structured-diag.yaml +│ │ ├── graph-embeddings.yaml +│ │ ├── document-embeddings.yaml +│ │ ├── text-load.yaml +│ │ └── document-load.yaml +│ ├── import-export/ +│ │ ├── core-import.yaml +│ │ ├── core-export.yaml +│ │ └── flow-import-export.yaml # WebSocket import/export +│ ├── websocket.yaml +│ └── metrics.yaml +├── components/ +│ ├── schemas/ +│ │ ├── config/ +│ │ ├── flow/ +│ │ ├── librarian/ +│ │ ├── knowledge/ +│ │ ├── collection/ +│ │ ├── ai-services/ +│ │ ├── common/ +│ │ └── errors/ +│ ├── parameters/ +│ ├── responses/ +│ └── examples/ +└── security/ + └── bearerAuth.yaml +``` + +## Huduma za Ulinganishaji + +### Huduma za Kimataifa (`/api/v1/{kind}`) +`config` - Usimamizi wa usanidi +`flow` - Mzungano wa mchakato +`librarian` - Maktaba ya nyaraka +`knowledge` - Vituo vya maarifa +`collection-management` - Meta data ya mkusanyiko + +### Huduma Zilizowekwa kwenye Mchakato (`/api/v1/flow/{flow}/service/{kind}`) + +**Ombi/Jibu:** +`agent`, `text-completion`, `prompt`, `mcp-tool` +`graph-rag`, `document-rag` +`embeddings`, `graph-embeddings`, `document-embeddings` +`triples`, `objects`, `nlp-query`, `structured-query`, `structured-diag` + +**Tuma na Usisubiri:** +`text-load`, `document-load` + +### Uingizaji/Utoaji +`/api/v1/import-core` (POST) +`/api/v1/export-core` (GET) +`/api/v1/flow/{flow}/import/{kind}` (WebSocket) +`/api/v1/flow/{flow}/export/{kind}` (WebSocket) + +### Mengine +`/api/v1/socket` (WebSocket iliyounganishwa) +`/api/metrics` (Prometheus) + +## Mbinu + +### Awamu ya 1: Uwekaji +1. Unda muundo wa saraka +2. Unda `openapi.yaml` kuu pamoja na metadata, seva, usalama +3. Unda vipengele vinavyoweza kutumika tena (makosa, vigezo vya kawaida, mpango wa usalama) + +### Awamu ya 2: Mfumo wa Kawaida +Unda mfumo wa kawaida unaotumika katika huduma: +`RdfValue`, `Triple` - Miundo ya RDF/triple +`ErrorObject` - Jibu la kosa +`DocumentMetadata`, `ProcessingMetadata` - Miundo ya metadata +Vigezo vya kawaida: `FlowId`, `User`, `Collection` + +### Awamu ya 3: Huduma za Kimataifa +Kwa kila huduma ya kimataifa (usanidi, mchakato, maktaba, maarifa, usimamizi wa mkusanyiko): +1. Unda faili ya njia katika `paths/` +2. Unda mfumo wa ombi katika `components/schemas/{service}/` +3. Unda mfumo wa jibu +4. Ongeza mifano +5. Rejelea kutoka kwa `openapi.yaml` kuu + +### Awamu ya 4: Huduma Zilizowekwa kwenye Mchakato +Kwa kila huduma iliyowekwa kwenye mchakato: +1. Unda faili ya njia katika `paths/flow-services/` +2. Unda mifumo ya ombi/jibu katika `components/schemas/ai-services/` +3. Ongeza maandishi ya bendera ya utiririshaji ambapo inafaa +4. Rejelea kutoka kwa `openapi.yaml` kuu + +### Awamu ya 5: Uingizaji/Utoaji & WebSocket +1. Andika kuhusu mwisho wa msingi wa uingizaji/utoaji +2. Andika kuhusu mifumo ya itifaki ya WebSocket +3. Andika kuhusu mwisho wa uingizaji/utoaji wa WebSocket wa kiwango cha mchakato + +### Awamu ya 6: Uthibitisho +1. Thibitisha kwa kutumia zana za uthibitisho wa OpenAPI +2. Jaribu kwa kutumia Swagger UI +3. Hakikisha kuwa watumizi wote wamefunikwa + +## Mfumo wa Majina ya Nyanja + +Nyanja zote za JSON hutumia **kebab-case**: +`flow-id`, `blueprint-name`, `doc-limit`, `entity-limit`, n.k. + +## Kuunda Faili za Mfumo + +Kwa kila mtumizi katika `trustgraph-base/trustgraph/messaging/translators/`: + +1. **Soma njia ya mtumizi `to_pulsar()`** - Inaweka mfumo wa ombi +2. **Soma njia ya mtumizi `from_pulsar()`** - Inaweka mfumo wa jibu +3. **Toa majina na aina za nyanja** +4. **Unda mfumo wa OpenAPI** pamoja na: + Majina ya nyanja (kebab-case) + Aina (string, integer, boolean, object, array) + Nyanja zinazohitajika + Maagizo + Maelezo + +### Mchakato wa Ulinganishaji wa Kifaa + +```python +# From retrieval.py DocumentRagRequestTranslator +def to_pulsar(self, data: Dict[str, Any]) -> DocumentRagQuery: + return DocumentRagQuery( + query=data["query"], # required string + user=data.get("user", "trustgraph"), # optional string, default "trustgraph" + collection=data.get("collection", "default"), # optional string, default "default" + doc_limit=int(data.get("doc-limit", 20)), # optional integer, default 20 + streaming=data.get("streaming", False) # optional boolean, default false + ) +``` + +Inafanana na: + +```yaml +# components/schemas/ai-services/DocumentRagRequest.yaml +type: object +required: + - query +properties: + query: + type: string + description: Search query + user: + type: string + default: trustgraph + collection: + type: string + default: default + doc-limit: + type: integer + default: 20 + description: Maximum number of documents to retrieve + streaming: + type: boolean + default: false + description: Enable streaming responses +``` + +## Majibu ya Utiririshaji + +Huduma zinazounga mkono utiririshaji hurudisha majibu mengi na bendera `end_of_stream`: +`agent`, `text-completion`, `prompt` +`document-rag`, `graph-rag` + +Elezea mfumo huu katika schema ya majibu ya kila huduma. + +## Majibu ya Kosa + +Huduma zote zinaweza kurudisha: +```yaml +error: + oneOf: + - type: string + - $ref: '#/components/schemas/ErrorObject' +``` + +Ambako `ErrorObject` iko: +```yaml +type: object +properties: + type: + type: string + message: + type: string +``` + +## Marejeleo + +Watengenezaji: `trustgraph-base/trustgraph/messaging/translators/` +Ramani ya utumaji: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +Uelekezaji wa mwisho: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` +Muhtasari wa huduma: `API_SERVICES_SUMMARY.md` diff --git a/docs/tech-specs/openapi-spec.tr.md b/docs/tech-specs/openapi-spec.tr.md new file mode 100644 index 00000000..6fcd530b --- /dev/null +++ b/docs/tech-specs/openapi-spec.tr.md @@ -0,0 +1,231 @@ +# OpenAPI Özellikleri - Teknik Belge + +## Amaç + +TrustGraph REST API Gateway için kapsamlı, modüler bir OpenAPI 3.1 spesifikasyonu oluşturmak, bu spesifikasyon şunları sağlamalıdır: +Tüm REST uç noktalarını belgelemelidir +Modülerlik ve bakım kolaylığı için harici `$ref` kullanmalıdır +Doğrudan mesaj çevirici koduna eşlenmelidir +Doğru istek/yanıt şemaları sağlamalıdır + +## Doğru Kaynak + +API aşağıdaki öğeler tarafından tanımlanır: +**Mesaj Çeviriciler**: `trustgraph-base/trustgraph/messaging/translators/*.py` +**Dağıtıcı Yöneticisi**: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +**Uç Nokta Yöneticisi**: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` + +## Dizin Yapısı + +``` +openapi/ +├── openapi.yaml # Main entry point +├── paths/ +│ ├── config.yaml # Global services +│ ├── flow.yaml +│ ├── librarian.yaml +│ ├── knowledge.yaml +│ ├── collection-management.yaml +│ ├── flow-services/ # Flow-hosted services +│ │ ├── agent.yaml +│ │ ├── document-rag.yaml +│ │ ├── graph-rag.yaml +│ │ ├── text-completion.yaml +│ │ ├── prompt.yaml +│ │ ├── embeddings.yaml +│ │ ├── mcp-tool.yaml +│ │ ├── triples.yaml +│ │ ├── objects.yaml +│ │ ├── nlp-query.yaml +│ │ ├── structured-query.yaml +│ │ ├── structured-diag.yaml +│ │ ├── graph-embeddings.yaml +│ │ ├── document-embeddings.yaml +│ │ ├── text-load.yaml +│ │ └── document-load.yaml +│ ├── import-export/ +│ │ ├── core-import.yaml +│ │ ├── core-export.yaml +│ │ └── flow-import-export.yaml # WebSocket import/export +│ ├── websocket.yaml +│ └── metrics.yaml +├── components/ +│ ├── schemas/ +│ │ ├── config/ +│ │ ├── flow/ +│ │ ├── librarian/ +│ │ ├── knowledge/ +│ │ ├── collection/ +│ │ ├── ai-services/ +│ │ ├── common/ +│ │ └── errors/ +│ ├── parameters/ +│ ├── responses/ +│ └── examples/ +└── security/ + └── bearerAuth.yaml +``` + +## Hizmet Eşlemesi + +### Küresel Hizmetler (`/api/v1/{kind}`) +`config` - Yapılandırma yönetimi +`flow` - Akış yaşam döngüsü +`librarian` - Belge kütüphanesi +`knowledge` - Bilgi çekirdekleri +`collection-management` - Koleksiyon meta verileri + +### Akışa Dayalı Hizmetler (`/api/v1/flow/{flow}/service/{kind}`) + +**İstek/Yanıt:** +`agent`, `text-completion`, `prompt`, `mcp-tool` +`graph-rag`, `document-rag` +`embeddings`, `graph-embeddings`, `document-embeddings` +`triples`, `objects`, `nlp-query`, `structured-query`, `structured-diag` + +**Gönder ve Unut:** +`text-load`, `document-load` + +### İçe/Dışa Aktarma +`/api/v1/import-core` (POST) +`/api/v1/export-core` (GET) +`/api/v1/flow/{flow}/import/{kind}` (WebSocket) +`/api/v1/flow/{flow}/export/{kind}` (WebSocket) + +### Diğer +`/api/v1/socket` (WebSocket çoklama) +`/api/metrics` (Prometheus) + +## Yaklaşım + +### Aşama 1: Kurulum +1. Dizin yapısını oluşturun +2. Ana `openapi.yaml` dosyasını meta veriler, sunucular, güvenlik ile birlikte oluşturun +3. Yeniden kullanılabilir bileşenleri (hatalar, ortak parametreler, güvenlik şemaları) oluşturun + +### Aşama 2: Ortak Şemalar +Hizmetler arasında kullanılan ortak şemaları oluşturun: +`RdfValue`, `Triple` - RDF/üçlü yapılar +`ErrorObject` - Hata yanıtı +`DocumentMetadata`, `ProcessingMetadata` - Meta veri yapıları +Ortak parametreler: `FlowId`, `User`, `Collection` + +### Aşama 3: Küresel Hizmetler +Her küresel hizmet için (yapılandırma, akış, kütüphaneci, bilgi, koleksiyon yönetimi): +1. `paths/` içinde bir yol dosyası oluşturun +2. `components/schemas/{service}/` içinde bir istek şeması oluşturun +3. Bir yanıt şeması oluşturun +4. Örnekler ekleyin +5. Ana `openapi.yaml` dosyasından referans alın + +### Aşama 4: Akışa Dayalı Hizmetler +Her akışa dayalı hizmet için: +1. `paths/flow-services/` içinde bir yol dosyası oluşturun +2. `components/schemas/ai-services/` içinde istek/yanıt şemalarını oluşturun +3. Gerekli durumlarda akış düzeyi akış bayrak dokümantasyonunu ekleyin +4. Ana `openapi.yaml` dosyasından referans alın + +### Aşama 5: İçe/Dışa Aktarma & WebSocket +1. Temel içe/dışa aktarma uç noktalarını belgeleyin +2. WebSocket protokol kalıplarını belgeleyin +3. Akış düzeyindeki içe/dışa aktarma WebSocket uç noktalarını belgeleyin + +### Aşama 6: Doğrulama +1. OpenAPI doğrulama araçlarıyla doğrulayın +2. Swagger UI ile test edin +3. Tüm çeviricilerin kapsandığından emin olun + +## Alan Adlandırma Kuralları + +Tüm JSON alanları **kebab-case** kullanır: +`flow-id`, `blueprint-name`, `doc-limit`, `entity-limit`, vb. + +## Şema Dosyaları Oluşturma + +Her çevirici için `trustgraph-base/trustgraph/messaging/translators/` içinde: + +1. **Çevirici `to_pulsar()` yöntemini okuyun** - İstek şemasını tanımlar +2. **Çevirici `from_pulsar()` yöntemini okuyun** - Yanıt şemasını tanımlar +3. **Alan adlarını ve türlerini çıkarın** +4. Aşağıdakilerle bir OpenAPI şeması oluşturun: + Alan adları (kebab-case) + Türler (string, integer, boolean, object, array) + Gerekli alanlar + Varsayılanlar + Açıklamalar + +### Örnek Eşleme Süreci + +```python +# From retrieval.py DocumentRagRequestTranslator +def to_pulsar(self, data: Dict[str, Any]) -> DocumentRagQuery: + return DocumentRagQuery( + query=data["query"], # required string + user=data.get("user", "trustgraph"), # optional string, default "trustgraph" + collection=data.get("collection", "default"), # optional string, default "default" + doc_limit=int(data.get("doc-limit", 20)), # optional integer, default 20 + streaming=data.get("streaming", False) # optional boolean, default false + ) +``` + +Çevrilir: + +```yaml +# components/schemas/ai-services/DocumentRagRequest.yaml +type: object +required: + - query +properties: + query: + type: string + description: Search query + user: + type: string + default: trustgraph + collection: + type: string + default: default + doc-limit: + type: integer + default: 20 + description: Maximum number of documents to retrieve + streaming: + type: boolean + default: false + description: Enable streaming responses +``` + +## Akışlı Yanıtlar + +Akışlı yanıtları destekleyen hizmetler, `end_of_stream` bayrağı ile birden fazla yanıt döndürür: +`agent`, `text-completion`, `prompt` +`document-rag`, `graph-rag` + +Bu kalıbı, her hizmetin yanıt şemasında belgeleyin. + +## Hata Yanıtları + +Tüm hizmetler aşağıdaki yanıtları döndürebilir: +```yaml +error: + oneOf: + - type: string + - $ref: '#/components/schemas/ErrorObject' +``` + +`ErrorObject` ifadesi nerede bulunuyor: +```yaml +type: object +properties: + type: + type: string + message: + type: string +``` + +## Referanslar + +Çevirenler: `trustgraph-base/trustgraph/messaging/translators/` +Dağıtım eşlemesi: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +Uç nokta yönlendirmesi: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` +Hizmet özeti: `API_SERVICES_SUMMARY.md` diff --git a/docs/tech-specs/openapi-spec.zh-cn.md b/docs/tech-specs/openapi-spec.zh-cn.md new file mode 100644 index 00000000..e2c6432f --- /dev/null +++ b/docs/tech-specs/openapi-spec.zh-cn.md @@ -0,0 +1,231 @@ +# OpenAPI 规范 - 技术规范 + +## 目标 + +创建一个全面的、模块化的 OpenAPI 3.1 规范,用于 TrustGraph REST API 网关,该规范应: +记录所有 REST 接口 +使用外部 `$ref` 以实现模块化和可维护性 +直接映射到消息转换器代码 +提供准确的请求/响应模式 + +## 权威来源 + +API 由以下内容定义: +**消息转换器**: `trustgraph-base/trustgraph/messaging/translators/*.py` +**分派器管理器**: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +**端点管理器**: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py` + +## 目录结构 + +``` +openapi/ +├── openapi.yaml # Main entry point +├── paths/ +│ ├── config.yaml # Global services +│ ├── flow.yaml +│ ├── librarian.yaml +│ ├── knowledge.yaml +│ ├── collection-management.yaml +│ ├── flow-services/ # Flow-hosted services +│ │ ├── agent.yaml +│ │ ├── document-rag.yaml +│ │ ├── graph-rag.yaml +│ │ ├── text-completion.yaml +│ │ ├── prompt.yaml +│ │ ├── embeddings.yaml +│ │ ├── mcp-tool.yaml +│ │ ├── triples.yaml +│ │ ├── objects.yaml +│ │ ├── nlp-query.yaml +│ │ ├── structured-query.yaml +│ │ ├── structured-diag.yaml +│ │ ├── graph-embeddings.yaml +│ │ ├── document-embeddings.yaml +│ │ ├── text-load.yaml +│ │ └── document-load.yaml +│ ├── import-export/ +│ │ ├── core-import.yaml +│ │ ├── core-export.yaml +│ │ └── flow-import-export.yaml # WebSocket import/export +│ ├── websocket.yaml +│ └── metrics.yaml +├── components/ +│ ├── schemas/ +│ │ ├── config/ +│ │ ├── flow/ +│ │ ├── librarian/ +│ │ ├── knowledge/ +│ │ ├── collection/ +│ │ ├── ai-services/ +│ │ ├── common/ +│ │ └── errors/ +│ ├── parameters/ +│ ├── responses/ +│ └── examples/ +└── security/ + └── bearerAuth.yaml +``` + +## 服务映射 + +### 全局服务 (`/api/v1/{kind}`) +`config` - 配置管理 +`flow` - 流生存周期 +`librarian` - 文档库 +`knowledge` - 知识核心 +`collection-management` - 集合元数据 + +### 托管于流的服务 (`/api/v1/flow/{flow}/service/{kind}`) + +**请求/响应:** +`agent`, `text-completion`, `prompt`, `mcp-tool` +`graph-rag`, `document-rag` +`embeddings`, `graph-embeddings`, `document-embeddings` +`triples`, `objects`, `nlp-query`, `structured-query`, `structured-diag` + +**发布/订阅:** +`text-load`, `document-load` + +### 导入/导出 +`/api/v1/import-core` (POST) +`/api/v1/export-core` (GET) +`/api/v1/flow/{flow}/import/{kind}` (WebSocket) +`/api/v1/flow/{flow}/export/{kind}` (WebSocket) + +### 其他 +`/api/v1/socket` (WebSocket 多路复用) +`/api/metrics` (Prometheus) + +## 方案 + +### 第一阶段:设置 +1. 创建目录结构 +2. 创建主 `openapi.yaml` 文件,包含元数据、服务器、安全配置 +3. 创建可重用组件(错误、通用参数、安全方案) + +### 第二阶段:通用模式 +创建在服务间共享的模式: +`RdfValue`, `Triple` - RDF/三元组结构 +`ErrorObject` - 错误响应 +`DocumentMetadata`, `ProcessingMetadata` - 元数据结构 +通用参数:`FlowId`, `User`, `Collection` + +### 第三阶段:全球服务 +对于每个全球服务(配置、流程、库管理员、知识、集合管理): +1. 在 `paths/` 中创建路径文件。 +2. 在 `components/schemas/{service}/` 中创建请求模式。 +3. 创建响应模式。 +4. 添加示例。 +5. 从主文件 `openapi.yaml` 中引用。 + +### 第四阶段:流程托管服务 +对于每个流程托管服务: +1. 在 `paths/flow-services/` 中创建路径文件。 +2. 在 `components/schemas/ai-services/` 中创建请求/响应模式。 +3. 在适用情况下,添加流媒体标志文档。 +4. 从主文件 `openapi.yaml` 中引用。 + +### 第五阶段:导入/导出 & WebSocket +1. 文档核心导入/导出端点。 +2. 文档 WebSocket 协议模式。 +3. 文档流程级别的导入/导出 WebSocket 端点。 + +### 第六阶段:验证 +1. 使用 OpenAPI 验证工具进行验证。 +2. 使用 Swagger UI 进行测试。 +3. 验证所有翻译器是否已覆盖。 + +## 字段命名约定 + +所有 JSON 字段使用 **kebab-case**: +`flow-id`, `blueprint-name`, `doc-limit`, `entity-limit`, 等。 + +## 创建模式文件 + +对于 `trustgraph-base/trustgraph/messaging/translators/` 中的每个翻译器: + +1. **读取翻译器 `to_pulsar()` 方法** - 定义请求模式。 +2. **读取翻译器 `from_pulsar()` 方法** - 定义响应模式。 +3. **提取字段名称和类型**。 +4. **创建 OpenAPI 模式**,包含: + 字段名称(kebab-case)。 + 类型(字符串、整数、布尔值、对象、数组)。 + 必需字段。 + 默认值。 + 描述。 + +### 示例映射过程 + +```python +# From retrieval.py DocumentRagRequestTranslator +def to_pulsar(self, data: Dict[str, Any]) -> DocumentRagQuery: + return DocumentRagQuery( + query=data["query"], # required string + user=data.get("user", "trustgraph"), # optional string, default "trustgraph" + collection=data.get("collection", "default"), # optional string, default "default" + doc_limit=int(data.get("doc-limit", 20)), # optional integer, default 20 + streaming=data.get("streaming", False) # optional boolean, default false + ) +``` + +对应于: + +```yaml +# components/schemas/ai-services/DocumentRagRequest.yaml +type: object +required: + - query +properties: + query: + type: string + description: Search query + user: + type: string + default: trustgraph + collection: + type: string + default: default + doc-limit: + type: integer + default: 20 + description: Maximum number of documents to retrieve + streaming: + type: boolean + default: false + description: Enable streaming responses +``` + +## 流式响应 + +支持流式传输的服务会返回带有 `end_of_stream` 标志的多个响应: +`agent`, `text-completion`, `prompt` +`document-rag`, `graph-rag` + +在每个服务的响应模式中记录此模式。 + +## 错误响应 + +所有服务都可以返回: +```yaml +error: + oneOf: + - type: string + - $ref: '#/components/schemas/ErrorObject' +``` + +其中,`ErrorObject` 指的是: +```yaml +type: object +properties: + type: + type: string + message: + type: string +``` + +## 参考文献 + +翻译人员:`trustgraph-base/trustgraph/messaging/translators/` +调度映射:`trustgraph-flow/trustgraph/gateway/dispatch/manager.py` +终端路由:`trustgraph-flow/trustgraph/gateway/endpoint/manager.py` +服务摘要:`API_SERVICES_SUMMARY.md` diff --git a/docs/tech-specs/pubsub.ar.md b/docs/tech-specs/pubsub.ar.md new file mode 100644 index 00000000..0a8151af --- /dev/null +++ b/docs/tech-specs/pubsub.ar.md @@ -0,0 +1,958 @@ +# البنية التحتية للنشر والاشتراك (Pub/Sub) + +## نظرة عامة + +يوثق هذا المستند جميع الاتصالات بين قاعدة بيانات TrustGraph والبنية التحتية للنشر والاشتراك. حاليًا، يتم ترميز النظام لاستخدام Apache Pulsar. تحدد هذه التحليلات جميع نقاط التكامل لإعلام عمليات إعادة الهيكلة المستقبلية نحو تجريد نشر واشتراك قابل للتكوين. + +## الحالة الحالية: نقاط تكامل Pulsar + +### 1. استخدام عميل Pulsar المباشر + +**الموقع:** `trustgraph-flow/trustgraph/gateway/service.py` + +يقوم بوابة واجهة برمجة التطبيقات باستيراد وتثبيت عميل Pulsar مباشرةً: + +**السطر 20:** `import pulsar` +**الأسطر 54-61:** تثبيت مباشر لـ `pulsar.Client()` مع `pulsar.AuthenticationToken()` الاختياري +**الأسطر 33-35:** تكوين مضيف Pulsar الافتراضي من متغيرات البيئة +**الأسطر 178-192:** وسيطات سطر الأوامر لـ `--pulsar-host`، `--pulsar-api-key`، و `--pulsar-listener` +**الأسطر 78، 124:** تمرير `pulsar_client` إلى `ConfigReceiver` و `DispatcherManager` + +هذا هو الموقع الوحيد الذي يقوم بتثبيت عميل Pulsar مباشرةً خارج طبقة التجريد. + +### 2. إطار عمل المعالج الأساسي + +**الموقع:** `trustgraph-base/trustgraph/base/async_processor.py` + +يوفر الفئة الأساسية لجميع المعالجات اتصال Pulsar: + +**السطر 9:** `import _pulsar` (للتعامل مع الاستثناءات) +**السطر 18:** `from . pubsub import PulsarClient` +**السطر 38:** إنشاء `pulsar_client_object = PulsarClient(**params)` +**الأسطر 104-108:** خصائص تعرض `pulsar_host` و `pulsar_client` +**السطر 250:** تستدعي الطريقة الثابتة `add_args()` `PulsarClient.add_args(parser)` لوسيطات سطر الأوامر +**الأسطر 223-225:** معالجة الاستثناءات لـ `_pulsar.Interrupted` + +ترث جميع المعالجات من `AsyncProcessor`، مما يجعل هذا نقطة التكامل المركزية. + +### 3. تجريد المستهلك + +**الموقع:** `trustgraph-base/trustgraph/base/consumer.py` + +يستهلك الرسائل من قوائم الانتظار ويستدعي وظائف المعالج: + +**استيرادات Pulsar:** +**السطر 12:** `from pulsar.schema import JsonSchema` +**السطر 13:** `import pulsar` +**السطر 14:** `import _pulsar` + +**الاستخدام المحدد لـ Pulsar:** +**الأسطر 100، 102:** `pulsar.InitialPosition.Earliest` / `pulsar.InitialPosition.Latest` +**السطر 108:** غلاف `JsonSchema(self.schema)` +**السطر 110:** `pulsar.ConsumerType.Shared` +**الأسطر 104-111:** `self.client.subscribe()` مع معلمات خاصة بـ Pulsar +**الأسطر 143، 150، 65:** طرق `consumer.unsubscribe()` و `consumer.close()` +**السطر 162:** استثناء `_pulsar.Timeout` +**الأسطر 182، 205، 232:** `consumer.acknowledge()` / `consumer.negative_acknowledge()` + +**ملف المواصفات:** `trustgraph-base/trustgraph/base/consumer_spec.py` +**السطر 22:** يشير إلى `processor.pulsar_client` + +### 4. تجريد الناشر + +**الموقع:** `trustgraph-base/trustgraph/base/producer.py` + +يرسل الرسائل إلى قوائم الانتظار: + +**استيرادات Pulsar:** +**السطر 2:** `from pulsar.schema import JsonSchema` + +**الاستخدام المحدد لـ Pulsar:** +**السطر 49:** غلاف `JsonSchema(self.schema)` +**الأسطر 47-51:** `self.client.create_producer()` مع معلمات خاصة بـ Pulsar (الموضوع، المخطط، تمكين التجزئة) +**الأسطر 31، 76:** طريقة `producer.close()` +**الأسطر 64-65:** `producer.send()` مع الرسالة والخصائص + +**ملف المواصفات:** `trustgraph-base/trustgraph/base/producer_spec.py` +**السطر 18:** يشير إلى `processor.pulsar_client` + +### 5. تجريد الناشر + +**الموقع:** `trustgraph-base/trustgraph/base/publisher.py` + +نشر الرسائل بشكل غير متزامن مع تخزين الرسائل مؤقتًا في قائمة الانتظار: + +**استيرادات Pulsar:** +**السطر 2:** `from pulsar.schema import JsonSchema` +**السطر 6:** `import pulsar` + +**الاستخدام المحدد لـ Pulsar:** +**السطر 52:** غلاف `JsonSchema(self.schema)` +**الأسطر 50-54:** `self.client.create_producer()` مع معلمات خاصة بـ Pulsar +**الأسطر 101، 103:** `producer.send()` مع الرسالة والخصائص الاختيارية +**الأسطر 106-107:** طرق `producer.flush()` و `producer.close()` + +### 6. تجريد المشترك + +**الموقع:** `trustgraph-base/trustgraph/base/subscriber.py` + +يوفر توزيع رسائل متعددة المستلمين من خلال قوائم الانتظار: + +**استيرادات Pulsar:** +**السطر 6:** `from pulsar.schema import JsonSchema` +**السطر 8:** `import _pulsar` + +**الاستخدام الخاص بـ Pulsar:** +**السطر 55:** `JsonSchema(self.schema)` wrapper +**السطر 57:** `self.client.subscribe(**subscribe_args)` +**الأسطر 101، 136، 160، 167-172:** استثناءات Pulsar: `_pulsar.Timeout`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +**الأسطر 159، 166، 170:** طرق المستهلك: `negative_acknowledge()`, `unsubscribe()`, `close()` +**الأسطر 247، 251:** إقرار الرسالة: `acknowledge()`, `negative_acknowledge()` + +**ملف المواصفات:** `trustgraph-base/trustgraph/base/subscriber_spec.py` +**السطر 19:** يشير إلى `processor.pulsar_client` + +### 7. نظام المخططات (قلب الظلام) + +**الموقع:** `trustgraph-base/trustgraph/schema/` + +يتم تعريف كل مخطط رسالة في النظام باستخدام إطار عمل المخططات الخاص بـ Pulsar. + +**المكونات الأساسية:** `schema/core/primitives.py` +**السطر 2:** `from pulsar.schema import Record, String, Boolean, Array, Integer` +ترث جميع المخططات من الفئة الأساسية `Record` الخاصة بـ Pulsar +جميع أنواع الحقول هي أنواع Pulsar: `String()`, `Integer()`, `Boolean()`, `Array()`, `Map()`, `Double()` + +**أمثلة على المخططات:** +`schema/services/llm.py` (السطر 2): `from pulsar.schema import Record, String, Array, Double, Integer, Boolean` +`schema/services/config.py` (السطر 2): `from pulsar.schema import Record, Bytes, String, Boolean, Array, Map, Integer` + +**تسمية الموضوع:** `schema/core/topic.py` +**الأسطر 2-3:** تنسيق الموضوع: `{kind}://{tenant}/{namespace}/{topic}` +هذه البنية URI خاصة بـ Pulsar (على سبيل المثال، `persistent://tg/flow/config`) + +**التأثير:** +تستخدم جميع تعريفات الرسائل/الردود في قاعدة التعليمات البرمجية مخططات Pulsar +يتضمن ذلك الخدمات الخاصة بـ: config, flow, llm, prompt, query, storage, agent, collection, diagnosis, library, lookup, nlp_query, objects_query, retrieval, structured_query +يتم استيراد تعريفات المخططات واستخدامها على نطاق واسع في جميع المعالجات والخدمات + +## ملخص + +### تبعيات Pulsar حسب الفئة + +1. **إنشاء العميل:** + مباشر: `gateway/service.py` + مجرد: `async_processor.py` → `pubsub.py` (PulsarClient) + +2. **نقل الرسائل:** + المستهلك: `consumer.py`, `consumer_spec.py` + المنتج: `producer.py`, `producer_spec.py` + الناشر: `publisher.py` + المشترك: `subscriber.py`, `subscriber_spec.py` + +3. **نظام المخططات:** + الأنواع الأساسية: `schema/core/primitives.py` + جميع مخططات الخدمة: `schema/services/*.py` + تسمية الموضوع: `schema/core/topic.py` + +4. **مفاهيم Pulsar الخاصة المطلوبة:** + رسائل قائمة على الموضوع + نظام المخططات (السجل، أنواع الحقول) + اشتراكات مشتركة + إقرار الرسالة (إيجابي/سلبي) + موضع المستهلك (الأول/الأخير) + خصائص الرسالة + المواضع الأولية وأنواع المستهلك + دعم التجزئة + مواضيع مستمرة مقابل مواضيع غير مستمرة + +### تحديات إعادة الهيكلة + +الخبر السار: توفر طبقة التجريد (المستهلك، المنتج، الناشر، المشترك) تغليفًا نظيفًا لمعظم تفاعلات Pulsar. + +التحديات: +1. **انتشار نظام المخططات:** يستخدم كل تعريف للرسالة `pulsar.schema.Record` وأنواع Pulsar للحقول +2. **قوائم Pulsar الخاصة:** `InitialPosition`, `ConsumerType` +3. **استثناءات Pulsar:** `_pulsar.Timeout`, `_pulsar.Interrupted`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +4. **توقيعات الطريقة:** `acknowledge()`, `negative_acknowledge()`, `subscribe()`, `create_producer()`، إلخ. +5. **تنسيق URI للموضوع:** هيكل Pulsar `kind://tenant/namespace/topic` + +### الخطوات التالية + +لجعل البنية التحتية للنشر/الاشتراك قابلة للتكوين، نحتاج إلى: + +1. إنشاء واجهة تجريد لنظام العميل/المخططات +2. تجريد قوائم Pulsar الخاصة والاستثناءات +3. إنشاء أغلفة المخططات أو تعريفات مخططات بديلة +4. تنفيذ الواجهة لكل من Pulsar وأنظمة بديلة (Kafka, RabbitMQ, Redis Streams, إلخ.) +5. تحديث `pubsub.py` ليكون قابلاً للتكوين ودعم الخلفيات المتعددة +6. توفير مسار ترحيل للنشر الحالي + +## مسودة النهج 1: نمط المحول مع طبقة ترجمة المخططات + +### الفكرة الرئيسية +**نظام المخططات** هو نقطة التكامل الأعمق - كل شيء آخر ينبع منه. نحتاج إلى حل هذه المشكلة أولاً، وإلا سنعيد كتابة قاعدة التعليمات البرمجية بأكملها. + +### الاستراتيجية: الحد الأدنى من الاضطرابات مع المحولات + +**1. الحفاظ على مخططات Pulsar كتمثيل داخلي** +لا تقم بإعادة كتابة جميع تعريفات المخططات. +تبقى المخططات `pulsar.schema.Record` داخليًا. +استخدم المحولات لترجمة البيانات عند الحد بين التعليمات البرمجية الخاصة بنا والخلفية الخاصة بالنشر والاشتراك. + +**2. إنشاء طبقة تجريدية للنشر والاشتراك:** + +``` +┌─────────────────────────────────────┐ +│ Existing Code (unchanged) │ +│ - Uses Pulsar schemas internally │ +│ - Consumer/Producer/Publisher │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - Creates backend-specific client │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────┐ ┌────▼─────────┐ +│ PulsarAdapter│ │ KafkaAdapter │ etc... +│ (passthrough)│ │ (translates) │ +└──────────────┘ └──────────────┘ +``` + +**3. تحديد الواجهات المجردة:** +`PubSubClient` - اتصال العميل +`PubSubProducer` - إرسال الرسائل +`PubSubConsumer` - استقبال الرسائل +`SchemaAdapter` - ترجمة مخططات Pulsar إلى/من JSON أو التنسيقات الخاصة بالخلفية + +**4. تفاصيل التنفيذ:** + +بالنسبة إلى **محول Pulsar**: تمرير تقريبي، ترجمة محدودة + +بالنسبة إلى **الخلفيات الأخرى** (Kafka، RabbitMQ، إلخ): +تسلسل كائنات سجل Pulsar إلى JSON/بايت +مطابقة المفاهيم مثل: + `InitialPosition.Earliest/Latest` → auto.offset.reset في Kafka + `acknowledge()` → commit في Kafka + `negative_acknowledge()` → نمط إعادة الترتيب أو قائمة الانتظار الميتة (DLQ) + عناوين الموضوع → أسماء الموضوعات الخاصة بالخلفية + +### التحليل + +**المزايا:** +✅ تغييرات قليلة في التعليمات البرمجية للخدمات الحالية +✅ تبقى المخططات كما هي (بدون إعادة كتابة شاملة) +✅ مسار ترحيل تدريجي +✅ لا يلاحظ مستخدمو Pulsar أي فرق +✅ إضافة خلفيات جديدة عبر المحولات + +**العيوب:** +⚠️ لا يزال يعتمد على Pulsar (لتحديد المخططات) +⚠️ بعض عدم التطابق في ترجمة المفاهيم + +### بديل يجب أخذه في الاعتبار + +إنشاء **نظام مخططات TrustGraph** مستقل عن النشر والاشتراك (باستخدام فئات البيانات أو Pydantic)، ثم إنشاء مخططات Pulsar/Kafka/إلخ من ذلك. يتطلب هذا إعادة كتابة كل ملف مخطط وقد يؤدي إلى تغييرات غير متوقعة. + +### التوصية للإصدار الأول + +ابدأ بـ **نهج المحول** لأنه: +1. عملي - يعمل مع التعليمات البرمجية الحالية +2. يثبت المفهوم بأقل قدر من المخاطر +3. يمكن أن يتطور إلى نظام مخططات أصلي لاحقًا إذا لزم الأمر +4. مدفوع بالتكوين: متغير بيئة واحد يقوم بتبديل الخلفيات + +## النهج المقترح للإصدار الثاني: نظام مخططات مستقل عن الخلفية باستخدام فئات البيانات + +### المفهوم الأساسي + +استخدم **فئات البيانات** في Python كتنسيق تعريف مخطط محايد. توفر كل خلفية نشر واشتراك الخاصة بها تسلسلًا/إلغاء تسلسل لـ فئات البيانات، مما يلغي الحاجة إلى بقاء مخططات Pulsar في قاعدة التعليمات البرمجية. + +### تعدد الأشكال للمخططات على مستوى المصنع + +بدلاً من ترجمة مخططات Pulsar، **توفر كل خلفية معالجتها الخاصة للمخططات** والتي تعمل مع فئات البيانات القياسية في Python. + +### تدفق الناشر + +```python +# 1. Get the configured backend from factory +pubsub = get_pubsub() # Returns PulsarBackend, MQTTBackend, etc. + +# 2. Get schema class from the backend +# (Can be imported directly - backend-agnostic) +from trustgraph.schema.services.llm import TextCompletionRequest + +# 3. Create a producer/publisher for a specific topic +producer = pubsub.create_producer( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend what schema to use +) + +# 4. Create message instances (same API regardless of backend) +request = TextCompletionRequest( + system="You are helpful", + prompt="Hello world", + streaming=False +) + +# 5. Send the message +producer.send(request) # Backend serializes appropriately +``` + +### تدفق المستهلك + +```python +# 1. Get the configured backend +pubsub = get_pubsub() + +# 2. Create a consumer +consumer = pubsub.subscribe( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend how to deserialize +) + +# 3. Receive and deserialize +msg = consumer.receive() +request = msg.value() # Returns TextCompletionRequest dataclass instance + +# 4. Use the data (type-safe access) +print(request.system) # "You are helpful" +print(request.prompt) # "Hello world" +print(request.streaming) # False +``` + +### ما الذي يحدث وراء الكواليس + +**للخلفية التقنية لـ Pulsar:** +`create_producer()` → ينشئ مُنتج Pulsar باستخدام مخطط JSON أو سجل تم إنشاؤه ديناميكيًا. +`send(request)` → يقوم بتسلسل كائن البيانات (dataclass) إلى تنسيق JSON/Pulsar، ويرسله إلى Pulsar. +`receive()` → يستقبل رسالة Pulsar، ويقوم بإلغاء تسلسلها مرة أخرى إلى كائن البيانات. + +**للخلفية التقنية لـ MQTT:** +`create_producer()` → يتصل بخادم MQTT، ولا يلزم تسجيل أي مخطط. +`send(request)` → يحول كائن البيانات إلى JSON، وينشره في موضوع MQTT. +`receive()` → يشترك في موضوع MQTT، ويقوم بإلغاء تسلسل JSON إلى كائن بيانات. + +**للخلفية التقنية لـ Kafka:** +`create_producer()` → ينشئ مُنتج Kafka، ويسجل مخطط Avro إذا لزم الأمر. +`send(request)` → يقوم بتسلسل كائن البيانات إلى تنسيق Avro، ويرسله إلى Kafka. +`receive()` → يستقبل رسالة Kafka، ويقوم بإلغاء تسلسل Avro مرة أخرى إلى كائن بيانات. + +### النقاط الرئيسية في التصميم + +1. **إنشاء كائن المخطط**: نسخة كائن البيانات (`TextCompletionRequest(...)`) متطابقة بغض النظر عن الخلفية التقنية. +2. **الخلفية التقنية تتعامل مع الترميز**: كل خلفية تقنية تعرف كيفية تسلسل كائن البيانات الخاص بها إلى التنسيق المستخدم. +3. **تعريف المخطط عند الإنشاء**: عند إنشاء المنتج/المستهلك، تحدد نوع المخطط. +4. **الحفاظ على سلامة النوع**: تحصل على كائن `TextCompletionRequest` صحيح، وليس قاموسًا. +5. **لا يوجد تسرب للخلفية التقنية**: لا يقوم كود التطبيق باستيراد مكتبات خاصة بالخلفية التقنية. + +### مثال للتحويل + +**الحالي (خاص بـ Pulsar):** +```python +# schema/services/llm.py +from pulsar.schema import Record, String, Boolean, Integer + +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() +``` + +**جديد (لا يعتمد على الواجهة الخلفية):** +```python +# schema/services/llm.py +from dataclasses import dataclass + +@dataclass +class TextCompletionRequest: + system: str + prompt: str + streaming: bool = False +``` + +### التكامل مع الواجهة الخلفية (Backend Integration) + +كل واجهة خلفية تتعامل مع التسلسل/إلغاء التسلسل لفئات البيانات (dataclasses): + +**واجهة خلفية Pulsar:** +إنشاء فئات `pulsar.schema.Record` ديناميكيًا من فئات البيانات. +أو تسلسل فئات البيانات إلى JSON واستخدام مخطط JSON الخاص بـ Pulsar. +تحافظ على التوافق مع عمليات نشر Pulsar الحالية. + +**واجهة خلفية MQTT/Redis:** +تسلسل JSON مباشر لمثيل فئة البيانات. +استخدم `dataclasses.asdict()` / `from_dict()`. +خفيفة الوزن، لا تحتاج إلى سجل مخططات. + +**واجهة خلفية Kafka:** +إنشاء مخططات Avro من تعريفات فئات البيانات. +استخدم سجل مخططات Confluent. +تسلسل آمن من حيث النوع مع دعم تطور المخطط. + +### البنية (Architecture) + +``` +┌─────────────────────────────────────┐ +│ Application Code │ +│ - Uses dataclass schemas │ +│ - Backend-agnostic │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - get_pubsub() returns backend │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────────┐ ┌────▼──────────────┐ +│ PulsarBackend │ │ MQTTBackend │ +│ - JSON schema │ │ - JSON serialize │ +│ - or dynamic │ │ - Simple queues │ +│ Record gen │ │ │ +└─────────────────┘ └───────────────────┘ +``` + +### تفاصيل التنفيذ + +**1. تعريفات المخططات:** فئات بيانات بسيطة مع تلميحات الأنواع + `str`، `int`، `bool`، `float` للقيم الأولية + `list[T]` للمصفوفات + `dict[str, T]` للخرائط + فئات بيانات متداخلة للأنواع المعقدة + +**2. يوفر كل خلفية:** + المُسلسل: `dataclass → bytes/wire format` + المُفكك: `bytes/wire format → dataclass` + تسجيل المخطط (إذا لزم الأمر، مثل Pulsar/Kafka) + +**3. تجريد المستهلك/المنتج:** + موجود بالفعل (consumer.py, producer.py) + تحديث لاستخدام التسلسل الخاص بالخلفية + إزالة استيرادات Pulsar المباشرة + +**4. تعيينات الأنواع:** + Pulsar `String()` → Python `str` + Pulsar `Integer()` → Python `int` + Pulsar `Boolean()` → Python `bool` + Pulsar `Array(T)` → Python `list[T]` + Pulsar `Map(K, V)` → Python `dict[K, V]` + Pulsar `Double()` → Python `float` + Pulsar `Bytes()` → Python `bytes` + +### مسار الترحيل + +1. **إنشاء إصدارات من فئات البيانات** لجميع المخططات في `trustgraph/schema/` +2. **تحديث الفئات الخلفية** (المستهلك، المنتج، الناشر، المشترك) لاستخدام التسلسل المقدم من الخلفية +3. **تنفيذ PulsarBackend** باستخدام مخطط JSON أو إنشاء سجل ديناميكي +4. **الاختبار مع Pulsar** للتأكد من التوافق مع الإصدارات السابقة للنشر +5. **إضافة خلفيات جديدة** (MQTT، Kafka، Redis، إلخ) حسب الحاجة +6. **إزالة استيرادات Pulsar** من ملفات المخططات + +### الفوائد + +✅ **لا يوجد اعتماد على النشر/الاشتراك** في تعريفات المخططات +✅ **Python قياسي** - سهل الفهم، التحقق من النوع، التوثيق +✅ **أدوات حديثة** - تعمل مع mypy، إكمال التعليمات البرمجية لبيئات التطوير المتكاملة، المدققين +✅ **محسّنة للخلفية** - تستخدم كل خلفية التسلسل الأصلي +✅ **لا توجد تكلفة ترجمة** - تسلسل مباشر، بدون محولات +✅ **أمان النوع** - كائنات حقيقية مع أنواع مناسبة +✅ **التحقق السهل** - يمكن استخدام Pydantic إذا لزم الأمر + +### التحديات والحلول + +**التحدي:** يحتوي Pulsar's `Record` على تحقق من صحة الحقول في وقت التشغيل +**الحل:** استخدم فئات بيانات Pydantic للتحقق من الصحة إذا لزم الأمر، أو ميزات فئة البيانات Python 3.10+ مع `__post_init__` + +**التحدي:** بعض ميزات Pulsar الخاصة (مثل نوع `Bytes`) +**الحل:** قم بتعيين إلى نوع `bytes` في فئة البيانات، تتعامل الخلفية مع الترميز بشكل مناسب + +**التحدي:** تسمية الموضوع (`persistent://tenant/namespace/topic`) +**الحل:** قم بتجريد أسماء الموضوع في تعريفات المخططات، تقوم الخلفية بتحويلها إلى التنسيق المناسب + +**التحدي:** تطور المخططات والتحكم في الإصدار +**الحل:** تتعامل كل خلفية مع هذا وفقًا لقدراتها (إصدارات مخطط Pulsar، سجل مخطط Kafka، إلخ) + +**التحدي:** الأنواع المعقدة المتداخلة +**الحل:** استخدم فئات بيانات متداخلة، تقوم الخلفيات بالتسلسل/فك التسلسل بشكل متكرر + +### قرارات التصميم + +1. **فئات بيانات عادية أو Pydantic؟** + ✅ **القرار: استخدم فئات بيانات Python عادية** + أبسط، بدون تبعيات إضافية + التحقق من الصحة ليس مطلوبًا عمليًا + أسهل في الفهم والصيانة + +2. **تطور المخطط:** + ✅ **القرار: لا يلزم آلية للتحكم في الإصدار** + المخططات مستقرة وطويلة الأمد + عادةً ما تضيف التحديثات حقولًا جديدة (متوافقة مع الإصدارات السابقة) + تتعامل الخلفيات مع تطور المخطط وفقًا لقدراتها + +3. **التوافق مع الإصدارات السابقة:** + ✅ **القرار: تغيير رئيسي للإصدار، لا يلزم التوافق مع الإصدارات السابقة** + سيكون هذا تغييرًا جذريًا مع تعليمات ترحيل + يسمح الفصل النظيف بتصميم أفضل + سيتم توفير دليل ترحيل للنشر الحالي + +4. **الأنواع المتداخلة والهياكل المعقدة:** + ✅ **القرار: استخدم فئات بيانات متداخلة بشكل طبيعي** + تتعامل فئات بيانات Python مع التداخل بشكل مثالي + `list[T]` للمصفوفات، `dict[K, V]` للخرائط + تقوم الخلفيات بالتسلسل/فك التسلسل بشكل متكرر + مثال: + ```python + @dataclass + class Value: + value: str + is_uri: bool + + @dataclass + class Triple: + s: Value # Nested dataclass + p: Value + o: Value + + @dataclass + class GraphQuery: + triples: list[Triple] # Array of nested dataclasses + metadata: dict[str, str] + ``` + +5. **القيم الافتراضية والحقول الاختيارية:** + ✅ **القرار: مزيج من الحقول المطلوبة، والقيم الافتراضية، والحقول الاختيارية** + الحقول المطلوبة: لا توجد قيمة افتراضية. + الحقول التي تحتوي على قيم افتراضية: موجودة دائمًا، ولها قيمة افتراضية منطقية. + الحقول الاختيارية حقًا: `T | None = None`، يتم حذفها من التسلسل عند `None`. + مثال: + ```python + @dataclass + class TextCompletionRequest: + system: str # Required, no default + prompt: str # Required, no default + streaming: bool = False # Optional with default value + metadata: dict | None = None # Truly optional, can be absent + ``` + + **المعاني الأساسية للتسلسل الهام:** + + عندما يكون `metadata = None`: + ```json + { + "system": "...", + "prompt": "...", + "streaming": false + // metadata field NOT PRESENT + } + ``` + + عندما `metadata = {}` (فارغة بشكل صريح): + ```json + { + "system": "...", + "prompt": "...", + "streaming": false, + "metadata": {} // Field PRESENT but empty + } + ``` + + **الفرق الرئيسي:** + `None` → حقل غير موجود في JSON (غير مُسلسل) + قيمة فارغة (`{}`، `[]`، `""`) → حقل موجود بقيمة فارغة + هذا مهم من الناحية الدلالية: "غير مقدم" مقابل "فارغ بشكل صريح" + يجب على أنظمة التسلسل الخلفية تخطي حقول `None`، وليس ترميزها كـ `null` + +## مسودة الحل الثالث: تفاصيل التنفيذ + +### تنسيق اسم قائمة انتظار عام + +استبدل أسماء قوائم الانتظار الخاصة بكل نظام خلفي بتنسيق عام يمكن للأنظمة الخلفية تعيينه بشكل مناسب. + +**التنسيق:** `{qos}/{tenant}/{namespace}/{queue-name}` + +حيث: +`qos`: مستوى جودة الخدمة + `q0` = بذل جهد (إرسال وإهمال، بدون إقرار) + `q1` = مرة واحدة على الأقل (يتطلب إقرارًا) + `q2` = مرة واحدة بالضبط (إقرار من مرحلتين) +`tenant`: تجميع منطقي للتعددية +`namespace`: تجميع فرعي داخل المستأجر +`queue-name`: اسم قائمة الانتظار/الموضوع الفعلي + +**أمثلة:** +``` +q1/tg/flow/text-completion-requests +q2/tg/config/config-push +q0/tg/metrics/stats +``` + +### ربط الموضوعات في الواجهة الخلفية + +تقوم كل واجهة خلفية بتحويل التنسيق العام إلى تنسيقها الأصلي: + +**الواجهة الخلفية Pulsar:** +```python +def map_topic(self, generic_topic: str) -> str: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS to persistence + persistence = 'persistent' if qos in ['q1', 'q2'] else 'non-persistent' + + # Return Pulsar URI: persistent://tg/flow/text-completion-requests + return f"{persistence}://{tenant}/{namespace}/{queue}" +``` + +**الخلفية التقنية لـ MQTT:** +```python +def map_topic(self, generic_topic: str) -> tuple[str, int]: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS level + qos_level = {'q0': 0, 'q1': 1, 'q2': 2}[qos] + + # Build MQTT topic including tenant/namespace for proper namespacing + mqtt_topic = f"{tenant}/{namespace}/{queue}" + + return mqtt_topic, qos_level +``` + +### الدالة المساعدة للموضوع المحدّثة + +```python +# schema/core/topic.py +def topic(queue_name, qos='q1', tenant='tg', namespace='flow'): + """ + Create a generic topic identifier that can be mapped by backends. + + Args: + queue_name: The queue/topic name + qos: Quality of service + - 'q0' = best-effort (no ack) + - 'q1' = at-least-once (ack required) + - 'q2' = exactly-once (two-phase ack) + tenant: Tenant identifier for multi-tenancy + namespace: Namespace within tenant + + Returns: + Generic topic string: qos/tenant/namespace/queue_name + + Examples: + topic('my-queue') # q1/tg/flow/my-queue + topic('config', qos='q2', namespace='config') # q2/tg/config/config + """ + return f"{qos}/{tenant}/{namespace}/{queue_name}" +``` + +### التكوين والتهيئة + +**وسائط سطر الأوامر + متغيرات البيئة:** + +```python +# In base/async_processor.py - add_args() method +@staticmethod +def add_args(parser): + # Pub/sub backend selection + parser.add_argument( + '--pubsub-backend', + default=os.getenv('PUBSUB_BACKEND', 'pulsar'), + choices=['pulsar', 'mqtt'], + help='Pub/sub backend (default: pulsar, env: PUBSUB_BACKEND)' + ) + + # Pulsar-specific configuration + parser.add_argument( + '--pulsar-host', + default=os.getenv('PULSAR_HOST', 'pulsar://localhost:6650'), + help='Pulsar host (default: pulsar://localhost:6650, env: PULSAR_HOST)' + ) + + parser.add_argument( + '--pulsar-api-key', + default=os.getenv('PULSAR_API_KEY', None), + help='Pulsar API key (env: PULSAR_API_KEY)' + ) + + parser.add_argument( + '--pulsar-listener', + default=os.getenv('PULSAR_LISTENER', None), + help='Pulsar listener name (env: PULSAR_LISTENER)' + ) + + # MQTT-specific configuration + parser.add_argument( + '--mqtt-host', + default=os.getenv('MQTT_HOST', 'localhost'), + help='MQTT broker host (default: localhost, env: MQTT_HOST)' + ) + + parser.add_argument( + '--mqtt-port', + type=int, + default=int(os.getenv('MQTT_PORT', '1883')), + help='MQTT broker port (default: 1883, env: MQTT_PORT)' + ) + + parser.add_argument( + '--mqtt-username', + default=os.getenv('MQTT_USERNAME', None), + help='MQTT username (env: MQTT_USERNAME)' + ) + + parser.add_argument( + '--mqtt-password', + default=os.getenv('MQTT_PASSWORD', None), + help='MQTT password (env: MQTT_PASSWORD)' + ) +``` + +**دالة المصنع:** + +```python +# In base/pubsub.py or base/pubsub_factory.py +def get_pubsub(**config) -> PubSubBackend: + """ + Create and return a pub/sub backend based on configuration. + + Args: + config: Configuration dict from command-line args + Must include 'pubsub_backend' key + + Returns: + Backend instance (PulsarBackend, MQTTBackend, etc.) + """ + backend_type = config.get('pubsub_backend', 'pulsar') + + if backend_type == 'pulsar': + return PulsarBackend( + host=config.get('pulsar_host'), + api_key=config.get('pulsar_api_key'), + listener=config.get('pulsar_listener'), + ) + elif backend_type == 'mqtt': + return MQTTBackend( + host=config.get('mqtt_host'), + port=config.get('mqtt_port'), + username=config.get('mqtt_username'), + password=config.get('mqtt_password'), + ) + else: + raise ValueError(f"Unknown pub/sub backend: {backend_type}") +``` + +**الاستخدام في AsyncProcessor:** + +```python +# In async_processor.py +class AsyncProcessor: + def __init__(self, **params): + self.id = params.get("id") + + # Create backend from config (replaces PulsarClient) + self.pubsub = get_pubsub(**params) + + # Rest of initialization... +``` + +### الواجهة الخلفية + +```python +class PubSubBackend(Protocol): + """Protocol defining the interface all pub/sub backends must implement.""" + + def create_producer(self, topic: str, schema: type, **options) -> BackendProducer: + """ + Create a producer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + schema: Dataclass type for messages + options: Backend-specific options (e.g., chunking_enabled) + + Returns: + Backend-specific producer instance + """ + ... + + def create_consumer( + self, + topic: str, + subscription: str, + schema: type, + initial_position: str = 'latest', + consumer_type: str = 'shared', + **options + ) -> BackendConsumer: + """ + Create a consumer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + subscription: Subscription/consumer group name + schema: Dataclass type for messages + initial_position: 'earliest' or 'latest' (MQTT may ignore) + consumer_type: 'shared', 'exclusive', 'failover' (MQTT may ignore) + options: Backend-specific options + + Returns: + Backend-specific consumer instance + """ + ... + + def close(self) -> None: + """Close the backend connection.""" + ... +``` + +```python +class BackendProducer(Protocol): + """Protocol for backend-specific producer.""" + + def send(self, message: Any, properties: dict = {}) -> None: + """Send a message (dataclass instance) with optional properties.""" + ... + + def flush(self) -> None: + """Flush any buffered messages.""" + ... + + def close(self) -> None: + """Close the producer.""" + ... +``` + +```python +class BackendConsumer(Protocol): + """Protocol for backend-specific consumer.""" + + def receive(self, timeout_millis: int = 2000) -> Message: + """ + Receive a message from the topic. + + Raises: + TimeoutError: If no message received within timeout + """ + ... + + def acknowledge(self, message: Message) -> None: + """Acknowledge successful processing of a message.""" + ... + + def negative_acknowledge(self, message: Message) -> None: + """Negative acknowledge - triggers redelivery.""" + ... + + def unsubscribe(self) -> None: + """Unsubscribe from the topic.""" + ... + + def close(self) -> None: + """Close the consumer.""" + ... +``` + +```python +class Message(Protocol): + """Protocol for a received message.""" + + def value(self) -> Any: + """Get the deserialized message (dataclass instance).""" + ... + + def properties(self) -> dict: + """Get message properties/metadata.""" + ... +``` + +### إعادة هيكلة الفئات الحالية + +تظل الفئات الحالية `Consumer`، `Producer`، `Publisher`، `Subscriber` في الغالب دون تغيير: + +**المسؤوليات الحالية (يجب الحفاظ عليها):** +نموذج الخيوط غير المتزامنة ومجموعات المهام. +منطق إعادة الاتصال ومعالجة إعادة المحاولة. +جمع المقاييس. +تحديد المعدل. +إدارة التزامن. + +**التغييرات المطلوبة:** +إزالة استيرادات Pulsar المباشرة (`pulsar.schema`، `pulsar.InitialPosition`، إلخ). +قبول `BackendProducer`/`BackendConsumer` بدلاً من عميل Pulsar. +تفويض عمليات النشر/الاشتراك الفعلية إلى مثيلات الواجهة الخلفية. +مطابقة المفاهيم العامة إلى استدعاءات الواجهة الخلفية. + +**مثال على إعادة الهيكلة:** + +```python +# OLD - consumer.py +class Consumer: + def __init__(self, client, topic, subscriber, schema, ...): + self.client = client # Direct Pulsar client + # ... + + async def consumer_run(self): + # Uses pulsar.InitialPosition, pulsar.ConsumerType + self.consumer = self.client.subscribe( + topic=self.topic, + schema=JsonSchema(self.schema), + initial_position=pulsar.InitialPosition.Earliest, + consumer_type=pulsar.ConsumerType.Shared, + ) + +# NEW - consumer.py +class Consumer: + def __init__(self, backend_consumer, schema, ...): + self.backend_consumer = backend_consumer # Backend-specific consumer + self.schema = schema + # ... + + async def consumer_run(self): + # Backend consumer already created with right settings + # Just use it directly + while self.running: + msg = await asyncio.to_thread( + self.backend_consumer.receive, + timeout_millis=2000 + ) + await self.handle_message(msg) +``` + +### السلوكيات الخاصة بالخادم الخلفي + +**الخادم الخلفي Pulsar:** +يربط `q0` → `non-persistent://`، و `q1`/`q2` → `persistent://` +يدعم جميع أنواع المستهلكين (مشترك، حصري، احتياطي) +يدعم الموضع الأولي (الأول/الأخير) +إقرار الرسائل الأصلي +دعم سجل المخططات + +**الخادم الخلفي MQTT:** +يربط `q0`/`q1`/`q2` بمستويات جودة الخدمة MQTT 0/1/2 +يتضمن المستأجر/المساحة الاسمية في مسار الموضوع لعملية التمييز +يقوم بإنشاء معرفات العملاء تلقائيًا من أسماء الاشتراكات +يتجاهل الموضع الأولي (لا يوجد سجل رسائل في MQTT الأساسي) +يتجاهل نوع المستهلك (يستخدم MQTT معرفات العملاء، وليس مجموعات المستهلكين) +نموذج نشر/اشتراك بسيط + +### ملخص قرارات التصميم + +1. ✅ **تسمية قائمة انتظار عامة**: بتنسيق `qos/tenant/namespace/queue-name` +2. ✅ **جودة الخدمة في معرف قائمة الانتظار**: يتم تحديدها بواسطة تعريف قائمة الانتظار، وليس التكوين +3. ✅ **إعادة الاتصال**: تتم معالجتها بواسطة فئات المستهلك/المنتج، وليس الخوادم الخلفية +4. ✅ **مواضيع MQTT**: تتضمن المستأجر/المساحة الاسمية لعملية التمييز المناسبة +5. ✅ **سجل الرسائل**: يتجاهل MQTT معلمة `initial_position` (تحسين مستقبلي) +6. ✅ **معرفات العملاء**: يقوم خادم MQTT بإنشائها تلقائيًا من اسم الاشتراك + +### التحسينات المستقبلية + +**سجل رسائل MQTT:** +يمكن إضافة طبقة تخزين اختيارية (مثل الرسائل المحفوظة، أو مخزن خارجي) +سيسمح بدعم `initial_position='earliest'` +ليس مطلوبًا للتنفيذ الأولي + diff --git a/docs/tech-specs/pubsub.es.md b/docs/tech-specs/pubsub.es.md new file mode 100644 index 00000000..1679a577 --- /dev/null +++ b/docs/tech-specs/pubsub.es.md @@ -0,0 +1,958 @@ +# Infraestructura Pub/Sub + +## Resumen + +Este documento cataloga todas las conexiones entre el código base de TrustGraph y la infraestructura pub/sub. Actualmente, el sistema está codificado para usar Apache Pulsar. Este análisis identifica todos los puntos de integración para informar futuras refactorizaciones hacia una abstracción pub/sub configurable. + +## Estado actual: Puntos de integración de Pulsar + +### 1. Uso directo del cliente de Pulsar + +**Ubicación:** `trustgraph-flow/trustgraph/gateway/service.py` + +La puerta de enlace de la API importa y crea una instancia directamente del cliente de Pulsar: + +**Línea 20:** `import pulsar` +**Líneas 54-61:** Creación directa de `pulsar.Client()` con `pulsar.AuthenticationToken()` opcional +**Líneas 33-35:** Configuración predeterminada del host de Pulsar desde variables de entorno +**Líneas 178-192:** Argumentos de la línea de comandos para `--pulsar-host`, `--pulsar-api-key` y `--pulsar-listener` +**Líneas 78, 124:** Pasa `pulsar_client` a `ConfigReceiver` y `DispatcherManager` + +Esta es la única ubicación que crea directamente un cliente de Pulsar fuera de la capa de abstracción. + +### 2. Marco base del procesador + +**Ubicación:** `trustgraph-base/trustgraph/base/async_processor.py` + +La clase base para todos los procesadores proporciona conectividad de Pulsar: + +**Línea 9:** `import _pulsar` (para el manejo de excepciones) +**Línea 18:** `from . pubsub import PulsarClient` +**Línea 38:** Crea `pulsar_client_object = PulsarClient(**params)` +**Líneas 104-108:** Propiedades que exponen `pulsar_host` y `pulsar_client` +**Línea 250:** El método estático `add_args()` llama a `PulsarClient.add_args(parser)` para los argumentos de la línea de comandos +**Líneas 223-225:** Manejo de excepciones para `_pulsar.Interrupted` + +Todos los procesadores heredan de `AsyncProcessor`, lo que convierte a este en el punto de integración central. + +### 3. Abstracción del consumidor + +**Ubicación:** `trustgraph-base/trustgraph/base/consumer.py` + +Consume mensajes de colas e invoca funciones de controlador: + +**Importaciones de Pulsar:** +**Línea 12:** `from pulsar.schema import JsonSchema` +**Línea 13:** `import pulsar` +**Línea 14:** `import _pulsar` + +**Uso específico de Pulsar:** +**Líneas 100, 102:** `pulsar.InitialPosition.Earliest` / `pulsar.InitialPosition.Latest` +**Línea 108:** Envoltorio `JsonSchema(self.schema)` +**Línea 110:** `pulsar.ConsumerType.Shared` +**Líneas 104-111:** `self.client.subscribe()` con parámetros específicos de Pulsar +**Líneas 143, 150, 65:** Métodos `consumer.unsubscribe()` y `consumer.close()` +**Línea 162:** Excepción `_pulsar.Timeout` +**Líneas 182, 205, 232:** `consumer.acknowledge()` / `consumer.negative_acknowledge()` + +**Archivo de especificación:** `trustgraph-base/trustgraph/base/consumer_spec.py` +**Línea 22:** Hace referencia a `processor.pulsar_client` + +### 4. Abstracción del productor + +**Ubicación:** `trustgraph-base/trustgraph/base/producer.py` + +Envía mensajes a colas: + +**Importaciones de Pulsar:** +**Línea 2:** `from pulsar.schema import JsonSchema` + +**Uso específico de Pulsar:** +**Línea 49:** Envoltorio `JsonSchema(self.schema)` +**Líneas 47-51:** `self.client.create_producer()` con parámetros específicos de Pulsar (tema, esquema, habilitación de fragmentación) +**Líneas 31, 76:** Método `producer.close()` +**Líneas 64-65:** `producer.send()` con mensaje y propiedades + +**Archivo de especificación:** `trustgraph-base/trustgraph/base/producer_spec.py` +**Línea 18:** Hace referencia a `processor.pulsar_client` + +### 5. Abstracción del publicador + +**Ubicación:** `trustgraph-base/trustgraph/base/publisher.py` + +Publicación de mensajes asíncrona con almacenamiento en búfer de cola: + +**Importaciones de Pulsar:** +**Línea 2:** `from pulsar.schema import JsonSchema` +**Línea 6:** `import pulsar` + +**Uso específico de Pulsar:** +**Línea 52:** Envoltorio `JsonSchema(self.schema)` +**Líneas 50-54:** `self.client.create_producer()` con parámetros específicos de Pulsar +**Líneas 101, 103:** `producer.send()` con mensaje y propiedades opcionales +**Líneas 106-107:** Métodos `producer.flush()` y `producer.close()` + +### 6. Abstracción del suscriptor + +**Ubicación:** `trustgraph-base/trustgraph/base/subscriber.py` + +Proporciona la distribución de mensajes a múltiples destinatarios desde colas: + +**Importaciones de Pulsar:** +**Línea 6:** `from pulsar.schema import JsonSchema` +**Línea 8:** `import _pulsar` + +**Uso específico de Pulsar:** +**Línea 55:** `JsonSchema(self.schema)` wrapper +**Línea 57:** `self.client.subscribe(**subscribe_args)` +**Líneas 101, 136, 160, 167-172:** Excepciones de Pulsar: `_pulsar.Timeout`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +**Líneas 159, 166, 170:** Métodos de consumidor: `negative_acknowledge()`, `unsubscribe()`, `close()` +**Líneas 247, 251:** Reconocimiento de mensajes: `acknowledge()`, `negative_acknowledge()` + +**Archivo de especificaciones:** `trustgraph-base/trustgraph/base/subscriber_spec.py` +**Línea 19:** Referencias a `processor.pulsar_client` + +### 7. Sistema de esquemas (Heart of Darkness) + +**Ubicación:** `trustgraph-base/trustgraph/schema/` + +Cada esquema de mensaje en el sistema se define utilizando el marco de esquemas de Pulsar. + +**Primitivos principales:** `schema/core/primitives.py` +**Línea 2:** `from pulsar.schema import Record, String, Boolean, Array, Integer` +Todos los esquemas heredan de la clase base de Pulsar `Record` +Todos los tipos de campo son tipos de Pulsar: `String()`, `Integer()`, `Boolean()`, `Array()`, `Map()`, `Double()` + +**Esquemas de ejemplo:** +`schema/services/llm.py` (Línea 2): `from pulsar.schema import Record, String, Array, Double, Integer, Boolean` +`schema/services/config.py` (Línea 2): `from pulsar.schema import Record, Bytes, String, Boolean, Array, Map, Integer` + +**Nomenclatura de temas:** `schema/core/topic.py` +**Líneas 2-3:** Formato del tema: `{kind}://{tenant}/{namespace}/{topic}` +Esta estructura de URI es específica de Pulsar (por ejemplo, `persistent://tg/flow/config`) + +**Impacto:** +Todas las definiciones de mensajes de solicitud/respuesta en todo el código base utilizan esquemas de Pulsar +Esto incluye servicios para: config, flow, llm, prompt, query, storage, agent, collection, diagnosis, library, lookup, nlp_query, objects_query, retrieval, structured_query +Las definiciones de esquemas se importan y utilizan ampliamente en todos los procesadores y servicios + +## Resumen + +### Dependencias de Pulsar por Categoría + +1. **Instanciación del cliente:** + Directo: `gateway/service.py` + Abstracto: `async_processor.py` → `pubsub.py` (PulsarClient) + +2. **Transporte de mensajes:** + Consumidor: `consumer.py`, `consumer_spec.py` + Productor: `producer.py`, `producer_spec.py` + Publicador: `publisher.py` + Suscriptor: `subscriber.py`, `subscriber_spec.py` + +3. **Sistema de esquemas:** + Tipos base: `schema/core/primitives.py` + Todos los esquemas de servicio: `schema/services/*.py` + Nomenclatura de temas: `schema/core/topic.py` + +4. **Conceptos específicos de Pulsar requeridos:** + Mensajería basada en temas + Sistema de esquemas (Registro, tipos de campo) + Suscripciones compartidas + Reconocimiento de mensajes (positivo/negativo) + Posicionamiento del consumidor (más temprano/más reciente) + Propiedades del mensaje + Posiciones iniciales y tipos de consumidor + Soporte de fragmentación + Temas persistentes frente a no persistentes + +### Desafíos de refactorización + +La buena noticia: la capa de abstracción (Consumidor, Productor, Publicador, Suscriptor) proporciona una encapsulación limpia de la mayoría de las interacciones de Pulsar. + +Los desafíos: +1. **Ubicuidad del sistema de esquemas:** Cada definición de mensaje utiliza `pulsar.schema.Record` y los tipos de campo de Pulsar +2. **Enums específicos de Pulsar:** `InitialPosition`, `ConsumerType` +3. **Excepciones de Pulsar:** `_pulsar.Timeout`, `_pulsar.Interrupted`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +4. **Fichas de método:** `acknowledge()`, `negative_acknowledge()`, `subscribe()`, `create_producer()`, etc. +5. **Formato de URI de tema:** Estructura de Pulsar `kind://tenant/namespace/topic` + +### Próximos pasos + +Para hacer que la infraestructura de pub/sub sea configurable, necesitamos: + +1. Crear una interfaz de abstracción para el sistema de cliente/esquemas +2. Abstractar enums y excepciones específicas de Pulsar +3. Crear envoltorios de esquema o definiciones de esquema alternativas +4. Implementar la interfaz tanto para Pulsar como para sistemas alternativos (Kafka, RabbitMQ, Redis Streams, etc.) +5. Actualizar `pubsub.py` para que sea configurable y admita varios backends +6. Proporcionar una ruta de migración para implementaciones existentes + +## Borrador de enfoque 1: Patrón de adaptador con capa de traducción de esquemas + +### Idea clave +El **sistema de esquemas** es el punto de integración más profundo; todo lo demás se deriva de él. Necesitamos resolver esto primero, o tendremos que reescribir todo el código base. + +### Estrategia: Interrupción mínima con adaptadores + +**1. Mantener los esquemas de Pulsar como la representación interna** +No reescribir todas las definiciones de esquemas. +Los esquemas permanecen `pulsar.schema.Record` internamente. +Utilizar adaptadores para traducir en la frontera entre nuestro código y el backend de publicación/suscripción. + +**2. Crear una capa de abstracción de publicación/suscripción:** + +``` +┌─────────────────────────────────────┐ +│ Existing Code (unchanged) │ +│ - Uses Pulsar schemas internally │ +│ - Consumer/Producer/Publisher │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - Creates backend-specific client │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────┐ ┌────▼─────────┐ +│ PulsarAdapter│ │ KafkaAdapter │ etc... +│ (passthrough)│ │ (translates) │ +└──────────────┘ └──────────────┘ +``` + +**3. Defina interfaces abstractas:** +`PubSubClient` - conexión del cliente +`PubSubProducer` - envío de mensajes +`PubSubConsumer` - recepción de mensajes +`SchemaAdapter` - traducción de esquemas de Pulsar a/desde JSON o formatos específicos del backend + +**4. Detalles de implementación:** + +Para el **adaptador de Pulsar**: Casi una transmisión directa, traducción mínima. + +Para **otros backends** (Kafka, RabbitMQ, etc.): +Serializar objetos de registro de Pulsar a JSON/bytes. +Mapear conceptos como: + `InitialPosition.Earliest/Latest` → auto.offset.reset de Kafka + `acknowledge()` → confirmación de Kafka + `negative_acknowledge()` → patrón de re-cola o cola de mensajes no entregados (DLQ). + URIs de temas → nombres de temas específicos del backend. + +### Análisis + +**Ventajas:** +✅ Cambios mínimos en el código de los servicios existentes. +✅ Los esquemas permanecen sin cambios (sin reescritura masiva). +✅ Ruta de migración gradual. +✅ Los usuarios de Pulsar no notan ninguna diferencia. +✅ Se agregan nuevos backends a través de adaptadores. + +**Desventajas:** +⚠️ Aún mantiene la dependencia de Pulsar (para las definiciones de esquemas). +⚠️ Algunos problemas de compatibilidad al traducir conceptos. + +### Consideración alternativa + +Crear un sistema de esquemas **TrustGraph** que sea independiente de pub/sub (usando dataclasses o Pydantic), y luego generar esquemas de Pulsar/Kafka/etc a partir de él. Esto requiere reescribir cada archivo de esquema y podría provocar cambios importantes. + +### Recomendación para la versión preliminar 1 + +Comience con el **enfoque de adaptador** porque: +1. Es práctico: funciona con el código existente. +2. Demuestra el concepto con un riesgo mínimo. +3. Puede evolucionar hacia un sistema de esquemas nativo más adelante, si es necesario. +4. Impulsado por la configuración: una variable de entorno cambia entre backends. + +## Enfoque de la versión preliminar 2: Sistema de esquemas independiente del backend con dataclasses + +### Concepto central + +Utilice **dataclasses** de Python como el formato de definición de esquema neutral. Cada backend de pub/sub proporciona su propia serialización/deserialización para dataclasses, eliminando la necesidad de que los esquemas de Pulsar permanezcan en el código base. + +### Polimorfismo de esquema a nivel de fábrica + +En lugar de traducir esquemas de Pulsar, **cada backend proporciona su propia gestión de esquemas** que funciona con dataclasses de Python estándar. + +### Flujo del publicador + +```python +# 1. Get the configured backend from factory +pubsub = get_pubsub() # Returns PulsarBackend, MQTTBackend, etc. + +# 2. Get schema class from the backend +# (Can be imported directly - backend-agnostic) +from trustgraph.schema.services.llm import TextCompletionRequest + +# 3. Create a producer/publisher for a specific topic +producer = pubsub.create_producer( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend what schema to use +) + +# 4. Create message instances (same API regardless of backend) +request = TextCompletionRequest( + system="You are helpful", + prompt="Hello world", + streaming=False +) + +# 5. Send the message +producer.send(request) # Backend serializes appropriately +``` + +### Flujo del consumidor + +```python +# 1. Get the configured backend +pubsub = get_pubsub() + +# 2. Create a consumer +consumer = pubsub.subscribe( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend how to deserialize +) + +# 3. Receive and deserialize +msg = consumer.receive() +request = msg.value() # Returns TextCompletionRequest dataclass instance + +# 4. Use the data (type-safe access) +print(request.system) # "You are helpful" +print(request.prompt) # "Hello world" +print(request.streaming) # False +``` + +### ¿Qué sucede detrás de escena? + +**Para el backend de Pulsar:** +`create_producer()` → crea un productor de Pulsar con un esquema JSON o un registro generado dinámicamente. +`send(request)` → serializa la clase de datos a formato JSON/Pulsar y lo envía a Pulsar. +`receive()` → recibe un mensaje de Pulsar, lo deserializa de nuevo a la clase de datos. + +**Para el backend de MQTT:** +`create_producer()` → se conecta a un broker de MQTT, no es necesario registrar ningún esquema. +`send(request)` → convierte la clase de datos a JSON y lo publica en un tema de MQTT. +`receive()` → se suscribe a un tema de MQTT y deserializa el JSON a la clase de datos. + +**Para el backend de Kafka:** +`create_producer()` → crea un productor de Kafka y registra el esquema Avro si es necesario. +`send(request)` → serializa la clase de datos a formato Avro y lo envía a Kafka. +`receive()` → recibe un mensaje de Kafka y lo deserializa de Avro de nuevo a la clase de datos. + +### Puntos Clave del Diseño + +1. **Creación del objeto de esquema**: La instancia de la clase de datos (`TextCompletionRequest(...)`) es idéntica independientemente del backend. +2. **El backend se encarga de la codificación**: Cada backend sabe cómo serializar su clase de datos al formato de cable. +3. **Definición del esquema en la creación**: Al crear el productor/consumidor, se especifica el tipo de esquema. +4. **Se mantiene la seguridad de tipos**: Se obtiene un objeto `TextCompletionRequest` adecuado, no un diccionario. +5. **Sin filtración del backend**: El código de la aplicación nunca importa bibliotecas específicas del backend. + +### Ejemplo de Transformación + +**Actual (específico de Pulsar):** +```python +# schema/services/llm.py +from pulsar.schema import Record, String, Boolean, Integer + +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() +``` + +**Nuevo (Independiente del backend):** +```python +# schema/services/llm.py +from dataclasses import dataclass + +@dataclass +class TextCompletionRequest: + system: str + prompt: str + streaming: bool = False +``` + +### Integración con el Backend + +Cada backend se encarga de la serialización/deserialización de dataclasses: + +**Backend de Pulsar:** +Genera clases `pulsar.schema.Record` dinámicamente a partir de dataclasses +O serializa dataclasses a JSON y utiliza el esquema JSON de Pulsar +Mantiene la compatibilidad con implementaciones de Pulsar existentes + +**Backend de MQTT/Redis:** +Serialización directa de instancias de dataclass a JSON +Utiliza `dataclasses.asdict()` / `from_dict()` +Ligero, no se necesita un registro de esquemas + +**Backend de Kafka:** +Genera esquemas Avro a partir de definiciones de dataclass +Utiliza el registro de esquemas de Confluent +Serialización con seguridad de tipos y soporte para la evolución del esquema + +### Arquitectura + +``` +┌─────────────────────────────────────┐ +│ Application Code │ +│ - Uses dataclass schemas │ +│ - Backend-agnostic │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - get_pubsub() returns backend │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────────┐ ┌────▼──────────────┐ +│ PulsarBackend │ │ MQTTBackend │ +│ - JSON schema │ │ - JSON serialize │ +│ - or dynamic │ │ - Simple queues │ +│ Record gen │ │ │ +└─────────────────┘ └───────────────────┘ +``` + +### Detalles de implementación + +**1. Definiciones de esquema:** Clases de datos simples con sugerencias de tipo + `str`, `int`, `bool`, `float` para tipos primitivos + `list[T]` para arreglos + `dict[str, T]` para mapas + Clases de datos anidadas para tipos complejos + +**2. Cada backend proporciona:** + Serializador: `dataclass → bytes/wire format` + Deserializador: `bytes/wire format → dataclass` + Registro de esquema (si es necesario, como Pulsar/Kafka) + +**3. Abstracción de consumidor/productor:** + Ya existe (consumer.py, producer.py) + Actualizar para usar la serialización del backend + Eliminar importaciones directas de Pulsar + +**4. Mapeos de tipo:** + Pulsar `String()` → Python `str` + Pulsar `Integer()` → Python `int` + Pulsar `Boolean()` → Python `bool` + Pulsar `Array(T)` → Python `list[T]` + Pulsar `Map(K, V)` → Python `dict[K, V]` + Pulsar `Double()` → Python `float` + Pulsar `Bytes()` → Python `bytes` + +### Ruta de migración + +1. **Crear versiones de clases de datos** de todos los esquemas en `trustgraph/schema/` +2. **Actualizar clases de backend** (Consumidor, Productor, Publicador, Suscriptor) para usar la serialización proporcionada por el backend +3. **Implementar PulsarBackend** con esquema JSON o generación dinámica de registros +4. **Probar con Pulsar** para garantizar la compatibilidad hacia atrás con las implementaciones existentes +5. **Agregar nuevos backends** (MQTT, Kafka, Redis, etc.) según sea necesario +6. **Eliminar importaciones de Pulsar** de los archivos de esquema + +### Beneficios + +✅ **Sin dependencia de pub/sub** en las definiciones de esquema +✅ **Python estándar** - fácil de entender, tipificar, documentar +✅ **Herramientas modernas** - funciona con mypy, autocompletado de IDE, analizadores +✅ **Optimizada para el backend** - cada backend utiliza la serialización nativa +✅ **Sin sobrecarga de traducción** - serialización directa, sin adaptadores +✅ **Seguridad de tipos** - objetos reales con tipos adecuados +✅ **Validación fácil** - se puede usar Pydantic si es necesario + +### Desafíos y soluciones + +**Desafío:** El `Record` de Pulsar tiene validación de campo en tiempo de ejecución +**Solución:** Usar clases de datos de Pydantic para la validación si es necesario, o características de clase de datos de Python 3.10+ con `__post_init__` + +**Desafío:** Algunas características específicas de Pulsar (como el tipo `Bytes`) +**Solución:** Mapear al tipo `bytes` en la clase de datos, el backend se encarga de la codificación apropiadamente + +**Desafío:** Nombres de temas (`persistent://tenant/namespace/topic`) +**Solución:** Abstracto los nombres de los temas en las definiciones de esquema, el backend convierte al formato adecuado + +**Desafío:** Evolución y versionado del esquema +**Solución:** Cada backend maneja esto de acuerdo con sus capacidades (versiones de esquema de Pulsar, registro de esquema de Kafka, etc.) + +**Desafío:** Tipos complejos anidados +**Solución:** Usar clases de datos anidadas, los backends serializan/deserializan recursivamente + +### Decisiones de diseño + +1. **¿Clases de datos simples o Pydantic?** + ✅ **Decisión: Usar clases de datos de Python simples** + Más simple, sin dependencias adicionales + La validación no es necesaria en la práctica + Más fácil de entender y mantener + +2. **Evolución del esquema:** + ✅ **Decisión: No se necesita un mecanismo de versionado** + Los esquemas son estables y duraderos + Las actualizaciones normalmente agregan nuevos campos (compatible con versiones anteriores) + Los backends manejan la evolución del esquema según sus capacidades + +3. **Compatibilidad hacia atrás:** + ✅ **Decisión: Cambio de versión importante, no se requiere compatibilidad hacia atrás** + Será un cambio importante con instrucciones de migración + La ruptura limpia permite un mejor diseño + Se proporcionará una guía de migración para las implementaciones existentes + +4. **Tipos anidados y estructuras complejas:** + ✅ **Decisión: Usar clases de datos anidadas de forma natural** + Las clases de datos de Python manejan el anidamiento perfectamente + `list[T]` para arreglos, `dict[K, V]` para mapas + Los backends serializan/deserializan recursivamente + Ejemplo: + ```python + @dataclass + class Value: + value: str + is_uri: bool + + @dataclass + class Triple: + s: Value # Nested dataclass + p: Value + o: Value + + @dataclass + class GraphQuery: + triples: list[Triple] # Array of nested dataclasses + metadata: dict[str, str] + ``` + +5. **Valores predeterminados y campos opcionales:** + ✅ **Decisión: Combinación de campos obligatorios, valores predeterminados y campos opcionales** + Campos obligatorios: Sin valor predeterminado + Campos con valores predeterminados: Siempre presentes, tienen un valor predeterminado razonable + Campos verdaderamente opcionales: `T | None = None`, omitidos de la serialización cuando `None` + Ejemplo: + ```python + @dataclass + class TextCompletionRequest: + system: str # Required, no default + prompt: str # Required, no default + streaming: bool = False # Optional with default value + metadata: dict | None = None # Truly optional, can be absent + ``` + + **Semántica de serialización importante:** + + Cuando `metadata = None`: + ```json + { + "system": "...", + "prompt": "...", + "streaming": false + // metadata field NOT PRESENT + } + ``` + + Cuando `metadata = {}` (explícitamente vacío): + ```json + { + "system": "...", + "prompt": "...", + "streaming": false, + "metadata": {} // Field PRESENT but empty + } + ``` + + **Diferencia clave:** + `None` → campo ausente en JSON (no se serializa) + Valor vacío (`{}`, `[]`, `""`) → campo presente con valor vacío + Esto es importante semánticamente: "no proporcionado" vs "explícitamente vacío" + Los sistemas de serialización deben omitir los campos `None`, no codificarlos como `null` + +## Esquema de Implementación Borrador 3: Detalles de Implementación + +### Formato Genérico para Nombres de Colas + +Reemplace los nombres de colas específicos del sistema de respaldo con un formato genérico que los sistemas de respaldo puedan mapear adecuadamente. + +**Formato:** `{qos}/{tenant}/{namespace}/{queue-name}` + +Donde: +`qos`: Nivel de Calidad de Servicio + `q0` = mejor esfuerzo (enviar y olvidar, sin confirmación) + `q1` = al menos una vez (requiere confirmación) + `q2` = exactamente una vez (confirmación de dos fases) +`tenant`: Agrupación lógica para multi-inquilino +`namespace`: Sub-agrupación dentro del inquilino +`queue-name`: Nombre real de la cola/tema + +**Ejemplos:** +``` +q1/tg/flow/text-completion-requests +q2/tg/config/config-push +q0/tg/metrics/stats +``` + +### Mapeo de temas del backend + +Cada backend mapea el formato genérico a su formato nativo: + +**Backend de Pulsar:** +```python +def map_topic(self, generic_topic: str) -> str: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS to persistence + persistence = 'persistent' if qos in ['q1', 'q2'] else 'non-persistent' + + # Return Pulsar URI: persistent://tg/flow/text-completion-requests + return f"{persistence}://{tenant}/{namespace}/{queue}" +``` + +**Backend de MQTT:** +```python +def map_topic(self, generic_topic: str) -> tuple[str, int]: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS level + qos_level = {'q0': 0, 'q1': 1, 'q2': 2}[qos] + + # Build MQTT topic including tenant/namespace for proper namespacing + mqtt_topic = f"{tenant}/{namespace}/{queue}" + + return mqtt_topic, qos_level +``` + +### Función de ayuda de tema actualizada + +```python +# schema/core/topic.py +def topic(queue_name, qos='q1', tenant='tg', namespace='flow'): + """ + Create a generic topic identifier that can be mapped by backends. + + Args: + queue_name: The queue/topic name + qos: Quality of service + - 'q0' = best-effort (no ack) + - 'q1' = at-least-once (ack required) + - 'q2' = exactly-once (two-phase ack) + tenant: Tenant identifier for multi-tenancy + namespace: Namespace within tenant + + Returns: + Generic topic string: qos/tenant/namespace/queue_name + + Examples: + topic('my-queue') # q1/tg/flow/my-queue + topic('config', qos='q2', namespace='config') # q2/tg/config/config + """ + return f"{qos}/{tenant}/{namespace}/{queue_name}" +``` + +### Configuración e Inicialización + +**Argumentos de Línea de Comandos + Variables de Entorno:** + +```python +# In base/async_processor.py - add_args() method +@staticmethod +def add_args(parser): + # Pub/sub backend selection + parser.add_argument( + '--pubsub-backend', + default=os.getenv('PUBSUB_BACKEND', 'pulsar'), + choices=['pulsar', 'mqtt'], + help='Pub/sub backend (default: pulsar, env: PUBSUB_BACKEND)' + ) + + # Pulsar-specific configuration + parser.add_argument( + '--pulsar-host', + default=os.getenv('PULSAR_HOST', 'pulsar://localhost:6650'), + help='Pulsar host (default: pulsar://localhost:6650, env: PULSAR_HOST)' + ) + + parser.add_argument( + '--pulsar-api-key', + default=os.getenv('PULSAR_API_KEY', None), + help='Pulsar API key (env: PULSAR_API_KEY)' + ) + + parser.add_argument( + '--pulsar-listener', + default=os.getenv('PULSAR_LISTENER', None), + help='Pulsar listener name (env: PULSAR_LISTENER)' + ) + + # MQTT-specific configuration + parser.add_argument( + '--mqtt-host', + default=os.getenv('MQTT_HOST', 'localhost'), + help='MQTT broker host (default: localhost, env: MQTT_HOST)' + ) + + parser.add_argument( + '--mqtt-port', + type=int, + default=int(os.getenv('MQTT_PORT', '1883')), + help='MQTT broker port (default: 1883, env: MQTT_PORT)' + ) + + parser.add_argument( + '--mqtt-username', + default=os.getenv('MQTT_USERNAME', None), + help='MQTT username (env: MQTT_USERNAME)' + ) + + parser.add_argument( + '--mqtt-password', + default=os.getenv('MQTT_PASSWORD', None), + help='MQTT password (env: MQTT_PASSWORD)' + ) +``` + +**Función de Fábrica:** + +```python +# In base/pubsub.py or base/pubsub_factory.py +def get_pubsub(**config) -> PubSubBackend: + """ + Create and return a pub/sub backend based on configuration. + + Args: + config: Configuration dict from command-line args + Must include 'pubsub_backend' key + + Returns: + Backend instance (PulsarBackend, MQTTBackend, etc.) + """ + backend_type = config.get('pubsub_backend', 'pulsar') + + if backend_type == 'pulsar': + return PulsarBackend( + host=config.get('pulsar_host'), + api_key=config.get('pulsar_api_key'), + listener=config.get('pulsar_listener'), + ) + elif backend_type == 'mqtt': + return MQTTBackend( + host=config.get('mqtt_host'), + port=config.get('mqtt_port'), + username=config.get('mqtt_username'), + password=config.get('mqtt_password'), + ) + else: + raise ValueError(f"Unknown pub/sub backend: {backend_type}") +``` + +**Uso en AsyncProcessor:** + +```python +# In async_processor.py +class AsyncProcessor: + def __init__(self, **params): + self.id = params.get("id") + + # Create backend from config (replaces PulsarClient) + self.pubsub = get_pubsub(**params) + + # Rest of initialization... +``` + +### Interfaz de Backend + +```python +class PubSubBackend(Protocol): + """Protocol defining the interface all pub/sub backends must implement.""" + + def create_producer(self, topic: str, schema: type, **options) -> BackendProducer: + """ + Create a producer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + schema: Dataclass type for messages + options: Backend-specific options (e.g., chunking_enabled) + + Returns: + Backend-specific producer instance + """ + ... + + def create_consumer( + self, + topic: str, + subscription: str, + schema: type, + initial_position: str = 'latest', + consumer_type: str = 'shared', + **options + ) -> BackendConsumer: + """ + Create a consumer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + subscription: Subscription/consumer group name + schema: Dataclass type for messages + initial_position: 'earliest' or 'latest' (MQTT may ignore) + consumer_type: 'shared', 'exclusive', 'failover' (MQTT may ignore) + options: Backend-specific options + + Returns: + Backend-specific consumer instance + """ + ... + + def close(self) -> None: + """Close the backend connection.""" + ... +``` + +```python +class BackendProducer(Protocol): + """Protocol for backend-specific producer.""" + + def send(self, message: Any, properties: dict = {}) -> None: + """Send a message (dataclass instance) with optional properties.""" + ... + + def flush(self) -> None: + """Flush any buffered messages.""" + ... + + def close(self) -> None: + """Close the producer.""" + ... +``` + +```python +class BackendConsumer(Protocol): + """Protocol for backend-specific consumer.""" + + def receive(self, timeout_millis: int = 2000) -> Message: + """ + Receive a message from the topic. + + Raises: + TimeoutError: If no message received within timeout + """ + ... + + def acknowledge(self, message: Message) -> None: + """Acknowledge successful processing of a message.""" + ... + + def negative_acknowledge(self, message: Message) -> None: + """Negative acknowledge - triggers redelivery.""" + ... + + def unsubscribe(self) -> None: + """Unsubscribe from the topic.""" + ... + + def close(self) -> None: + """Close the consumer.""" + ... +``` + +```python +class Message(Protocol): + """Protocol for a received message.""" + + def value(self) -> Any: + """Get the deserialized message (dataclass instance).""" + ... + + def properties(self) -> dict: + """Get message properties/metadata.""" + ... +``` + +### Refactorización de Clases Existentes + +Las clases existentes `Consumer`, `Producer`, `Publisher`, `Subscriber` permanecen en gran medida intactas: + +**Responsabilidades actuales (mantener):** +Modelo de subprocesos asíncronos y grupos de tareas +Lógica de reconexión y manejo de reintentos +Recopilación de métricas +Limitación de velocidad +Gestión de la concurrencia + +**Cambios necesarios:** +Eliminar importaciones directas de Pulsar (`pulsar.schema`, `pulsar.InitialPosition`, etc.) +Aceptar `BackendProducer`/`BackendConsumer` en lugar del cliente de Pulsar +Delegar las operaciones de publicación/suscripción reales a instancias de backend +Mapear conceptos genéricos a llamadas de backend + +**Ejemplo de refactorización:** + +```python +# OLD - consumer.py +class Consumer: + def __init__(self, client, topic, subscriber, schema, ...): + self.client = client # Direct Pulsar client + # ... + + async def consumer_run(self): + # Uses pulsar.InitialPosition, pulsar.ConsumerType + self.consumer = self.client.subscribe( + topic=self.topic, + schema=JsonSchema(self.schema), + initial_position=pulsar.InitialPosition.Earliest, + consumer_type=pulsar.ConsumerType.Shared, + ) + +# NEW - consumer.py +class Consumer: + def __init__(self, backend_consumer, schema, ...): + self.backend_consumer = backend_consumer # Backend-specific consumer + self.schema = schema + # ... + + async def consumer_run(self): + # Backend consumer already created with right settings + # Just use it directly + while self.running: + msg = await asyncio.to_thread( + self.backend_consumer.receive, + timeout_millis=2000 + ) + await self.handle_message(msg) +``` + +### Comportamientos Específicos del Backend + +**Backend de Pulsar:** +Mapea `q0` → `non-persistent://`, `q1`/`q2` → `persistent://` +Soporta todos los tipos de consumidores (compartido, exclusivo, de respaldo) +Soporta la posición inicial (earliest/latest) +Reconocimiento nativo de mensajes +Soporte para el registro de esquemas + +**Backend de MQTT:** +Mapea `q0`/`q1`/`q2` → Niveles de QoS de MQTT 0/1/2 +Incluye el inquilino/espacio de nombres en la ruta del tema para el espaciado de nombres +Genera automáticamente ID de cliente a partir de los nombres de suscripción +Ignora la posición inicial (no hay historial de mensajes en MQTT básico) +Ignora el tipo de consumidor (MQTT utiliza ID de cliente, no grupos de consumidores) +Modelo de publicación/suscripción simple + +### Resumen de Decisiones de Diseño + +1. ✅ **Nombres de cola genéricos**: Formato `qos/tenant/namespace/queue-name` +2. ✅ **QoS en el ID de la cola**: Determinado por la definición de la cola, no por la configuración +3. ✅ **Reconexión**: Manejada por las clases Consumer/Producer, no por los backends +4. ✅ **Temas de MQTT**: Incluir inquilino/espacio de nombres para un espaciado de nombres adecuado +5. ✅ **Historial de mensajes**: MQTT ignora el parámetro `initial_position` (mejora futura) +6. ✅ **ID de cliente**: El backend de MQTT genera automáticamente a partir del nombre de la suscripción + +### Mejoras Futuras + +**Historial de mensajes de MQTT:** +Se podría agregar una capa de persistencia opcional (por ejemplo, mensajes retenidos, almacenamiento externo) +Permitiría soportar `initial_position='earliest'` +No es necesario para la implementación inicial + diff --git a/docs/tech-specs/pubsub.he.md b/docs/tech-specs/pubsub.he.md new file mode 100644 index 00000000..379b601c --- /dev/null +++ b/docs/tech-specs/pubsub.he.md @@ -0,0 +1,958 @@ +# תשתית Pub/Sub + +## סקירה כללית + +מסמך זה מפרט את כל החיבורים בין בסיס הקוד של TrustGraph לתשתית ה-pub/sub. כיום, המערכת מקודדת בצורה קבועה לשימוש ב-Apache Pulsar. ניתוח זה מזהה את כל נקודות האינטגרציה כדי ליידע שינויים עתידיים לכיוון הפשטה של pub/sub הניתנת לתצורה. + +## מצב נוכחי: נקודות אינטגרציה של Pulsar + +### 1. שימוש ישיר בלקוח Pulsar + +**מיקום:** `trustgraph-flow/trustgraph/gateway/service.py` + +שער ה-API מייבא ויוצר ישירות את לקוח ה-Pulsar: + +**שורה 20:** `import pulsar` +**שורות 54-61:** יצירה ישירה של `pulsar.Client()` עם `pulsar.AuthenticationToken()` אופציונלי +**שורות 33-35:** תצורת מארח ברירת מחדל של Pulsar ממשתני סביבה +**שורות 178-192:** ארגומנטים של שורת הפקודה עבור `--pulsar-host`, `--pulsar-api-key` ו-`--pulsar-listener` +**שורות 78, 124:** מעביר `pulsar_client` ל-`ConfigReceiver` ו-`DispatcherManager` + +זה המיקום היחיד שבו נוצר ישירות לקוח Pulsar מחוץ לשכבת ההפשטה. + +### 2. מסגרת מעבד בסיסית + +**מיקום:** `trustgraph-base/trustgraph/base/async_processor.py` + +המחלקה הבסיסית לכל המעבדים מספקת קישוריות ל-Pulsar: + +**שורה 9:** `import _pulsar` (לטיפול בחריגים) +**שורה 18:** `from . pubsub import PulsarClient` +**שורה 38:** יוצר `pulsar_client_object = PulsarClient(**params)` +**שורות 104-108:** מאפיינים החושפים `pulsar_host` ו-`pulsar_client` +**שורה 250:** שיטה סטטית `add_args()` קוראת ל-`PulsarClient.add_args(parser)` עבור ארגומנטים של שורת הפקודה +**שורות 223-225:** טיפול בחריגים עבור `_pulsar.Interrupted` + +כל המעבדים יורשים מ-`AsyncProcessor`, מה שהופך זאת לנקודת האינטגרציה המרכזית. + +### 3. הפשטת צרכן + +**מיקום:** `trustgraph-base/trustgraph/base/consumer.py` + +צורך הודעות מתורים ומפעיל פונקציות מטפלות: + +**ייבוא של Pulsar:** +**שורה 12:** `from pulsar.schema import JsonSchema` +**שורה 13:** `import pulsar` +**שורה 14:** `import _pulsar` + +**שימוש ספציפי ל-Pulsar:** +**שורות 100, 102:** `pulsar.InitialPosition.Earliest` / `pulsar.InitialPosition.Latest` +**שורה 108:** עטיפה של `JsonSchema(self.schema)` +**שורה 110:** `pulsar.ConsumerType.Shared` +**שורות 104-111:** `self.client.subscribe()` עם פרמטרים ספציפיים ל-Pulsar +**שורות 143, 150, 65:** שיטות `consumer.unsubscribe()` ו-`consumer.close()` +**שורה 162:** חריגה של `_pulsar.Timeout` +**שורות 182, 205, 232:** `consumer.acknowledge()` / `consumer.negative_acknowledge()` + +**קובץ מפרט:** `trustgraph-base/trustgraph/base/consumer_spec.py` +**שורה 22:** מפנה ל-`processor.pulsar_client` + +### 4. הפשטת מפרסם + +**מיקום:** `trustgraph-base/trustgraph/base/producer.py` + +שולח הודעות לתורים: + +**ייבוא של Pulsar:** +**שורה 2:** `from pulsar.schema import JsonSchema` + +**שימוש ספציפי ל-Pulsar:** +**שורה 49:** עטיפה של `JsonSchema(self.schema)` +**שורות 47-51:** `self.client.create_producer()` עם פרמטרים ספציפיים ל-Pulsar (נושא, סכימה, הפעלה של חלוקה לחלקים) +**שורות 31, 76:** שיטה `producer.close()` +**שורות 64-65:** `producer.send()` עם הודעה ומאפיינים + +**קובץ מפרט:** `trustgraph-base/trustgraph/base/producer_spec.py` +**שורה 18:** מפנה ל-`processor.pulsar_client` + +### 5. הפשטת מפרסם + +**מיקום:** `trustgraph-base/trustgraph/base/publisher.py` + +פרסום הודעות אסינכרוני עם חיץ תורים: + +**ייבוא של Pulsar:** +**שורה 2:** `from pulsar.schema import JsonSchema` +**שורה 6:** `import pulsar` + +**שימוש ספציפי ל-Pulsar:** +**שורה 52:** עטיפה של `JsonSchema(self.schema)` +**שורות 50-54:** `self.client.create_producer()` עם פרמטרים ספציפיים ל-Pulsar +**שורות 101, 103:** `producer.send()` עם הודעה ומאפיינים אופציונליים +**שורות 106-107:** שיטות `producer.flush()` ו-`producer.close()` + +### 6. הפשטת מנוי + +**מיקום:** `trustgraph-base/trustgraph/base/subscriber.py` + +מספק הפצת הודעות למספר נמענים ממחזורים: + +**ייבוא מ-Pulsar:** +**שורה 6:** `from pulsar.schema import JsonSchema` +**שורה 8:** `import _pulsar` + +**שימוש ספציפי ל-Pulsar:** +**שורה 55:** `JsonSchema(self.schema)` wrapper +**שורה 57:** `self.client.subscribe(**subscribe_args)` +**שורות 101, 136, 160, 167-172:** חריגות של Pulsar: `_pulsar.Timeout`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +**שורות 159, 166, 170:** שיטות צרכן: `negative_acknowledge()`, `unsubscribe()`, `close()` +**שורות 247, 251:** אישור הודעות: `acknowledge()`, `negative_acknowledge()` + +**קובץ מפרט:** `trustgraph-base/trustgraph/base/subscriber_spec.py` +**שורה 19:** מפנה ל-`processor.pulsar_client` + +### 7. מערכת סכימות (Heart of Darkness) + +**מיקום:** `trustgraph-base/trustgraph/schema/` + +כל סכימת הודעה במערכת מוגדרת באמצעות מסגרת הסכימות של Pulsar. + +**אלמנטים בסיסיים:** `schema/core/primitives.py` +**שורה 2:** `from pulsar.schema import Record, String, Boolean, Array, Integer` +כל הסכימות יורשות מהמחלקה הבסיסית של Pulsar `Record` +כל סוגי השדות הם סוגי Pulsar: `String()`, `Integer()`, `Boolean()`, `Array()`, `Map()`, `Double()` + +**דוגמאות לסכימות:** +`schema/services/llm.py` (שורה 2): `from pulsar.schema import Record, String, Array, Double, Integer, Boolean` +`schema/services/config.py` (שורה 2): `from pulsar.schema import Record, Bytes, String, Boolean, Array, Map, Integer` + +**שמות נושאים:** `schema/core/topic.py` +**שורות 2-3:** פורמט נושא: `{kind}://{tenant}/{namespace}/{topic}` +מבנה ה-URI הזה ספציפי ל-Pulsar (לדוגמה, `persistent://tg/flow/config`) + +**השפעה:** +כל הגדרות הודעות בקשות/תגובות בכל בסיס הקוד משתמשות בסכימות של Pulsar +זה כולל שירותים עבור: config, flow, llm, prompt, query, storage, agent, collection, diagnosis, library, lookup, nlp_query, objects_query, retrieval, structured_query +הגדרות סכימות מיובאות ומשמשות באופן נרחב בכל המעבדים והשירותים + +## סיכום + +### תלויות של Pulsar לפי קטגוריה + +1. **יצירת מופע לקוח:** + ישיר: `gateway/service.py` + מופשט: `async_processor.py` → `pubsub.py` (PulsarClient) + +2. **העברת הודעות:** + צרכן: `consumer.py`, `consumer_spec.py` + מפיק: `producer.py`, `producer_spec.py` + מפרסם: `publisher.py` + מנוי: `subscriber.py`, `subscriber_spec.py` + +3. **מערכת סכימות:** + סוגים בסיסיים: `schema/core/primitives.py` + כל סכימות השירות: `schema/services/*.py` + שמות נושאים: `schema/core/topic.py` + +4. **מושגים ספציפיים ל-Pulsar הנדרשים:** + העברת הודעות מבוססת נושאים + מערכת סכימות (Record, סוגי שדות) + מנויים משותפים + אישור הודעות (חיובי/שלילי) + מיקום צרכן (מוקדם/מאוחר) + מאפייני הודעות + מיקומים התחלתיים וסוגי צרכנים + תמיכה בפיצול + נושאים קבועים לעומת לא קבועים + +### אתגרי שינוי מבנה + +החדשות הטובות: שכבת ההפשטה (צרכן, מפיק, מפרסם, מנוי) מספקת אריזה נקייה של רוב האינטראקציות של Pulsar. + +האתגרים: +1. **הנחת סכימות נרחבת:** כל הגדרת הודעה משתמשת ב-`pulsar.schema.Record` ובסוגי Pulsar +2. **אנונימים ספציפיים ל-Pulsar:** `InitialPosition`, `ConsumerType` +3. **חריגות של Pulsar:** `_pulsar.Timeout`, `_pulsar.Interrupted`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +4. **חתימות שיטות:** `acknowledge()`, `negative_acknowledge()`, `subscribe()`, `create_producer()`, וכו'. +5. **פורמט URI של נושא:** מבנה `kind://tenant/namespace/topic` של Pulsar + +### שלבים הבאים + +כדי להפוך את התשתית של pub/sub לכזו שניתן להגדיר, עלינו: + +1. ליצור ממשק הפשטה עבור מערכת הלקוח/סכימות +2. להפשיט אנונימים ספציפיים ל-Pulsar וחריגות +3. ליצור עטיפות סכימות או הגדרות סכימות חלופיות +4. ליישם את הממשק הן עבור Pulsar והן עבור מערכות חלופיות (Kafka, RabbitMQ, Redis Streams, וכו') +5. לעדכן את `pubsub.py` כך שניתן יהיה להגדיר אותו ולתמוך במספר מערכות אחוריות +6. לספק נתיב מעבר לפריסות קיימות + +## טיוטת גישה 1: תבנית מתאם עם שכבת תרגום סכימות + +### הערה + + +### אסטרטגיה: הפרעה מינימלית באמצעות מתאמים + +**1. שמירה על סכימות Pulsar כייצוג הפנימי** +אין לשכתב את כל הגדרות הסכימות. +הסכימות נשארות `pulsar.schema.Record` באופן פנימי. +השתמשו במתאמים כדי לתרגם בגבול בין הקוד שלנו לבין ה-backend של ה-pub/sub. + +**2. יצירת שכבת הפשטה עבור pub/sub:** + +``` +┌─────────────────────────────────────┐ +│ Existing Code (unchanged) │ +│ - Uses Pulsar schemas internally │ +│ - Consumer/Producer/Publisher │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - Creates backend-specific client │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────┐ ┌────▼─────────┐ +│ PulsarAdapter│ │ KafkaAdapter │ etc... +│ (passthrough)│ │ (translates) │ +└──────────────┘ └──────────────┘ +``` + +**3. הגדרת ממשקים מופשטים:** +`PubSubClient` - חיבור לקוח +`PubSubProducer` - שליחת הודעות +`PubSubConsumer` - קבלת הודעות +`SchemaAdapter` - המרת סכימות Pulsar ל-JSON או פורמטים ספציפיים ל-backend + +**4. פרטי יישום:** + +עבור **מתאם Pulsar**: כמעט העברה ישירה, המרה מינימלית + +עבור **backends אחרים** (Kafka, RabbitMQ, וכו'): +סריאליזציה של אובייקטי Pulsar Record ל-JSON/bytes +מיפוי מושגים כמו: + `InitialPosition.Earliest/Latest` → auto.offset.reset של Kafka + `acknowledge()` → commit של Kafka + `negative_acknowledge()` → תבנית Re-queue או DLQ + URIs של נושאים → שמות נושאים ספציפיים ל-backend + +### ניתוח + +**יתרונות:** +✅ שינויים מינימליים בקוד של שירותים קיימים +✅ הסכימות נשארות כפי שהן (ללא כתיבה מחדש מסיבית) +✅ מסלול מעבר הדרגתי +✅ משתמשי Pulsar לא רואים הבדל +✅ backends חדשים מתווספים באמצעות מתאמים + +**חסרונות:** +⚠️ עדיין כולל תלות ב-Pulsar (לצרכי הגדרות סכימה) +⚠️ חוסר התאמה מסוים בהמרת מושגים + +### שיקול חלופי + +ליצור **מערכת סכימות TrustGraph** שאינה תלויה ב-pub/sub ספציפי (תוך שימוש ב-dataclasses או Pydantic), ולאחר מכן ליצור סכימות Pulsar/Kafka/וכו מתוך זה. זה דורש כתיבה מחדש של כל קובץ סכימה ועלול לגרום לשינויים משמעותיים. + +### המלצה עבור טיוטה 1 + +להתחיל עם **גישת המתאם** מכיוון ש: +1. זה פרגמטי - עובד עם קוד קיים +2. מוכיח את הקונספט עם סיכון מינימלי +3. ניתן להתפתח למערכת סכימה מקומית יותר בעתיד אם יש צורך +4. מונחה תצורה: משתנה סביבה אחד משנה את ה-backends + +## גישה טיוטה 2: מערכת סכימות עצמאית מ-backend באמצעות Dataclasses + +### מושג מרכזי + +להשתמש ב-**dataclasses** של Python כפורמט הגדרת סכימה ניטרלי. כל backend של pub/sub מספק את הסריאליזציה/דה-סריאליזציה שלו עבור dataclasses, מה שמבטל את הצורך לשמור על סכימות Pulsar בקוד הבסיס. + +### פולימורפיזם של סכימה ברמת המפעל + +במקום להמיר סכימות Pulsar, **כל backend מספק את הטיפול שלו בסכימות** שעובד עם dataclasses סטנדרטיים של Python. + +### זרימת פרסום + +```python +# 1. Get the configured backend from factory +pubsub = get_pubsub() # Returns PulsarBackend, MQTTBackend, etc. + +# 2. Get schema class from the backend +# (Can be imported directly - backend-agnostic) +from trustgraph.schema.services.llm import TextCompletionRequest + +# 3. Create a producer/publisher for a specific topic +producer = pubsub.create_producer( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend what schema to use +) + +# 4. Create message instances (same API regardless of backend) +request = TextCompletionRequest( + system="You are helpful", + prompt="Hello world", + streaming=False +) + +# 5. Send the message +producer.send(request) # Backend serializes appropriately +``` + +### זרימת לקוח + +```python +# 1. Get the configured backend +pubsub = get_pubsub() + +# 2. Create a consumer +consumer = pubsub.subscribe( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend how to deserialize +) + +# 3. Receive and deserialize +msg = consumer.receive() +request = msg.value() # Returns TextCompletionRequest dataclass instance + +# 4. Use the data (type-safe access) +print(request.system) # "You are helpful" +print(request.prompt) # "Hello world" +print(request.streaming) # False +``` + +### מה קורה מאחורי הקלעים + +**עבור ה-backend של Pulsar:** +`create_producer()` → יוצר יצרן Pulsar עם סכימה JSON או רשומה שנוצרה באופן דינמי +`send(request)` → ממיר את מחלקת הנתונים לפורמט JSON/Pulsar, שולח ל-Pulsar +`receive()` → מקבל הודעת Pulsar, ממיר חזרה למחלקת נתונים + +**עבור ה-backend של MQTT:** +`create_producer()` → מתחבר ל-MQTT broker, אין צורך ברישום סכימה +`send(request)` → ממיר מחלקת נתונים ל-JSON, מפרסם לנושא MQTT +`receive()` → נרשם לנושא MQTT, ממיר JSON למחלקת נתונים + +**עבור ה-backend של Kafka:** +`create_producer()` → יוצר יצרן Kafka, רושם סכימת Avro במידת הצורך +`send(request)` → ממיר מחלקת נתונים לפורמט Avro, שולח ל-Kafka +`receive()` → מקבל הודעת Kafka, ממיר Avro חזרה למחלקת נתונים + +### נקודות עיצוב מרכזיות + +1. **יצירת אובייקט סכימה**: מופע מחלקת הנתונים (`TextCompletionRequest(...)`) זהה ללא קשר ל-backend +2. **ה-backend מטפל בקידוד**: כל backend יודע כיצד לתרגם את מחלקת הנתונים לפורמט הנתונים +3. **הגדרת סכימה ביצירה**: בעת יצירת יצרן/צרכן, מציינים את סוג הסכימה +4. **שמירה על בטיחות טיפוסים**: מקבלים בחזרה אובייקט `TextCompletionRequest` תקין, ולא מילון +5. **ללא חשיפה ל-backend**: קוד האפליקציה לעולם לא מייבא ספריות ספציפיות ל-backend + +### דוגמה לטרנספורמציה + +**נוכחי (ספציפי ל-Pulsar):** +```python +# schema/services/llm.py +from pulsar.schema import Record, String, Boolean, Integer + +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() +``` + +**חדש (בלתי תלוי בטכנולוגיית השרת):** +```python +# schema/services/llm.py +from dataclasses import dataclass + +@dataclass +class TextCompletionRequest: + system: str + prompt: str + streaming: bool = False +``` + +### אינטגרציה עם השרת האחורי + +כל שרת אחורי מטפל בסריאליזציה/דה-סריאליזציה של מחלקות נתונים: + +**שרת אחורי של Pulsar:** +יצירת מחלקות `pulsar.schema.Record` באופן דינמי ממחלקות נתונים +או סריאליזציה של מחלקות נתונים ל-JSON ושימוש בסכימה של JSON של Pulsar +שומר על תאימות לפריסות Pulsar קיימות + +**שרת אחורי של MQTT/Redis:** +סריאליזציה ישירה של מופעים של מחלקות נתונים ל-JSON +שימוש ב-`dataclasses.asdict()` / `from_dict()` +קל משקל, לא נדרש רישום סכימות + +**שרת אחורי של Kafka:** +יצירת סכימות Avro מהגדרות של מחלקות נתונים +שימוש ברישום סכימות של Confluent +סריאליזציה בטוחה עם תמיכה באבולוציה של סכימות + +### ארכיטקטורה + +``` +┌─────────────────────────────────────┐ +│ Application Code │ +│ - Uses dataclass schemas │ +│ - Backend-agnostic │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - get_pubsub() returns backend │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────────┐ ┌────▼──────────────┐ +│ PulsarBackend │ │ MQTTBackend │ +│ - JSON schema │ │ - JSON serialize │ +│ - or dynamic │ │ - Simple queues │ +│ Record gen │ │ │ +└─────────────────┘ └───────────────────┘ +``` + +### פרטי יישום + +**1. הגדרות סכימה:** מחלקות נתונים פשוטות עם רמזי סוג + `str`, `int`, `bool`, `float` עבור ערכים בסיסיים + `list[T]` עבור מערכים + `dict[str, T]` עבור מפות + מחלקות נתונים מקוננות עבור סוגים מורכבים + +**2. כל ממשק מספק:** + ממיר: `dataclass → bytes/wire format` + ממיר הפוך: `bytes/wire format → dataclass` + רישום סכימה (אם נדרש, כמו Pulsar/Kafka) + +**3. הפשטה של צרכן/משדר:** + כבר קיים (consumer.py, producer.py) + עדכון לשימוש בשימוש בשידור של הממשק + הסרת יבוא ישיר של Pulsar + +**4. התאמות סוג:** + Pulsar `String()` → Python `str` + Pulsar `Integer()` → Python `int` + Pulsar `Boolean()` → Python `bool` + Pulsar `Array(T)` → Python `list[T]` + Pulsar `Map(K, V)` → Python `dict[K, V]` + Pulsar `Double()` → Python `float` + Pulsar `Bytes()` → Python `bytes` + +### נתיב מעבר + +1. **צור גרסאות של מחלקות נתונים** עבור כל הסכימות ב-`trustgraph/schema/` +2. **עדכן מחלקות ממשק** (צרכן, משדר, מפרסם, מנוי) לשימוש בשידור שמסופק על ידי הממשק +3. **יישם PulsarBackend** עם סכימה ב-JSON או יצירת רשומות דינמית +4. **בדוק עם Pulsar** כדי להבטיח תאימות לאחור עם פריסות קיימות +5. **הוסף ממשקים חדשים** (MQTT, Kafka, Redis, וכו') לפי הצורך +6. **הסר יבוא של Pulsar** מקבצי סכימה + +### יתרונות + +✅ **ללא תלות ב-pub/sub** בהגדרות סכימה +✅ **Python סטנדרטי** - קל להבנה, בדיקת סוגים, תיעוד +✅ **כלים מודרניים** - עובד עם mypy, השלמה אוטומטית של IDE, כלי ניתוח +✅ **מותאם לממשק** - כל ממשק משתמש בשידור מקומי +✅ **ללא תקורה של תרגום** - שידור ישיר, ללא מתאמים +✅ **בטיחות סוג** - אובייקטים אמיתיים עם סוגים מתאימים +✅ **אימות קל** - ניתן להשתמש ב-Pydantic אם נדרש + +### אתגרים ופתרונות + +**אתגר:** ל-Pulsar יש `Record` עם אימות שדה בזמן ריצה +**פתרון:** השתמש במחלקות נתונים של Pydantic לאימות אם נדרש, או בתכונות של מחלקת נתונים של Python 3.10+ עם `__post_init__` + +**אתגר:** תכונות ספציפיות של Pulsar (כמו סוג `Bytes`) +**פתרון:** התאם לסוג `bytes` במחלקת נתונים, הממשק מטפל בקידוד המתאים + +**אתגר:** שמות נושא (`persistent://tenant/namespace/topic`) +**פתרון:** הפשט שמות נושא בהגדרות סכימה, הממשק ממיר לפורמט המתאים + +**אתגר:** אבולוציה וגרסאות של סכימה +**פתרון:** כל ממשק מטפל בכך בהתאם ליכולות שלו (גרסאות סכימה של Pulsar, רישום סכימה של Kafka, וכו') + +**אתגר:** סוגים מורכבים מקוננים +**פתרון:** השתמש במחלקות נתונים מקוננות, הממשקים מבצעים שידור/פענוח רקורסיבי + +### החלטות עיצוב + +1. **מחלקות נתונים פשוטות או Pydantic?** + ✅ **החלטה: השתמש במחלקות נתונים של Python פשוטות** + פשוט יותר, ללא תלויות נוספות + אימות אינו נדרש בפועל + קל יותר להבנה ולתחזוקה + +2. **אבולוציה של סכימה:** + ✅ **החלטה: לא נדרש מנגנון גרסאות** + הסכימות יציבות וקיימות לאורך זמן + עדכונים בדרך כלל מוסיפים שדות חדשים (תואמים לאחור) + ממשקים מטפלים באבולוציה של סכימה בהתאם ליכולות שלהם + +3. **תאימות לאחור:** + ✅ **החלטה: שינוי גרסה עיקרית, תאימות לאחור אינה נדרשת** + יהיה שינוי משמעותי עם הוראות מעבר + ניתוק נקי מאפשר עיצוב טוב יותר + מדריך מעבר יסופק עבור פריסות קיימות + +4. **סוגים מקוננים ומבנים מורכבים:** + ✅ **החלטה: השתמש במחלקות נתונים מקוננות באופן טבעי** + מחלקות נתונים של Python מטפלות בקינון בצורה מושלמת + `list[T]` עבור מערכים, `dict[K, V]` עבור מפות + ממשקים מבצעים שידור/פענוח רקורסיבי + דוגמה: + ```python + @dataclass + class Value: + value: str + is_uri: bool + + @dataclass + class Triple: + s: Value # Nested dataclass + p: Value + o: Value + + @dataclass + class GraphQuery: + triples: list[Triple] # Array of nested dataclasses + metadata: dict[str, str] + ``` + +5. **ערכים ברירת מחדל ושדות אופציונליים:** + ✅ **החלטה: שילוב של שדות חובה, ערכי ברירת מחדל ושדות אופציונליים** + שדות חובה: ללא ערך ברירת מחדל + שדות עם ערכי ברירת מחדל: תמיד נוכחים, בעלי ערך ברירת מחדל הגיוני + שדות אופציונליים לחלוטין: `T | None = None`, מושמטים מסריאליזציה כאשר `None` + דוגמה: + ```python + @dataclass + class TextCompletionRequest: + system: str # Required, no default + prompt: str # Required, no default + streaming: bool = False # Optional with default value + metadata: dict | None = None # Truly optional, can be absent + ``` + + **סמנטיקה חשובה של סריאליזציה:** + + כאשר `metadata = None`: + ```json + { + "system": "...", + "prompt": "...", + "streaming": false + // metadata field NOT PRESENT + } + ``` + + כאשר `metadata = {}` (ריק במפורש): + ```json + { + "system": "...", + "prompt": "...", + "streaming": false, + "metadata": {} // Field PRESENT but empty + } + ``` + + **ההבחנה העיקרית:** + `None` → שדה שאינו קיים ב-JSON (לא מיוצא) + ערך ריק (`{}`, `[]`, `""`) → שדה קיים עם ערך ריק + זה חשוב מבחינה סמנטית: "לא סופק" לעומת "ריק באופן מפורש" + מערכות הקידוד חייבות לדלג על שדות `None`, ולא לקודד אותם כ-`null` + +## טיוטה 3 של הגישה: פרטי יישום + +### פורמט שם תור גנרי + +החליפו שמות תורים ספציפיים לכל מערכת קידוד בפורמט גנרי שמערכות הקידוד יכולות למפות בהתאם. + +**פורמט:** `{qos}/{tenant}/{namespace}/{queue-name}` + +כאשר: +`qos`: רמת שירות (Quality of Service) + `q0` = מאמץ מינימלי (שליחה ללא אישור) + `q1` = לפחות פעם אחת (דורש אישור) + `q2` = בדיוק פעם אחת (אישור בשני שלבים) +`tenant`: קיבוץ לוגי עבור ריבוי דיירים +`namespace`: תת-קיבוץ בתוך דייר +`queue-name`: שם התור/נושא בפועל + +**דוגמאות:** +``` +q1/tg/flow/text-completion-requests +q2/tg/config/config-push +q0/tg/metrics/stats +``` + +### מיפוי נושאים בצד השרת + +כל צד שרת ממפה את הפורמט הכללי לפורמט הייחודי שלו: + +**צד שרת Pulsar:** +```python +def map_topic(self, generic_topic: str) -> str: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS to persistence + persistence = 'persistent' if qos in ['q1', 'q2'] else 'non-persistent' + + # Return Pulsar URI: persistent://tg/flow/text-completion-requests + return f"{persistence}://{tenant}/{namespace}/{queue}" +``` + +**שרת MQTT:** +```python +def map_topic(self, generic_topic: str) -> tuple[str, int]: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS level + qos_level = {'q0': 0, 'q1': 1, 'q2': 2}[qos] + + # Build MQTT topic including tenant/namespace for proper namespacing + mqtt_topic = f"{tenant}/{namespace}/{queue}" + + return mqtt_topic, qos_level +``` + +### פונקציית עזר מעודכנת לנושא + +```python +# schema/core/topic.py +def topic(queue_name, qos='q1', tenant='tg', namespace='flow'): + """ + Create a generic topic identifier that can be mapped by backends. + + Args: + queue_name: The queue/topic name + qos: Quality of service + - 'q0' = best-effort (no ack) + - 'q1' = at-least-once (ack required) + - 'q2' = exactly-once (two-phase ack) + tenant: Tenant identifier for multi-tenancy + namespace: Namespace within tenant + + Returns: + Generic topic string: qos/tenant/namespace/queue_name + + Examples: + topic('my-queue') # q1/tg/flow/my-queue + topic('config', qos='q2', namespace='config') # q2/tg/config/config + """ + return f"{qos}/{tenant}/{namespace}/{queue_name}" +``` + +### הגדרות ואתחול + +**ארגומנטים של שורת הפקודה + משתני סביבה:** + +```python +# In base/async_processor.py - add_args() method +@staticmethod +def add_args(parser): + # Pub/sub backend selection + parser.add_argument( + '--pubsub-backend', + default=os.getenv('PUBSUB_BACKEND', 'pulsar'), + choices=['pulsar', 'mqtt'], + help='Pub/sub backend (default: pulsar, env: PUBSUB_BACKEND)' + ) + + # Pulsar-specific configuration + parser.add_argument( + '--pulsar-host', + default=os.getenv('PULSAR_HOST', 'pulsar://localhost:6650'), + help='Pulsar host (default: pulsar://localhost:6650, env: PULSAR_HOST)' + ) + + parser.add_argument( + '--pulsar-api-key', + default=os.getenv('PULSAR_API_KEY', None), + help='Pulsar API key (env: PULSAR_API_KEY)' + ) + + parser.add_argument( + '--pulsar-listener', + default=os.getenv('PULSAR_LISTENER', None), + help='Pulsar listener name (env: PULSAR_LISTENER)' + ) + + # MQTT-specific configuration + parser.add_argument( + '--mqtt-host', + default=os.getenv('MQTT_HOST', 'localhost'), + help='MQTT broker host (default: localhost, env: MQTT_HOST)' + ) + + parser.add_argument( + '--mqtt-port', + type=int, + default=int(os.getenv('MQTT_PORT', '1883')), + help='MQTT broker port (default: 1883, env: MQTT_PORT)' + ) + + parser.add_argument( + '--mqtt-username', + default=os.getenv('MQTT_USERNAME', None), + help='MQTT username (env: MQTT_USERNAME)' + ) + + parser.add_argument( + '--mqtt-password', + default=os.getenv('MQTT_PASSWORD', None), + help='MQTT password (env: MQTT_PASSWORD)' + ) +``` + +**פונקציית יצירה:** + +```python +# In base/pubsub.py or base/pubsub_factory.py +def get_pubsub(**config) -> PubSubBackend: + """ + Create and return a pub/sub backend based on configuration. + + Args: + config: Configuration dict from command-line args + Must include 'pubsub_backend' key + + Returns: + Backend instance (PulsarBackend, MQTTBackend, etc.) + """ + backend_type = config.get('pubsub_backend', 'pulsar') + + if backend_type == 'pulsar': + return PulsarBackend( + host=config.get('pulsar_host'), + api_key=config.get('pulsar_api_key'), + listener=config.get('pulsar_listener'), + ) + elif backend_type == 'mqtt': + return MQTTBackend( + host=config.get('mqtt_host'), + port=config.get('mqtt_port'), + username=config.get('mqtt_username'), + password=config.get('mqtt_password'), + ) + else: + raise ValueError(f"Unknown pub/sub backend: {backend_type}") +``` + +**שימוש ב-AsyncProcessor:** + +```python +# In async_processor.py +class AsyncProcessor: + def __init__(self, **params): + self.id = params.get("id") + + # Create backend from config (replaces PulsarClient) + self.pubsub = get_pubsub(**params) + + # Rest of initialization... +``` + +### ממשק צד שרת + +```python +class PubSubBackend(Protocol): + """Protocol defining the interface all pub/sub backends must implement.""" + + def create_producer(self, topic: str, schema: type, **options) -> BackendProducer: + """ + Create a producer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + schema: Dataclass type for messages + options: Backend-specific options (e.g., chunking_enabled) + + Returns: + Backend-specific producer instance + """ + ... + + def create_consumer( + self, + topic: str, + subscription: str, + schema: type, + initial_position: str = 'latest', + consumer_type: str = 'shared', + **options + ) -> BackendConsumer: + """ + Create a consumer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + subscription: Subscription/consumer group name + schema: Dataclass type for messages + initial_position: 'earliest' or 'latest' (MQTT may ignore) + consumer_type: 'shared', 'exclusive', 'failover' (MQTT may ignore) + options: Backend-specific options + + Returns: + Backend-specific consumer instance + """ + ... + + def close(self) -> None: + """Close the backend connection.""" + ... +``` + +```python +class BackendProducer(Protocol): + """Protocol for backend-specific producer.""" + + def send(self, message: Any, properties: dict = {}) -> None: + """Send a message (dataclass instance) with optional properties.""" + ... + + def flush(self) -> None: + """Flush any buffered messages.""" + ... + + def close(self) -> None: + """Close the producer.""" + ... +``` + +```python +class BackendConsumer(Protocol): + """Protocol for backend-specific consumer.""" + + def receive(self, timeout_millis: int = 2000) -> Message: + """ + Receive a message from the topic. + + Raises: + TimeoutError: If no message received within timeout + """ + ... + + def acknowledge(self, message: Message) -> None: + """Acknowledge successful processing of a message.""" + ... + + def negative_acknowledge(self, message: Message) -> None: + """Negative acknowledge - triggers redelivery.""" + ... + + def unsubscribe(self) -> None: + """Unsubscribe from the topic.""" + ... + + def close(self) -> None: + """Close the consumer.""" + ... +``` + +```python +class Message(Protocol): + """Protocol for a received message.""" + + def value(self) -> Any: + """Get the deserialized message (dataclass instance).""" + ... + + def properties(self) -> dict: + """Get message properties/metadata.""" + ... +``` + +### שינוי מבנה מחלקות קיימות + +המחלקות הקיימות `Consumer`, `Producer`, `Publisher`, `Subscriber` נשארות ברובן ללא שינוי: + +**אחריות נוכחית (לשמור):** +מודל תהליכים אסינכרוניים וקבוצות משימות +לוגיקת חיבור מחדש וטיפול בכישלונות +איסוף מדדים +הגבלת קצב +ניהול תחרות + +**שינויים נדרשים:** +הסרת יבוא ישיר של Pulsar (`pulsar.schema`, `pulsar.InitialPosition`, וכו') +קבלת `BackendProducer`/`BackendConsumer` במקום לקוח Pulsar +העברת פעולות פרסום/מנוי בפועל לאינסטנסים אחוריים +התאמת מושגים כלליים לפעולות אחוריות + +**דוגמה לשינוי מבנה:** + +```python +# OLD - consumer.py +class Consumer: + def __init__(self, client, topic, subscriber, schema, ...): + self.client = client # Direct Pulsar client + # ... + + async def consumer_run(self): + # Uses pulsar.InitialPosition, pulsar.ConsumerType + self.consumer = self.client.subscribe( + topic=self.topic, + schema=JsonSchema(self.schema), + initial_position=pulsar.InitialPosition.Earliest, + consumer_type=pulsar.ConsumerType.Shared, + ) + +# NEW - consumer.py +class Consumer: + def __init__(self, backend_consumer, schema, ...): + self.backend_consumer = backend_consumer # Backend-specific consumer + self.schema = schema + # ... + + async def consumer_run(self): + # Backend consumer already created with right settings + # Just use it directly + while self.running: + msg = await asyncio.to_thread( + self.backend_consumer.receive, + timeout_millis=2000 + ) + await self.handle_message(msg) +``` + +### התנהגויות ספציפיות לצד האחורי (Backend) + +**צד אחורי Pulsar:** +ממפה `q0` → `non-persistent://`, `q1`/`q2` → `persistent://` +תומך בכל סוגי הצרכנים (משותף, בלעדי, גיבוי) +תומך בעמדה התחלתית (הכי מוקדם/הכי מאוחר) +אישור הודעות מקורי +תמיכה ברישום סכימות + +**צד אחורי MQTT:** +ממפה `q0`/`q1`/`q2` → רמות QoS של MQTT 0/1/2 +כולל שוכר/מרחב שם בנתיב הנושא לצורך הפרדה +מייצר באופן אוטומטי מזהי לקוח משמות מנויים +מתעלם מעמדה התחלתית (אין היסטוריית הודעות ב-MQTT בסיסי) +מתעלם מסוג צרכן (MQTT משתמש במזהי לקוח, לא בקבוצות צרכנים) +מודל פרסום/מנוי פשוט + +### סיכום החלטות עיצוב + +1. ✅ **שמות תורים גנריים**: פורמט `qos/tenant/namespace/queue-name` +2. ✅ **רמת QoS במזהה תור**: נקבעת על ידי הגדרת התור, ולא על ידי תצורה +3. ✅ **חיבור מחדש**: מטופל על ידי מחלקות צרכן/מפיק, ולא על ידי הצד האחורי +4. ✅ **נושאים של MQTT**: כוללים שוכר/מרחב שם לצורך הפרדה תקינה +5. ✅ **היסטוריית הודעות**: MQTT מתעלם מהפרמטר `initial_position` (שיפור עתידי) +6. ✅ **מזהי לקוח**: צד אחורי MQTT מייצר באופן אוטומטי משם מנוי + +### שיפורים עתידיים + +**היסטוריית הודעות של MQTT:** +ניתן להוסיף שכבת שמירה אופציונלית (לדוגמה, הודעות שמורות, אחסון חיצוני) +יאפשר תמיכה ב-`initial_position='earliest'` +לא נדרש ליישום ראשוני + diff --git a/docs/tech-specs/pubsub.hi.md b/docs/tech-specs/pubsub.hi.md new file mode 100644 index 00000000..2d52cb32 --- /dev/null +++ b/docs/tech-specs/pubsub.hi.md @@ -0,0 +1,958 @@ +# पब/सब इंफ्रास्ट्रक्चर + +## अवलोकन + +यह दस्तावेज़ ट्रस्टग्राफ कोडबेस और पब/सब इंफ्रास्ट्रक्चर के बीच सभी कनेक्शनों को सूचीबद्ध करता है। वर्तमान में, सिस्टम को अपाचे पल्सर का उपयोग करने के लिए हार्डकोड किया गया है। यह विश्लेषण सभी एकीकरण बिंदुओं की पहचान करता है ताकि एक कॉन्फ़िगर करने योग्य पब/सब एब्स्ट्रैक्शन की ओर भविष्य के रीफैक्टरिंग को सूचित किया जा सके। + +## वर्तमान स्थिति: पल्सर एकीकरण बिंदु + +### 1. डायरेक्ट पल्सर क्लाइंट उपयोग + +**स्थान:** `trustgraph-flow/trustgraph/gateway/service.py` + +एपीआई गेटवे सीधे पल्सर क्लाइंट को आयात और इंस्टेंट करता है: + +**पंक्ति 20:** `import pulsar` +**पंक्तियाँ 54-61:** `pulsar.Client()` का प्रत्यक्ष इंस्टेंटेशन, वैकल्पिक `pulsar.AuthenticationToken()` के साथ +**पंक्तियाँ 33-35:** पर्यावरण चर से डिफ़ॉल्ट पल्सर होस्ट कॉन्फ़िगरेशन +**पंक्तियाँ 178-192:** `--pulsar-host`, `--pulsar-api-key` और `--pulsar-listener` के लिए CLI तर्क +**पंक्तियाँ 78, 124:** `pulsar_client` को `ConfigReceiver` और `DispatcherManager` को पास करता है + +यह एकमात्र स्थान है जहां पल्सर क्लाइंट को एब्स्ट्रैक्शन लेयर के बाहर सीधे इंस्टेंट किया गया है। + +### 2. बेस प्रोसेसर फ्रेमवर्क + +**स्थान:** `trustgraph-base/trustgraph/base/async_processor.py` + +सभी प्रोसेसर के लिए बेस क्लास पल्सर कनेक्टिविटी प्रदान करता है: + +**पंक्ति 9:** `import _pulsar` (अपवाद हैंडलिंग के लिए) +**पंक्ति 18:** `from . pubsub import PulsarClient` +**पंक्ति 38:** `pulsar_client_object = PulsarClient(**params)` बनाता है +**पंक्तियाँ 104-108:** गुण जो `pulsar_host` और `pulsar_client` को उजागर करते हैं +**पंक्ति 250:** स्थैतिक विधि `add_args()` CLI तर्कों के लिए `PulsarClient.add_args(parser)` को कॉल करता है +**पंक्तियाँ 223-225:** `_pulsar.Interrupted` के लिए अपवाद हैंडलिंग + +सभी प्रोसेसर `AsyncProcessor` से इनहेरिट करते हैं, जिससे यह केंद्रीय एकीकरण बिंदु बन जाता है। + +### 3. उपभोक्ता एब्स्ट्रैक्शन + +**स्थान:** `trustgraph-base/trustgraph/base/consumer.py` + +यह कतारों से संदेशों का उपभोग करता है और हैंडलर फ़ंक्शन को लागू करता है: + +**पल्सर आयात:** +**पंक्ति 12:** `from pulsar.schema import JsonSchema` +**पंक्ति 13:** `import pulsar` +**पंक्ति 14:** `import _pulsar` + +**पल्सर-विशिष्ट उपयोग:** +**पंक्तियाँ 100, 102:** `pulsar.InitialPosition.Earliest` / `pulsar.InitialPosition.Latest` +**पंक्ति 108:** `JsonSchema(self.schema)` रैपर +**पंक्ति 110:** `pulsar.ConsumerType.Shared` +**पंक्तियाँ 104-111:** पल्सर-विशिष्ट मापदंडों के साथ `self.client.subscribe()` +**पंक्तियाँ 143, 150, 65:** `consumer.unsubscribe()` और `consumer.close()` विधियाँ +**पंक्ति 162:** `_pulsar.Timeout` अपवाद +**पंक्तियाँ 182, 205, 232:** `consumer.acknowledge()` / `consumer.negative_acknowledge()` + +**स्पेक फ़ाइल:** `trustgraph-base/trustgraph/base/consumer_spec.py` +**पंक्ति 22:** `processor.pulsar_client` को संदर्भित करता है + +### 4. उत्पादक एब्स्ट्रैक्शन + +**स्थान:** `trustgraph-base/trustgraph/base/producer.py` + +यह कतारों में संदेश भेजता है: + +**पल्सर आयात:** +**पंक्ति 2:** `from pulsar.schema import JsonSchema` + +**पल्सर-विशिष्ट उपयोग:** +**पंक्ति 49:** `JsonSchema(self.schema)` रैपर +**पंक्तियाँ 47-51:** पल्सर-विशिष्ट मापदंडों (विषय, स्कीमा, चंकिंग_सक्षम) के साथ `self.client.create_producer()` +**पंक्तियाँ 31, 76:** `producer.close()` विधि +**पंक्तियाँ 64-65:** संदेश और गुणों के साथ `producer.send()` + +**स्पेक फ़ाइल:** `trustgraph-base/trustgraph/base/producer_spec.py` +**पंक्ति 18:** `processor.pulsar_client` को संदर्भित करता है + +### 5. प्रकाशक एब्स्ट्रैक्शन + +**स्थान:** `trustgraph-base/trustgraph/base/publisher.py` + +यह कतार बफरिंग के साथ एसिंक्रोनस संदेश प्रकाशन है: + +**पल्सर आयात:** +**पंक्ति 2:** `from pulsar.schema import JsonSchema` +**पंक्ति 6:** `import pulsar` + +**पल्सर-विशिष्ट उपयोग:** +**पंक्ति 52:** `JsonSchema(self.schema)` रैपर +**पंक्तियाँ 50-54:** पल्सर-विशिष्ट मापदंडों के साथ `self.client.create_producer()` +**पंक्तियाँ 101, 103:** संदेश और वैकल्पिक गुणों के साथ `producer.send()` +**पंक्तियाँ 106-107:** `producer.flush()` और `producer.close()` विधियाँ + +### 6. सब्सक्राइबर एब्स्ट्रैक्शन + +**स्थान:** `trustgraph-base/trustgraph/base/subscriber.py` + +यह क्यूज़ से मल्टी-रिसीवर मैसेज डिस्ट्रीब्यूशन प्रदान करता है: + +**पल्सर इम्पोर्ट्स:** +**लाइन 6:** `from pulsar.schema import JsonSchema` +**लाइन 8:** `import _pulsar` + +**पल्सर-विशिष्ट उपयोग:** +**लाइन 55:** `JsonSchema(self.schema)` रैपर +**लाइन 57:** `self.client.subscribe(**subscribe_args)` +**लाइनें 101, 136, 160, 167-172:** पल्सर अपवाद: `_pulsar.Timeout`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +**लाइनें 159, 166, 170:** उपभोक्ता विधियाँ: `negative_acknowledge()`, `unsubscribe()`, `close()` +**लाइनें 247, 251:** मैसेज स्वीकृति: `acknowledge()`, `negative_acknowledge()` + +**स्पेक फाइल:** `trustgraph-base/trustgraph/base/subscriber_spec.py` +**लाइन 19:** संदर्भ `processor.pulsar_client` + +### 7. स्कीमा सिस्टम (हार्ट ऑफ डार्कनेस) + +**स्थान:** `trustgraph-base/trustgraph/schema/` + +सिस्टम में हर मैसेज स्कीमा पल्सर के स्कीमा फ्रेमवर्क का उपयोग करके परिभाषित किया गया है। + +**कोर प्रिमिटिव्स:** `schema/core/primitives.py` +**लाइन 2:** `from pulsar.schema import Record, String, Boolean, Array, Integer` +सभी स्कीमा पल्सर के `Record` बेस क्लास से इनहेरिट होते हैं +सभी फ़ील्ड प्रकार पल्सर प्रकार हैं: `String()`, `Integer()`, `Boolean()`, `Array()`, `Map()`, `Double()` + +**उदाहरण स्कीमा:** +`schema/services/llm.py` (लाइन 2): `from pulsar.schema import Record, String, Array, Double, Integer, Boolean` +`schema/services/config.py` (लाइन 2): `from pulsar.schema import Record, Bytes, String, Boolean, Array, Map, Integer` + +**टॉपिक नामकरण:** `schema/core/topic.py` +**लाइनें 2-3:** टॉपिक फॉर्मेट: `{kind}://{tenant}/{namespace}/{topic}` +यह URI संरचना पल्सर-विशिष्ट है (जैसे, `persistent://tg/flow/config`) + +**प्रभाव:** +पूरे कोडबेस में सभी अनुरोध/प्रतिक्रिया मैसेज परिभाषाएँ पल्सर स्कीमा का उपयोग करती हैं +इसमें निम्नलिखित के लिए सेवाएँ शामिल हैं: कॉन्फ़िग, फ्लो, एलएलएम, प्रॉम्प्ट, क्वेरी, स्टोरेज, एजेंट, कलेक्शन, डायग्नोसिस, लाइब्रेरी, लुकअप, एनएलपी_क्वेरी, ऑब्जेक्ट्स_क्वेरी, रिट्रीवल, स्ट्रक्चर्ड_क्वेरी +स्कीमा परिभाषाएँ सभी प्रोसेसर और सेवाओं में आयात की जाती हैं और व्यापक रूप से उपयोग की जाती हैं + +## सारांश + +### श्रेणी के अनुसार पल्सर निर्भरताएँ + +1. **क्लाइंट इंस्टेंशिएशन:** + सीधा: `gateway/service.py` + अमूर्त: `async_processor.py` → `pubsub.py` (PulsarClient) + +2. **मैसेज ट्रांसपोर्ट:** + उपभोक्ता: `consumer.py`, `consumer_spec.py` + उत्पादक: `producer.py`, `producer_spec.py` + प्रकाशक: `publisher.py` + सब्सक्राइबर: `subscriber.py`, `subscriber_spec.py` + +3. **स्कीमा सिस्टम:** + बेस प्रकार: `schema/core/primitives.py` + सभी सेवा स्कीमा: `schema/services/*.py` + टॉपिक नामकरण: `schema/core/topic.py` + +4. **पल्सर-विशिष्ट अवधारणाएँ आवश्यक:** + टॉपिक-आधारित मैसेजिंग + स्कीमा सिस्टम (रिकॉर्ड, फ़ील्ड प्रकार) + साझा सदस्यताएँ + मैसेज स्वीकृति (सकारात्मक/नकारात्मक) + उपभोक्ता पोजिशनिंग (सबसे पहले/नवीनतम) + मैसेज प्रॉपर्टीज़ + प्रारंभिक पोजीशन और उपभोक्ता प्रकार + चंकिंग सपोर्ट + लगातार बनाम गैर-लगातार टॉपिक + +### रिफैक्टरिंग चुनौतियाँ + +अच्छी खबर: एब्स्ट्रैक्शन लेयर (उपभोक्ता, उत्पादक, प्रकाशक, सब्सक्राइबर) पल्सर इंटरैक्शन के अधिकांश पहलुओं को साफ-सुथरा रूप से एनकैप्सुलेट करता है। + +चुनौतियाँ: +1. **स्कीमा सिस्टम की सर्वव्यापकता:** हर मैसेज परिभाषा `pulsar.schema.Record` और पल्सर फ़ील्ड प्रकारों का उपयोग करती है +2. **पल्सर-विशिष्ट एनम्स:** `InitialPosition`, `ConsumerType` +3. **पल्सर अपवाद:** `_pulsar.Timeout`, `_pulsar.Interrupted`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +4. **विधि हस्ताक्षर:** `acknowledge()`, `negative_acknowledge()`, `subscribe()`, `create_producer()`, आदि। +5. **टॉपिक URI फॉर्मेट:** पल्सर की `kind://tenant/namespace/topic` संरचना + +### अगले कदम + +पब/सब इंफ्रास्ट्रक्चर को कॉन्फ़िगर करने योग्य बनाने के लिए, हमें: + +1. क्लाइंट/स्कीमा सिस्टम के लिए एक एब्स्ट्रैक्शन इंटरफ़ेस बनाएं +2. पल्सर-विशिष्ट एनम्स और अपवादों को अमूर्त करें +3. स्कीमा रैपर या वैकल्पिक स्कीमा परिभाषाएँ बनाएँ +4. पल्सर और वैकल्पिक सिस्टम (काफ्का, रैबिटएमक्यू, रेडिस स्ट्रीम्स, आदि) दोनों के लिए इंटरफ़ेस को लागू करें +5. `pubsub.py` को कॉन्फ़िगर करने योग्य बनाएं और कई बैकएंड का समर्थन करें +6. मौजूदा डिप्लॉयमेंट के लिए माइग्रेशन पाथ प्रदान करें + +## दृष्टिकोण ड्राफ्ट 1: स्कीमा ट्रांसलेशन लेयर के साथ एडाप्टर पैटर्न + +### मुख्य अंतर्दृष्टि +**स्कीमा सिस्टम** एकीकरण का सबसे गहरा बिंदु है - बाकी सब कुछ इससे उपजा है। हमें पहले इसे हल करना होगा, अन्यथा हमें पूरे कोडबेस को फिर से लिखना होगा। + +### रणनीति: न्यूनतम व्यवधान के साथ एडाप्टर + +**1. पल्सर स्कीमा को आंतरिक प्रतिनिधित्व के रूप में बनाए रखें** +सभी स्कीमा परिभाषाओं को फिर से न लिखें +स्कीमा `pulsar.schema.Record` आंतरिक रूप से बने रहेंगे +हमारे कोड और पब/सब बैकएंड के बीच की सीमा पर अनुवाद करने के लिए एडेप्टर का उपयोग करें + +**2. एक पब/सब एब्स्ट्रैक्शन लेयर बनाएं:** + +``` +┌─────────────────────────────────────┐ +│ Existing Code (unchanged) │ +│ - Uses Pulsar schemas internally │ +│ - Consumer/Producer/Publisher │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - Creates backend-specific client │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────┐ ┌────▼─────────┐ +│ PulsarAdapter│ │ KafkaAdapter │ etc... +│ (passthrough)│ │ (translates) │ +└──────────────┘ └──────────────┘ +``` + +**3. अमूर्त इंटरफेस को परिभाषित करें:** +`PubSubClient` - क्लाइंट कनेक्शन +`PubSubProducer` - संदेश भेजना +`PubSubConsumer` - संदेश प्राप्त करना +`SchemaAdapter` - पल्सर स्कीमा को JSON या बैकएंड-विशिष्ट प्रारूपों में अनुवाद करना + +**4. कार्यान्वयन विवरण:** + +**पल्सर एडेप्टर के लिए:** लगभग सीधे, न्यूनतम अनुवाद + +**अन्य बैकएंड के लिए** (Kafka, RabbitMQ, आदि): +पल्सर रिकॉर्ड ऑब्जेक्ट को JSON/बाइट में क्रमबद्ध करें +निम्नलिखित अवधारणाओं को मैप करें: + `InitialPosition.Earliest/Latest` → Kafka का auto.offset.reset + `acknowledge()` → Kafka का कमिट + `negative_acknowledge()` → पुनः कतार या DLQ पैटर्न + टॉपिक URI → बैकएंड-विशिष्ट टॉपिक नाम + +### विश्लेषण + +**लाभ:** +✅ मौजूदा सेवाओं में न्यूनतम कोड परिवर्तन +✅ स्कीमा अपरिवर्तित रहते हैं (कोई बड़ा पुनर्लेखन नहीं) +✅ क्रमिक माइग्रेशन पथ +✅ पल्सर उपयोगकर्ताओं को कोई अंतर दिखाई नहीं देता +✅ एडेप्टर के माध्यम से नए बैकएंड जोड़े जा सकते हैं + +**नुकसान:** +⚠️ अभी भी पल्सर पर निर्भरता है (स्कीमा परिभाषाओं के लिए) +⚠️ अवधारणाओं का अनुवाद करते समय कुछ असंगति + +### वैकल्पिक विचार + +एक **ट्रस्टग्राफ स्कीमा सिस्टम** बनाएं जो पब/सब से स्वतंत्र हो (डेटाक्लासेस या पाइडैंटिक का उपयोग करके), और फिर पल्सर/काफ्का/आदि स्कीमा को इससे उत्पन्न करें। इसके लिए प्रत्येक स्कीमा फ़ाइल को फिर से लिखना होगा और संभावित रूप से ब्रेकिंग परिवर्तन हो सकते हैं। + +### ड्राफ्ट 1 के लिए अनुशंसा + +**एडाप्टर दृष्टिकोण** से शुरुआत करें क्योंकि: +1. यह व्यावहारिक है - मौजूदा कोड के साथ काम करता है +2. यह न्यूनतम जोखिम के साथ अवधारणा को सिद्ध करता है +3. यदि आवश्यक हो तो बाद में एक देशी स्कीमा सिस्टम में विकसित किया जा सकता है +4. कॉन्फ़िगरेशन-संचालित: एक पर्यावरण चर बैकएंड को स्विच करता है + +## दृष्टिकोण ड्राफ्ट 2: डेटाक्लासेस के साथ बैकएंड-अज्ञेय स्कीमा सिस्टम + +### मुख्य अवधारणा + +पायथन **डेटाक्लासेस** का उपयोग तटस्थ स्कीमा परिभाषा प्रारूप के रूप में करें। प्रत्येक पब/सब बैकएंड डेटाक्लासेस के लिए अपना सीरियललाइज़ेशन/डीसेरियलाइज़ेशन प्रदान करता है, जिससे पल्सर स्कीमा को कोडबेस में बने रहने की आवश्यकता समाप्त हो जाती है। + +### फैक्ट्री स्तर पर स्कीमा बहुरूपता + +पल्सर स्कीमा का अनुवाद करने के बजाय, **प्रत्येक बैकएंड अपनी स्कीमा हैंडलिंग प्रदान करता है** जो मानक पायथन डेटाक्लासेस के साथ काम करता है। + +### प्रकाशक प्रवाह + +```python +# 1. Get the configured backend from factory +pubsub = get_pubsub() # Returns PulsarBackend, MQTTBackend, etc. + +# 2. Get schema class from the backend +# (Can be imported directly - backend-agnostic) +from trustgraph.schema.services.llm import TextCompletionRequest + +# 3. Create a producer/publisher for a specific topic +producer = pubsub.create_producer( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend what schema to use +) + +# 4. Create message instances (same API regardless of backend) +request = TextCompletionRequest( + system="You are helpful", + prompt="Hello world", + streaming=False +) + +# 5. Send the message +producer.send(request) # Backend serializes appropriately +``` + +### उपभोक्ता प्रवाह + +```python +# 1. Get the configured backend +pubsub = get_pubsub() + +# 2. Create a consumer +consumer = pubsub.subscribe( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend how to deserialize +) + +# 3. Receive and deserialize +msg = consumer.receive() +request = msg.value() # Returns TextCompletionRequest dataclass instance + +# 4. Use the data (type-safe access) +print(request.system) # "You are helpful" +print(request.prompt) # "Hello world" +print(request.streaming) # False +``` + +### पर्दे के पीछे क्या होता है + +**पल्सर बैकएंड के लिए:** +`create_producer()` → JSON स्कीमा या गतिशील रूप से उत्पन्न रिकॉर्ड के साथ पल्सर प्रोड्यूसर बनाता है +`send(request)` → डेटाक्लास को JSON/पल्सर प्रारूप में क्रमबद्ध करता है, पल्सर को भेजता है +`receive()` → पल्सर संदेश प्राप्त करता है, डेटाक्लास में वापस क्रमबद्ध करता है + +**MQTT बैकएंड के लिए:** +`create_producer()` → MQTT ब्रोकर से कनेक्ट होता है, स्कीमा पंजीकरण की आवश्यकता नहीं है +`send(request)` → डेटाक्लास को JSON में परिवर्तित करता है, MQTT टॉपिक पर प्रकाशित करता है +`receive()` → MQTT टॉपिक की सदस्यता लेता है, JSON को डेटाक्लास में क्रमबद्ध करता है + +**Kafka बैकएंड के लिए:** +`create_producer()` → Kafka प्रोड्यूसर बनाता है, यदि आवश्यक हो तो Avro स्कीमा पंजीकृत करता है +`send(request)` → डेटाक्लास को Avro प्रारूप में क्रमबद्ध करता है, Kafka को भेजता है +`receive()` → Kafka संदेश प्राप्त करता है, Avro को डेटाक्लास में वापस क्रमबद्ध करता है + +### मुख्य डिज़ाइन बिंदु + +1. **स्कीमा ऑब्जेक्ट निर्माण**: डेटाक्लास इंस्टेंस (`TextCompletionRequest(...)`) बैकएंड की परवाह किए बिना समान होता है +2. **बैकएंड एन्कोडिंग को संभालता है**: प्रत्येक बैकएंड जानता है कि अपने डेटाक्लास को वायर प्रारूप में कैसे क्रमबद्ध करना है +3. **निर्माण पर स्कीमा परिभाषा**: जब प्रोड्यूसर/कंज्यूमर बनाते हैं, तो आप स्कीमा प्रकार निर्दिष्ट करते हैं +4. **टाइप सुरक्षा संरक्षित**: आपको एक उचित `TextCompletionRequest` ऑब्जेक्ट वापस मिलता है, कोई डिक्ट नहीं +5. **कोई बैकएंड रिसाव नहीं**: एप्लिकेशन कोड कभी भी बैकएंड-विशिष्ट लाइब्रेरीज़ को आयात नहीं करता है + +### उदाहरण परिवर्तन + +**वर्तमान (पल्सर-विशिष्ट):** +```python +# schema/services/llm.py +from pulsar.schema import Record, String, Boolean, Integer + +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() +``` + +**नया (बैकएंड-स्वतंत्र):** +```python +# schema/services/llm.py +from dataclasses import dataclass + +@dataclass +class TextCompletionRequest: + system: str + prompt: str + streaming: bool = False +``` + +### बैकएंड एकीकरण + +प्रत्येक बैकएंड डेटाक्लासों का क्रमबद्धता/अक्रमबद्धता (सीरियलाइज़ेशन/डीसीरियलाइज़ेशन) संभालता है: + +**पल्सर बैकएंड:** +डेटाक्लासों से गतिशील रूप से `pulsar.schema.Record` क्लास उत्पन्न करें +या डेटाक्लासों को JSON में क्रमबद्ध करें और पल्सर के JSON स्कीमा का उपयोग करें +मौजूदा पल्सर डिप्लॉयमेंट के साथ संगतता बनाए रखता है + +**MQTT/रेडिस बैकएंड:** +डेटाक्लास उदाहरणों का सीधा JSON क्रमबद्धता +`dataclasses.asdict()` / `from_dict()` का उपयोग करें +हल्का, किसी स्कीमा रजिस्ट्री की आवश्यकता नहीं है + +**काफ्का बैकएंड:** +डेटाक्लास परिभाषाओं से एवरो स्कीमा उत्पन्न करें +कॉन्फ्लुएंट की स्कीमा रजिस्ट्री का उपयोग करें +स्कीमा विकास समर्थन के साथ टाइप-सुरक्षित क्रमबद्धता + +### वास्तुकला + +``` +┌─────────────────────────────────────┐ +│ Application Code │ +│ - Uses dataclass schemas │ +│ - Backend-agnostic │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - get_pubsub() returns backend │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────────┐ ┌────▼──────────────┐ +│ PulsarBackend │ │ MQTTBackend │ +│ - JSON schema │ │ - JSON serialize │ +│ - or dynamic │ │ - Simple queues │ +│ Record gen │ │ │ +└─────────────────┘ └───────────────────┘ +``` + +### कार्यान्वयन विवरण + +**1. स्कीमा परिभाषाएँ:** साधारण डेटाक्लास, टाइप हिंट के साथ + `str`, `int`, `bool`, `float` मूल डेटा प्रकारों के लिए + `list[T]` सरणियों के लिए + `dict[str, T]` मानचित्रों के लिए + जटिल प्रकारों के लिए नेस्टेड डेटाक्लास + +**2. प्रत्येक बैकएंड निम्नलिखित प्रदान करता है:** + सीरियलइज़र: `dataclass → bytes/wire format` + डीसीरियलइज़र: `bytes/wire format → dataclass` + स्कीमा पंजीकरण (यदि आवश्यक हो, जैसे कि Pulsar/Kafka) + +**3. उपभोक्ता/उत्पादक सार:** + पहले से मौजूद (consumer.py, producer.py) + बैकएंड के सीरियलइज़ेशन का उपयोग करने के लिए अपडेट करें + सीधे Pulsar आयात को हटा दें + +**4. टाइप मैपिंग:** + Pulsar `String()` → Python `str` + Pulsar `Integer()` → Python `int` + Pulsar `Boolean()` → Python `bool` + Pulsar `Array(T)` → Python `list[T]` + Pulsar `Map(K, V)` → Python `dict[K, V]` + Pulsar `Double()` → Python `float` + Pulsar `Bytes()` → Python `bytes` + +### माइग्रेशन पथ + +1. `trustgraph/schema/` में सभी स्कीमा के डेटाक्लास संस्करण बनाएं +2. बैकएंड-प्रदान सीरियलइज़ेशन का उपयोग करने के लिए (उपभोक्ता, उत्पादक, प्रकाशक, ग्राहक) बैकएंड क्लास को अपडेट करें +3. JSON स्कीमा या गतिशील रिकॉर्ड पीढ़ी के साथ PulsarBackend को लागू करें +4. मौजूदा परिनियोजनों के साथ पिछड़े अनुकूलता सुनिश्चित करने के लिए Pulsar के साथ परीक्षण करें +5. आवश्यकतानुसार नए बैकएंड (MQTT, Kafka, Redis, आदि) जोड़ें +6. स्कीमा फ़ाइलों से Pulsar आयात को हटा दें + +### लाभ + +✅ **स्कीमा परिभाषाओं में कोई पब/सब निर्भरता नहीं** +✅ **मानक Python** - समझने, टाइप-चेक करने और दस्तावेज़ बनाने में आसान +✅ **आधुनिक टूलिंग** - mypy, IDE ऑटो-कंप्लीट, लिंटर के साथ काम करता है +✅ **बैकएंड-अनुकूलित** - प्रत्येक बैकएंड देशी सीरियलइज़ेशन का उपयोग करता है +✅ **कोई अनुवाद ओवरहेड नहीं** - सीधा सीरियलइज़ेशन, कोई एडेप्टर नहीं +✅ **टाइप सुरक्षा** - उचित प्रकारों के साथ वास्तविक ऑब्जेक्ट +✅ **आसान सत्यापन** - यदि आवश्यक हो तो Pydantic का उपयोग कर सकते हैं + +### चुनौतियाँ और समाधान + +**चुनौती:** Pulsar का `Record` में रनटाइम फ़ील्ड सत्यापन होता है +**समाधान:** यदि आवश्यक हो तो सत्यापन के लिए Pydantic डेटाक्लास का उपयोग करें, या `__post_init__` के साथ Python 3.10+ डेटाक्लास सुविधाओं का उपयोग करें + +**चुनौती:** कुछ Pulsar-विशिष्ट विशेषताएं (जैसे `Bytes` प्रकार) +**समाधान:** डेटाक्लास में `bytes` प्रकार पर मैप करें, बैकएंड उचित रूप से एन्कोडिंग को संभालता है + +**चुनौती:** टॉपिक नामकरण (`persistent://tenant/namespace/topic`) +**समाधान:** स्कीमा परिभाषाओं में टॉपिक नामों को सारगर्भित करें, बैकएंड उचित प्रारूप में परिवर्तित करता है + +**चुनौती:** स्कीमा विकास और संस्करण +**समाधान:** प्रत्येक बैकएंड अपनी क्षमताओं के अनुसार इसका प्रबंधन करता है (Pulsar स्कीमा संस्करण, Kafka स्कीमा रजिस्ट्री, आदि) + +**चुनौती:** नेस्टेड जटिल प्रकार +**समाधान:** नेस्टेड डेटाक्लास का उपयोग करें, बैकएंड पुनरावर्ती रूप से सीरियलइज़/डीसीरियलइज़ करते हैं + +### डिज़ाइन निर्णय + +1. **सादे डेटाक्लास या Pydantic?** + ✅ **निर्णय: सादे Python डेटाक्लास का उपयोग करें** + सरल, कोई अतिरिक्त निर्भरता नहीं + सत्यापन व्यावहारिक रूप से आवश्यक नहीं है + समझना और बनाए रखना आसान है + +2. **स्कीमा विकास:** + ✅ **निर्णय: कोई संस्करण तंत्र आवश्यक नहीं है** + स्कीमा स्थिर और लंबे समय तक चलने वाले हैं + अपडेट आमतौर पर नए फ़ील्ड जोड़ते हैं (पिछड़े संगत) + बैकएंड अपनी क्षमताओं के अनुसार स्कीमा विकास को संभालते हैं + +3. **पिछड़ी संगतता:** + ✅ **निर्णय: प्रमुख संस्करण परिवर्तन, पिछड़े संगतता की आवश्यकता नहीं है** + यह एक ब्रेकिंग परिवर्तन होगा जिसमें माइग्रेशन निर्देश होंगे + बेहतर डिज़ाइन के लिए स्वच्छ ब्रेक + मौजूदा परिनियोजनों के लिए एक माइग्रेशन गाइड प्रदान किया जाएगा + +4. **नेस्टेड प्रकार और जटिल संरचनाएं:** + ✅ **निर्णय: स्वाभाविक रूप से नेस्टेड डेटाक्लास का उपयोग करें** + Python डेटाक्लास नेस्टिंग को पूरी तरह से संभालते हैं + सरणियों के लिए `list[T]`, मानचित्रों के लिए `dict[K, V]` + बैकएंड पुनरावर्ती रूप से सीरियलइज़/डीसीरियलइज़ करते हैं + उदाहरण: + ```python + @dataclass + class Value: + value: str + is_uri: bool + + @dataclass + class Triple: + s: Value # Nested dataclass + p: Value + o: Value + + @dataclass + class GraphQuery: + triples: list[Triple] # Array of nested dataclasses + metadata: dict[str, str] + ``` + +5. **डिफ़ॉल्ट मान और वैकल्पिक फ़ील्ड:** + ✅ **निर्णय: आवश्यक, डिफ़ॉल्ट और वैकल्पिक फ़ील्ड का मिश्रण** + आवश्यक फ़ील्ड: कोई डिफ़ॉल्ट मान नहीं + डिफ़ॉल्ट वाले फ़ील्ड: हमेशा मौजूद, उनका उचित डिफ़ॉल्ट मान होता है + वास्तव में वैकल्पिक फ़ील्ड: `T | None = None`, जब `None` हो तो क्रमबद्धता से छोड़े जा सकते हैं + उदाहरण: + ```python + @dataclass + class TextCompletionRequest: + system: str # Required, no default + prompt: str # Required, no default + streaming: bool = False # Optional with default value + metadata: dict | None = None # Truly optional, can be absent + ``` + + **महत्वपूर्ण क्रमबद्धता अर्थ:** + + जब `metadata = None`: + ```json + { + "system": "...", + "prompt": "...", + "streaming": false + // metadata field NOT PRESENT + } + ``` + + जब `metadata = {}` (स्पष्ट रूप से खाली): + ```json + { + "system": "...", + "prompt": "...", + "streaming": false, + "metadata": {} // Field PRESENT but empty + } + ``` + + **मुख्य अंतर:** + `None` → JSON में अनुपस्थित फ़ील्ड (सीरियलाइज़ नहीं किया गया) + खाली मान (`{}`, `[]`, `""`) → फ़ील्ड मौजूद है लेकिन खाली मान के साथ + यह अर्थपूर्ण रूप से महत्वपूर्ण है: "प्रदान नहीं किया गया" बनाम "स्पष्ट रूप से खाली" + सीरियलाइज़ेशन बैकएंड को `None` फ़ील्ड को छोड़ना चाहिए, न कि इसे `null` के रूप में एन्कोड करना चाहिए + +## दृष्टिकोण ड्राफ्ट 3: कार्यान्वयन विवरण + +### सामान्य कतार नामकरण प्रारूप + +बैकएंड-विशिष्ट कतार नामों को एक सामान्य प्रारूप से बदलें जिसे बैकएंड उचित रूप से मैप कर सकें। + +**प्रारूप:** `{qos}/{tenant}/{namespace}/{queue-name}` + +जहाँ: +`qos`: सेवा की गुणवत्ता स्तर + `q0` = बेस्ट-एफर्ट (फायर एंड फॉरगेट, कोई स्वीकृति नहीं) + `q1` = एट-लीस्ट-वन्स (स्वीकृति की आवश्यकता होती है) + `q2` = एग्ज़ैक्टली-वन्स (दो-चरण स्वीकृति) +`tenant`: मल्टी-टेनेंसी के लिए तार्किक समूहीकरण +`namespace`: किरायेदार के भीतर उप-समूहीकरण +`queue-name`: वास्तविक कतार/विषय नाम + +**उदाहरण:** +``` +q1/tg/flow/text-completion-requests +q2/tg/config/config-push +q0/tg/metrics/stats +``` + +### बैकएंड टॉपिक मैपिंग + +प्रत्येक बैकएंड सामान्य प्रारूप को अपने मूल प्रारूप में परिवर्तित करता है: + +**पल्सर बैकएंड:** +```python +def map_topic(self, generic_topic: str) -> str: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS to persistence + persistence = 'persistent' if qos in ['q1', 'q2'] else 'non-persistent' + + # Return Pulsar URI: persistent://tg/flow/text-completion-requests + return f"{persistence}://{tenant}/{namespace}/{queue}" +``` + +**एमक्यूटीटी बैकएंड:** +```python +def map_topic(self, generic_topic: str) -> tuple[str, int]: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS level + qos_level = {'q0': 0, 'q1': 1, 'q2': 2}[qos] + + # Build MQTT topic including tenant/namespace for proper namespacing + mqtt_topic = f"{tenant}/{namespace}/{queue}" + + return mqtt_topic, qos_level +``` + +### अद्यतित विषय सहायक फ़ंक्शन + +```python +# schema/core/topic.py +def topic(queue_name, qos='q1', tenant='tg', namespace='flow'): + """ + Create a generic topic identifier that can be mapped by backends. + + Args: + queue_name: The queue/topic name + qos: Quality of service + - 'q0' = best-effort (no ack) + - 'q1' = at-least-once (ack required) + - 'q2' = exactly-once (two-phase ack) + tenant: Tenant identifier for multi-tenancy + namespace: Namespace within tenant + + Returns: + Generic topic string: qos/tenant/namespace/queue_name + + Examples: + topic('my-queue') # q1/tg/flow/my-queue + topic('config', qos='q2', namespace='config') # q2/tg/config/config + """ + return f"{qos}/{tenant}/{namespace}/{queue_name}" +``` + +### कॉन्फ़िगरेशन और इनिशियलाइज़ेशन + +**कमांड-लाइन तर्क + पर्यावरण चर:** + +```python +# In base/async_processor.py - add_args() method +@staticmethod +def add_args(parser): + # Pub/sub backend selection + parser.add_argument( + '--pubsub-backend', + default=os.getenv('PUBSUB_BACKEND', 'pulsar'), + choices=['pulsar', 'mqtt'], + help='Pub/sub backend (default: pulsar, env: PUBSUB_BACKEND)' + ) + + # Pulsar-specific configuration + parser.add_argument( + '--pulsar-host', + default=os.getenv('PULSAR_HOST', 'pulsar://localhost:6650'), + help='Pulsar host (default: pulsar://localhost:6650, env: PULSAR_HOST)' + ) + + parser.add_argument( + '--pulsar-api-key', + default=os.getenv('PULSAR_API_KEY', None), + help='Pulsar API key (env: PULSAR_API_KEY)' + ) + + parser.add_argument( + '--pulsar-listener', + default=os.getenv('PULSAR_LISTENER', None), + help='Pulsar listener name (env: PULSAR_LISTENER)' + ) + + # MQTT-specific configuration + parser.add_argument( + '--mqtt-host', + default=os.getenv('MQTT_HOST', 'localhost'), + help='MQTT broker host (default: localhost, env: MQTT_HOST)' + ) + + parser.add_argument( + '--mqtt-port', + type=int, + default=int(os.getenv('MQTT_PORT', '1883')), + help='MQTT broker port (default: 1883, env: MQTT_PORT)' + ) + + parser.add_argument( + '--mqtt-username', + default=os.getenv('MQTT_USERNAME', None), + help='MQTT username (env: MQTT_USERNAME)' + ) + + parser.add_argument( + '--mqtt-password', + default=os.getenv('MQTT_PASSWORD', None), + help='MQTT password (env: MQTT_PASSWORD)' + ) +``` + +**फ़ैक्टरी फ़ंक्शन:** + +```python +# In base/pubsub.py or base/pubsub_factory.py +def get_pubsub(**config) -> PubSubBackend: + """ + Create and return a pub/sub backend based on configuration. + + Args: + config: Configuration dict from command-line args + Must include 'pubsub_backend' key + + Returns: + Backend instance (PulsarBackend, MQTTBackend, etc.) + """ + backend_type = config.get('pubsub_backend', 'pulsar') + + if backend_type == 'pulsar': + return PulsarBackend( + host=config.get('pulsar_host'), + api_key=config.get('pulsar_api_key'), + listener=config.get('pulsar_listener'), + ) + elif backend_type == 'mqtt': + return MQTTBackend( + host=config.get('mqtt_host'), + port=config.get('mqtt_port'), + username=config.get('mqtt_username'), + password=config.get('mqtt_password'), + ) + else: + raise ValueError(f"Unknown pub/sub backend: {backend_type}") +``` + +**एसिंक्रोनसप्रोसेसर में उपयोग:** + +```python +# In async_processor.py +class AsyncProcessor: + def __init__(self, **params): + self.id = params.get("id") + + # Create backend from config (replaces PulsarClient) + self.pubsub = get_pubsub(**params) + + # Rest of initialization... +``` + +### बैकएंड इंटरफ़ेस + +```python +class PubSubBackend(Protocol): + """Protocol defining the interface all pub/sub backends must implement.""" + + def create_producer(self, topic: str, schema: type, **options) -> BackendProducer: + """ + Create a producer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + schema: Dataclass type for messages + options: Backend-specific options (e.g., chunking_enabled) + + Returns: + Backend-specific producer instance + """ + ... + + def create_consumer( + self, + topic: str, + subscription: str, + schema: type, + initial_position: str = 'latest', + consumer_type: str = 'shared', + **options + ) -> BackendConsumer: + """ + Create a consumer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + subscription: Subscription/consumer group name + schema: Dataclass type for messages + initial_position: 'earliest' or 'latest' (MQTT may ignore) + consumer_type: 'shared', 'exclusive', 'failover' (MQTT may ignore) + options: Backend-specific options + + Returns: + Backend-specific consumer instance + """ + ... + + def close(self) -> None: + """Close the backend connection.""" + ... +``` + +```python +class BackendProducer(Protocol): + """Protocol for backend-specific producer.""" + + def send(self, message: Any, properties: dict = {}) -> None: + """Send a message (dataclass instance) with optional properties.""" + ... + + def flush(self) -> None: + """Flush any buffered messages.""" + ... + + def close(self) -> None: + """Close the producer.""" + ... +``` + +```python +class BackendConsumer(Protocol): + """Protocol for backend-specific consumer.""" + + def receive(self, timeout_millis: int = 2000) -> Message: + """ + Receive a message from the topic. + + Raises: + TimeoutError: If no message received within timeout + """ + ... + + def acknowledge(self, message: Message) -> None: + """Acknowledge successful processing of a message.""" + ... + + def negative_acknowledge(self, message: Message) -> None: + """Negative acknowledge - triggers redelivery.""" + ... + + def unsubscribe(self) -> None: + """Unsubscribe from the topic.""" + ... + + def close(self) -> None: + """Close the consumer.""" + ... +``` + +```python +class Message(Protocol): + """Protocol for a received message.""" + + def value(self) -> Any: + """Get the deserialized message (dataclass instance).""" + ... + + def properties(self) -> dict: + """Get message properties/metadata.""" + ... +``` + +### मौजूदा कक्षाओं का पुनर्गठन + +मौजूदा `Consumer`, `Producer`, `Publisher`, `Subscriber` कक्षाएं काफी हद तक अपरिवर्तित रहेंगी: + +**वर्तमान जिम्मेदारियां (बनाए रखें):** +एसिंक्रोनस थ्रेडिंग मॉडल और टास्कग्रुप +पुनः कनेक्शन लॉजिक और पुनः प्रयास प्रबंधन +मेट्रिक्स संग्रह +दर सीमित करना +समवर्ती प्रबंधन + +**आवश्यक परिवर्तन:** +सीधे पल्सर आयात को हटा दें (`pulsar.schema`, `pulsar.InitialPosition`, आदि) +पल्सर क्लाइंट के बजाय `BackendProducer`/`BackendConsumer` स्वीकार करें +वास्तविक पब/सब संचालन को बैकएंड इंस्टेंस को सौंपें +सामान्य अवधारणाओं को बैकएंड कॉल में मैप करें + +**उदाहरण पुनर्गठन:** + +```python +# OLD - consumer.py +class Consumer: + def __init__(self, client, topic, subscriber, schema, ...): + self.client = client # Direct Pulsar client + # ... + + async def consumer_run(self): + # Uses pulsar.InitialPosition, pulsar.ConsumerType + self.consumer = self.client.subscribe( + topic=self.topic, + schema=JsonSchema(self.schema), + initial_position=pulsar.InitialPosition.Earliest, + consumer_type=pulsar.ConsumerType.Shared, + ) + +# NEW - consumer.py +class Consumer: + def __init__(self, backend_consumer, schema, ...): + self.backend_consumer = backend_consumer # Backend-specific consumer + self.schema = schema + # ... + + async def consumer_run(self): + # Backend consumer already created with right settings + # Just use it directly + while self.running: + msg = await asyncio.to_thread( + self.backend_consumer.receive, + timeout_millis=2000 + ) + await self.handle_message(msg) +``` + +### बैकएंड-विशिष्ट व्यवहार + +**पल्सर बैकएंड:** +`q0` को `non-persistent://` में मैप करता है, `q1`/`q2` को `persistent://` में मैप करता है। +सभी प्रकार के उपभोक्ताओं का समर्थन करता है (साझा, विशेष, फेलओवर)। +प्रारंभिक स्थिति का समर्थन करता है (सबसे पहले/सबसे बाद में)। +मूल संदेश स्वीकृति। +स्कीमा रजिस्ट्री समर्थन। + +**एमक्यूटीटी बैकएंड:** +`q0`/`q1`/`q2` को एमक्यूटीटी क्यूओएस स्तर 0/1/2 में मैप करता है। +नामस्थान के लिए टॉपिक पथ में किरायेदार/नेमस्पेस शामिल करता है। +सदस्यता नामों से स्वचालित रूप से क्लाइंट आईडी उत्पन्न करता है। +प्रारंभिक स्थिति को अनदेखा करता है (मूल एमक्यूटीटी में कोई संदेश इतिहास नहीं)। +उपभोक्ता प्रकार को अनदेखा करता है (एमक्यूटीटी क्लाइंट आईडी, उपभोक्ता समूहों का उपयोग नहीं करता है)। +सरल प्रकाशित/सदस्यता मॉडल। + +### डिज़ाइन निर्णयों का सारांश + +1. ✅ **सामान्य कतार नामकरण**: `qos/tenant/namespace/queue-name` प्रारूप। +2. ✅ **कतार आईडी में क्यूओएस**: कतार परिभाषा द्वारा निर्धारित, कॉन्फ़िगरेशन द्वारा नहीं। +3. ✅ **पुनः कनेक्शन**: उपभोक्ता/उत्पादक कक्षाओं द्वारा संभाला जाता है, बैकएंड द्वारा नहीं। +4. ✅ **एमक्यूटीटी टॉपिक**: उचित नामस्थान के लिए किरायेदार/नेमस्पेस शामिल करें। +5. ✅ **संदेश इतिहास**: एमक्यूटीटी `initial_position` पैरामीटर को अनदेखा करता है (भविष्य में सुधार)। +6. ✅ **क्लाइंट आईडी**: एमक्यूटीटी बैकएंड सदस्यता नाम से स्वचालित रूप से उत्पन्न करता है। + +### भविष्य के सुधार + +**एमक्यूटीटी संदेश इतिहास:** +वैकल्पिक दृढ़ता परत (जैसे, रिटेन्ड संदेश, बाहरी स्टोर) जोड़ा जा सकता है। +यह `initial_position='earliest'` का समर्थन करने की अनुमति देगा। +प्रारंभिक कार्यान्वयन के लिए आवश्यक नहीं है। + diff --git a/docs/tech-specs/pubsub.pt.md b/docs/tech-specs/pubsub.pt.md new file mode 100644 index 00000000..e9c131b0 --- /dev/null +++ b/docs/tech-specs/pubsub.pt.md @@ -0,0 +1,958 @@ +# Infraestrutura Pub/Sub + +## Visão Geral + +Este documento cataloga todas as conexões entre o código-fonte do TrustGraph e a infraestrutura pub/sub. Atualmente, o sistema está codificado para usar o Apache Pulsar. Esta análise identifica todos os pontos de integração para informar futuras refatorações em direção a uma abstração pub/sub configurável. + +## Estado Atual: Pontos de Integração do Pulsar + +### 1. Uso Direto do Cliente Pulsar + +**Localização:** `trustgraph-flow/trustgraph/gateway/service.py` + +O gateway da API importa e instancia diretamente o cliente Pulsar: + +**Linha 20:** `import pulsar` +**Linhas 54-61:** Instanciação direta de `pulsar.Client()` com `pulsar.AuthenticationToken()` opcional +**Linhas 33-35:** Configuração padrão do host Pulsar a partir de variáveis de ambiente +**Linhas 178-192:** Argumentos da linha de comando para `--pulsar-host`, `--pulsar-api-key` e `--pulsar-listener` +**Linhas 78, 124:** Passa `pulsar_client` para `ConfigReceiver` e `DispatcherManager` + +Esta é a única localização que instancia diretamente um cliente Pulsar fora da camada de abstração. + +### 2. Framework Base do Processador + +**Localização:** `trustgraph-base/trustgraph/base/async_processor.py` + +A classe base para todos os processadores fornece conectividade Pulsar: + +**Linha 9:** `import _pulsar` (para tratamento de exceções) +**Linha 18:** `from . pubsub import PulsarClient` +**Linha 38:** Cria `pulsar_client_object = PulsarClient(**params)` +**Linhas 104-108:** Propriedades que expõem `pulsar_host` e `pulsar_client` +**Linha 250:** O método estático `add_args()` chama `PulsarClient.add_args(parser)` para argumentos da linha de comando +**Linhas 223-225:** Tratamento de exceções para `_pulsar.Interrupted` + +Todos os processadores herdam de `AsyncProcessor`, tornando este o ponto de integração central. + +### 3. Abstração do Consumidor + +**Localização:** `trustgraph-base/trustgraph/base/consumer.py` + +Consome mensagens de filas e invoca funções de tratamento: + +**Importações do Pulsar:** +**Linha 12:** `from pulsar.schema import JsonSchema` +**Linha 13:** `import pulsar` +**Linha 14:** `import _pulsar` + +**Uso específico do Pulsar:** +**Linhas 100, 102:** `pulsar.InitialPosition.Earliest` / `pulsar.InitialPosition.Latest` +**Linha 108:** Wrapper `JsonSchema(self.schema)` +**Linha 110:** `pulsar.ConsumerType.Shared` +**Linhas 104-111:** `self.client.subscribe()` com parâmetros específicos do Pulsar +**Linhas 143, 150, 65:** Métodos `consumer.unsubscribe()` e `consumer.close()` +**Linha 162:** Exceção `_pulsar.Timeout` +**Linhas 182, 205, 232:** `consumer.acknowledge()` / `consumer.negative_acknowledge()` + +**Arquivo de especificação:** `trustgraph-base/trustgraph/base/consumer_spec.py` +**Linha 22:** Referencia `processor.pulsar_client` + +### 4. Abstração do Produtor + +**Localização:** `trustgraph-base/trustgraph/base/producer.py` + +Envia mensagens para filas: + +**Importações do Pulsar:** +**Linha 2:** `from pulsar.schema import JsonSchema` + +**Uso específico do Pulsar:** +**Linha 49:** Wrapper `JsonSchema(self.schema)` +**Linhas 47-51:** `self.client.create_producer()` com parâmetros específicos do Pulsar (tópico, esquema, chunking_enabled) +**Linhas 31, 76:** Método `producer.close()` +**Linhas 64-65:** `producer.send()` com mensagem e propriedades + +**Arquivo de especificação:** `trustgraph-base/trustgraph/base/producer_spec.py` +**Linha 18:** Referencia `processor.pulsar_client` + +### 5. Abstração do Publicador + +**Localização:** `trustgraph-base/trustgraph/base/publisher.py` + +Publicação de mensagens assíncrona com buffer de fila: + +**Importações do Pulsar:** +**Linha 2:** `from pulsar.schema import JsonSchema` +**Linha 6:** `import pulsar` + +**Uso específico do Pulsar:** +**Linha 52:** Wrapper `JsonSchema(self.schema)` +**Linhas 50-54:** `self.client.create_producer()` com parâmetros específicos do Pulsar +**Linhas 101, 103:** `producer.send()` com mensagem e propriedades opcionais +**Linhas 106-107:** Métodos `producer.flush()` e `producer.close()` + +### 6. Abstração do Assinante + +**Localização:** `trustgraph-base/trustgraph/base/subscriber.py` + +Fornece distribuição de mensagens para múltiplos destinatários a partir de filas: + +**Importações do Pulsar:** +**Linha 6:** `from pulsar.schema import JsonSchema` +**Linha 8:** `import _pulsar` + +**Uso específico do Pulsar:** +**Linha 55:** `JsonSchema(self.schema)` wrapper +**Linha 57:** `self.client.subscribe(**subscribe_args)` +**Linhas 101, 136, 160, 167-172:** Exceções do Pulsar: `_pulsar.Timeout`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +**Linhas 159, 166, 170:** Métodos do consumidor: `negative_acknowledge()`, `unsubscribe()`, `close()` +**Linhas 247, 251:** Reconhecimento de mensagens: `acknowledge()`, `negative_acknowledge()` + +**Arquivo de especificação:** `trustgraph-base/trustgraph/base/subscriber_spec.py` +**Linha 19:** Referencia `processor.pulsar_client` + +### 7. Sistema de Schema (Heart of Darkness) + +**Localização:** `trustgraph-base/trustgraph/schema/` + +Cada schema de mensagem no sistema é definido usando o framework de schema do Pulsar. + +**Primitivos principais:** `schema/core/primitives.py` +**Linha 2:** `from pulsar.schema import Record, String, Boolean, Array, Integer` +Todos os schemas herdam da classe base do Pulsar `Record` +Todos os tipos de campo são tipos do Pulsar: `String()`, `Integer()`, `Boolean()`, `Array()`, `Map()`, `Double()` + +**Schemas de exemplo:** +`schema/services/llm.py` (Linha 2): `from pulsar.schema import Record, String, Array, Double, Integer, Boolean` +`schema/services/config.py` (Linha 2): `from pulsar.schema import Record, Bytes, String, Boolean, Array, Map, Integer` + +**Nomeação de tópicos:** `schema/core/topic.py` +**Linhas 2-3:** Formato do tópico: `{kind}://{tenant}/{namespace}/{topic}` +Esta estrutura de URI é específica do Pulsar (por exemplo, `persistent://tg/flow/config`) + +**Impacto:** +Todas as definições de mensagens de solicitação/resposta em todo o código-fonte usam schemas do Pulsar +Isso inclui serviços para: config, flow, llm, prompt, query, storage, agent, collection, diagnosis, library, lookup, nlp_query, objects_query, retrieval, structured_query +As definições de schema são importadas e usadas extensivamente em todos os processadores e serviços + +## Resumo + +### Dependências do Pulsar por Categoria + +1. **Instanciação do cliente:** + Direto: `gateway/service.py` + Abstrato: `async_processor.py` → `pubsub.py` (PulsarClient) + +2. **Transporte de mensagens:** + Consumidor: `consumer.py`, `consumer_spec.py` + Produtor: `producer.py`, `producer_spec.py` + Publicador: `publisher.py` + Assinante: `subscriber.py`, `subscriber_spec.py` + +3. **Sistema de schema:** + Tipos base: `schema/core/primitives.py` + Todos os schemas de serviço: `schema/services/*.py` + Nomeação de tópicos: `schema/core/topic.py` + +4. **Conceitos específicos do Pulsar necessários:** + Mensagens baseadas em tópicos + Sistema de schema (Registro, tipos de campo) + Assinaturas compartilhadas + Reconhecimento de mensagens (positivo/negativo) + Posicionamento do consumidor (mais cedo/mais tarde) + Propriedades da mensagem + Posições iniciais e tipos de consumidor + Suporte de fragmentação + Tópicos persistentes vs não persistentes + +### Desafios de Refatoração + +A boa notícia: A camada de abstração (Consumidor, Produtor, Publicador, Assinante) fornece um encapsulamento limpo da maioria das interações do Pulsar. + +Os desafios: +1. **Ubiquidade do sistema de schema:** Cada definição de mensagem usa `pulsar.schema.Record` e tipos de campo do Pulsar +2. **Enums específicos do Pulsar:** `InitialPosition`, `ConsumerType` +3. **Exceções do Pulsar:** `_pulsar.Timeout`, `_pulsar.Interrupted`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +4. **Assinaturas de método:** `acknowledge()`, `negative_acknowledge()`, `subscribe()`, `create_producer()`, etc. +5. **Formato de URI do tópico:** Estrutura do Pulsar `kind://tenant/namespace/topic` + +### Próximos Passos + +Para tornar a infraestrutura de pub/sub configurável, precisamos: + +1. Criar uma interface de abstração para o sistema de cliente/schema +2. Abstrair enums e exceções específicos do Pulsar +3. Criar wrappers de schema ou definições de schema alternativas +4. Implementar a interface para sistemas Pulsar e sistemas alternativos (Kafka, RabbitMQ, Redis Streams, etc.) +5. Atualizar `pubsub.py` para ser configurável e suportar vários backends +6. Fornecer um caminho de migração para implantações existentes + +## Abordagem Preliminar 1: Padrão Adapter com Camada de Tradução de Schema + +### Principio Fundamental +O **sistema de schema** é o ponto de integração mais profundo - tudo o mais deriva dele. Precisamos resolver isso primeiro, ou teremos que reescrever todo o código-fonte. + +### Estratégia: Encapsulamento Mínimo com Adapters + +**1. Manter os esquemas Pulsar como a representação interna** +Não reescrever todas as definições de esquema +Os esquemas permanecem `pulsar.schema.Record` internamente +Usar adaptadores para traduzir na fronteira entre nosso código e o backend de publicação/assinatura + +**2. Criar uma camada de abstração de publicação/assinatura:** + +``` +┌─────────────────────────────────────┐ +│ Existing Code (unchanged) │ +│ - Uses Pulsar schemas internally │ +│ - Consumer/Producer/Publisher │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - Creates backend-specific client │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────┐ ┌────▼─────────┐ +│ PulsarAdapter│ │ KafkaAdapter │ etc... +│ (passthrough)│ │ (translates) │ +└──────────────┘ └──────────────┘ +``` + +**3. Defina interfaces abstratas:** +`PubSubClient` - conexão do cliente +`PubSubProducer` - envio de mensagens +`PubSubConsumer` - recebimento de mensagens +`SchemaAdapter` - tradução de esquemas Pulsar para/de JSON ou formatos específicos do backend + +**4. Detalhes de implementação:** + +Para o **adaptador Pulsar**: Quase transparente, tradução mínima + +Para **outros backends** (Kafka, RabbitMQ, etc.): +Serializa objetos de registro Pulsar para JSON/bytes +Mapeia conceitos como: + `InitialPosition.Earliest/Latest` → auto.offset.reset do Kafka + `acknowledge()` → commit do Kafka + `negative_acknowledge()` → padrão de re-fila ou DLQ + URIs de tópicos → nomes de tópicos específicos do backend + +### Análise + +**Prós:** +✅ Alterações mínimas no código dos serviços existentes +✅ Os esquemas permanecem como estão (sem reescrita massiva) +✅ Caminho de migração gradual +✅ Os usuários do Pulsar não percebem diferença +✅ Novos backends adicionados via adaptadores + +**Contras:** +⚠️ Ainda possui dependência do Pulsar (para definições de esquema) +⚠️ Alguma incompatibilidade na tradução de conceitos + +### Consideração Alternativa + +Crie um sistema de esquemas **TrustGraph** que seja agnóstico de pub/sub (usando dataclasses ou Pydantic), e então gere esquemas Pulsar/Kafka/etc a partir dele. Isso requer reescrever todos os arquivos de esquema e pode causar alterações disruptivas. + +### Recomendação para a Versão 1 + +Comece com a **abordagem de adaptador** porque: +1. É pragmática - funciona com o código existente +2. Demonstra o conceito com risco mínimo +3. Pode evoluir para um sistema de esquemas nativo posteriormente, se necessário +4. Impulsionado por configuração: uma variável de ambiente alterna entre backends + +## Abordagem da Versão 2: Sistema de Esquemas Agnostic de Backend com Dataclasses + +### Conceito Central + +Use **dataclasses** do Python como o formato de definição de esquema neutro. Cada backend de pub/sub fornece sua própria serialização/desserialização para dataclasses, eliminando a necessidade de que os esquemas Pulsar permaneçam no código-fonte. + +### Polimorfismo de Esquema no Nível da Fábrica + +Em vez de traduzir esquemas Pulsar, **cada backend fornece seu próprio tratamento de esquema** que funciona com dataclasses Python padrão. + +### Fluxo do Publicador + +```python +# 1. Get the configured backend from factory +pubsub = get_pubsub() # Returns PulsarBackend, MQTTBackend, etc. + +# 2. Get schema class from the backend +# (Can be imported directly - backend-agnostic) +from trustgraph.schema.services.llm import TextCompletionRequest + +# 3. Create a producer/publisher for a specific topic +producer = pubsub.create_producer( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend what schema to use +) + +# 4. Create message instances (same API regardless of backend) +request = TextCompletionRequest( + system="You are helpful", + prompt="Hello world", + streaming=False +) + +# 5. Send the message +producer.send(request) # Backend serializes appropriately +``` + +### Fluxo do Consumidor + +```python +# 1. Get the configured backend +pubsub = get_pubsub() + +# 2. Create a consumer +consumer = pubsub.subscribe( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend how to deserialize +) + +# 3. Receive and deserialize +msg = consumer.receive() +request = msg.value() # Returns TextCompletionRequest dataclass instance + +# 4. Use the data (type-safe access) +print(request.system) # "You are helpful" +print(request.prompt) # "Hello world" +print(request.streaming) # False +``` + +### O que acontece nos bastidores + +**Para o backend Pulsar:** +`create_producer()` → cria um produtor Pulsar com esquema JSON ou um registro gerado dinamicamente. +`send(request)` → serializa a classe de dados para o formato JSON/Pulsar e envia para o Pulsar. +`receive()` → recebe a mensagem do Pulsar, desserializa de volta para a classe de dados. + +**Para o backend MQTT:** +`create_producer()` → conecta a um broker MQTT, não é necessário registro de esquema. +`send(request)` → converte a classe de dados para JSON e publica em um tópico MQTT. +`receive()` → assina um tópico MQTT e desserializa o JSON para a classe de dados. + +**Para o backend Kafka:** +`create_producer()` → cria um produtor Kafka e registra o esquema Avro, se necessário. +`send(request)` → serializa a classe de dados para o formato Avro e envia para o Kafka. +`receive()` → recebe a mensagem do Kafka e desserializa o Avro de volta para a classe de dados. + +### Pontos-chave do design + +1. **Criação do objeto de esquema**: A instância da classe de dados (`TextCompletionRequest(...)`) é idêntica, independentemente do backend. +2. **O backend lida com a codificação**: Cada backend sabe como serializar sua classe de dados para o formato de transmissão. +3. **Definição do esquema na criação**: Ao criar o produtor/consumidor, você especifica o tipo de esquema. +4. **Segurança de tipo preservada**: Você recebe um objeto `TextCompletionRequest` adequado, não um dicionário. +5. **Nenhum vazamento do backend**: O código da aplicação nunca importa bibliotecas específicas do backend. + +### Exemplo de transformação + +**Atual (específico para Pulsar):** +```python +# schema/services/llm.py +from pulsar.schema import Record, String, Boolean, Integer + +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() +``` + +**Novo (Independente do backend):** +```python +# schema/services/llm.py +from dataclasses import dataclass + +@dataclass +class TextCompletionRequest: + system: str + prompt: str + streaming: bool = False +``` + +### Integração com o Backend + +Cada backend lida com a serialização/desserialização de dataclasses: + +**Backend Pulsar:** +Gera classes `pulsar.schema.Record` dinamicamente a partir de dataclasses +Ou serializa dataclasses para JSON e usa o esquema JSON do Pulsar +Mantém a compatibilidade com implantações Pulsar existentes + +**Backend MQTT/Redis:** +Serialização direta de instâncias de dataclass para JSON +Use `dataclasses.asdict()` / `from_dict()` +Leve, não requer registro de esquema + +**Backend Kafka:** +Gera esquemas Avro a partir de definições de dataclass +Use o registro de esquema da Confluent +Serialização com segurança de tipo com suporte à evolução do esquema + +### Arquitetura + +``` +┌─────────────────────────────────────┐ +│ Application Code │ +│ - Uses dataclass schemas │ +│ - Backend-agnostic │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - get_pubsub() returns backend │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────────┐ ┌────▼──────────────┐ +│ PulsarBackend │ │ MQTTBackend │ +│ - JSON schema │ │ - JSON serialize │ +│ - or dynamic │ │ - Simple queues │ +│ Record gen │ │ │ +└─────────────────┘ └───────────────────┘ +``` + +### Detalhes de Implementação + +**1. Definições de esquema:** Dataclasses simples com dicas de tipo + `str`, `int`, `bool`, `float` para tipos primitivos + `list[T]` para arrays + `dict[str, T]` para mapas + Dataclasses aninhados para tipos complexos + +**2. Cada backend fornece:** + Serializador: `dataclass → bytes/wire format` + Deserializador: `bytes/wire format → dataclass` + Registro de esquema (se necessário, como Pulsar/Kafka) + +**3. Abstração de consumidor/produtor:** + Já existe (consumer.py, producer.py) + Atualizar para usar a serialização do backend + Remover importações diretas do Pulsar + +**4. Mapeamentos de tipo:** + Pulsar `String()` → Python `str` + Pulsar `Integer()` → Python `int` + Pulsar `Boolean()` → Python `bool` + Pulsar `Array(T)` → Python `list[T]` + Pulsar `Map(K, V)` → Python `dict[K, V]` + Pulsar `Double()` → Python `float` + Pulsar `Bytes()` → Python `bytes` + +### Caminho de Migração + +1. **Criar versões de dataclass** de todos os esquemas em `trustgraph/schema/` +2. **Atualizar classes de backend** (Consumer, Producer, Publisher, Subscriber) para usar a serialização fornecida pelo backend +3. **Implementar PulsarBackend** com esquema JSON ou geração dinâmica de Record +4. **Testar com Pulsar** para garantir a compatibilidade com versões anteriores com implantações existentes +5. **Adicionar novos backends** (MQTT, Kafka, Redis, etc.) conforme necessário +6. **Remover importações do Pulsar** de arquivos de esquema + +### Benefícios + +✅ **Nenhuma dependência de pub/sub** nas definições de esquema +✅ **Python padrão** - fácil de entender, tipar, documentar +✅ **Ferramentas modernas** - funciona com mypy, preenchimento automático de IDE, linters +✅ **Otimizado para backend** - cada backend usa a serialização nativa +✅ **Sem sobrecarga de tradução** - serialização direta, sem adaptadores +✅ **Segurança de tipo** - objetos reais com tipos adequados +✅ **Validação fácil** - pode usar Pydantic, se necessário + +### Desafios e Soluções + +**Desafio:** O `Record` do Pulsar tem validação de campo em tempo de execução +**Solução:** Use dataclasses Pydantic para validação, se necessário, ou recursos de dataclass Python 3.10+ com `__post_init__` + +**Desafio:** Alguns recursos específicos do Pulsar (como o tipo `Bytes`) +**Solução:** Mapear para o tipo `bytes` na dataclass, o backend lida com a codificação apropriadamente + +**Desafio:** Nomenclatura de tópicos (`persistent://tenant/namespace/topic`) +**Solução:** Abstrair nomes de tópicos em definições de esquema, o backend converte para o formato adequado + +**Desafio:** Evolução e versionamento de esquema +**Solução:** Cada backend lida com isso de acordo com suas capacidades (versões de esquema do Pulsar, registro de esquema do Kafka, etc.) + +**Desafio:** Tipos complexos aninhados +**Solução:** Use dataclasses aninhadas, os backends serializam/desserializam recursivamente + +### Decisões de Design + +1. **Dataclasses simples ou Pydantic?** + ✅ **Decisão: Usar dataclasses Python simples** + Mais simples, sem dependências adicionais + Validação não é necessária na prática + Mais fácil de entender e manter + +2. **Evolução de esquema:** + ✅ **Decisão: Nenhum mecanismo de versionamento necessário** + Os esquemas são estáveis e duradouros + As atualizações normalmente adicionam novos campos (compatíveis com versões anteriores) + Os backends lidam com a evolução do esquema de acordo com suas capacidades + +3. **Compatibilidade com versões anteriores:** + ✅ **Decisão: Alteração de versão principal, compatibilidade com versões anteriores não é necessária** + Será uma alteração disruptiva com instruções de migração + A separação limpa permite um melhor design + Um guia de migração será fornecido para implantações existentes + +4. **Tipos aninhados e estruturas complexas:** + ✅ **Decisão: Usar dataclasses aninhadas naturalmente** + Dataclasses Python lidam com o aninhamento perfeitamente + `list[T]` para arrays, `dict[K, V]` para mapas + Backends serializam/desserializam recursivamente + Exemplo: + ```python + @dataclass + class Value: + value: str + is_uri: bool + + @dataclass + class Triple: + s: Value # Nested dataclass + p: Value + o: Value + + @dataclass + class GraphQuery: + triples: list[Triple] # Array of nested dataclasses + metadata: dict[str, str] + ``` + +5. **Valores padrão e campos opcionais:** + ✅ **Decisão: Mistura de campos obrigatórios, valores padrão e campos opcionais** + Campos obrigatórios: Sem valor padrão + Campos com valores padrão: Sempre presentes, possuem um valor padrão razoável + Campos verdadeiramente opcionais: `T | None = None`, omitidos da serialização quando `None` + Exemplo: + ```python + @dataclass + class TextCompletionRequest: + system: str # Required, no default + prompt: str # Required, no default + streaming: bool = False # Optional with default value + metadata: dict | None = None # Truly optional, can be absent + ``` + + **Semântica de serialização importante:** + + Quando `metadata = None`: + ```json + { + "system": "...", + "prompt": "...", + "streaming": false + // metadata field NOT PRESENT + } + ``` + + Quando `metadata = {}` (explicitamente vazio): + ```json + { + "system": "...", + "prompt": "...", + "streaming": false, + "metadata": {} // Field PRESENT but empty + } + ``` + + **Diferença chave:** + `None` → campo ausente do JSON (não serializado) + Valor vazio (`{}`, `[]`, `""`) → campo presente com valor vazio + Isso importa semanticamente: "não fornecido" vs "explicitamente vazio" + Os backends de serialização devem ignorar os campos `None`, não codificá-los como `null` + +## Abordagem Rascunho 3: Detalhes de Implementação + +### Formato Genérico de Nomes de Filas + +Substitua os nomes de filas específicos do backend por um formato genérico que os backends possam mapear adequadamente. + +**Formato:** `{qos}/{tenant}/{namespace}/{queue-name}` + +Onde: +`qos`: Nível de Qualidade de Serviço + `q0` = melhor esforço (enviar e esquecer, sem confirmação) + `q1` = pelo menos uma vez (requer confirmação) + `q2` = exatamente uma vez (confirmação de duas fases) +`tenant`: Agrupamento lógico para multi-inquilinato +`namespace`: Sub-agrupamento dentro do inquilino +`queue-name`: Nome real da fila/tópico + +**Exemplos:** +``` +q1/tg/flow/text-completion-requests +q2/tg/config/config-push +q0/tg/metrics/stats +``` + +### Mapeamento de Tópicos do Backend + +Cada backend mapeia o formato genérico para o seu formato nativo: + +**Backend do Pulsar:** +```python +def map_topic(self, generic_topic: str) -> str: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS to persistence + persistence = 'persistent' if qos in ['q1', 'q2'] else 'non-persistent' + + # Return Pulsar URI: persistent://tg/flow/text-completion-requests + return f"{persistence}://{tenant}/{namespace}/{queue}" +``` + +**Backend MQTT:** +```python +def map_topic(self, generic_topic: str) -> tuple[str, int]: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS level + qos_level = {'q0': 0, 'q1': 1, 'q2': 2}[qos] + + # Build MQTT topic including tenant/namespace for proper namespacing + mqtt_topic = f"{tenant}/{namespace}/{queue}" + + return mqtt_topic, qos_level +``` + +### Função de Auxílio de Tópico Atualizada + +```python +# schema/core/topic.py +def topic(queue_name, qos='q1', tenant='tg', namespace='flow'): + """ + Create a generic topic identifier that can be mapped by backends. + + Args: + queue_name: The queue/topic name + qos: Quality of service + - 'q0' = best-effort (no ack) + - 'q1' = at-least-once (ack required) + - 'q2' = exactly-once (two-phase ack) + tenant: Tenant identifier for multi-tenancy + namespace: Namespace within tenant + + Returns: + Generic topic string: qos/tenant/namespace/queue_name + + Examples: + topic('my-queue') # q1/tg/flow/my-queue + topic('config', qos='q2', namespace='config') # q2/tg/config/config + """ + return f"{qos}/{tenant}/{namespace}/{queue_name}" +``` + +### Configuração e Inicialização + +**Argumentos de Linha de Comando + Variáveis de Ambiente:** + +```python +# In base/async_processor.py - add_args() method +@staticmethod +def add_args(parser): + # Pub/sub backend selection + parser.add_argument( + '--pubsub-backend', + default=os.getenv('PUBSUB_BACKEND', 'pulsar'), + choices=['pulsar', 'mqtt'], + help='Pub/sub backend (default: pulsar, env: PUBSUB_BACKEND)' + ) + + # Pulsar-specific configuration + parser.add_argument( + '--pulsar-host', + default=os.getenv('PULSAR_HOST', 'pulsar://localhost:6650'), + help='Pulsar host (default: pulsar://localhost:6650, env: PULSAR_HOST)' + ) + + parser.add_argument( + '--pulsar-api-key', + default=os.getenv('PULSAR_API_KEY', None), + help='Pulsar API key (env: PULSAR_API_KEY)' + ) + + parser.add_argument( + '--pulsar-listener', + default=os.getenv('PULSAR_LISTENER', None), + help='Pulsar listener name (env: PULSAR_LISTENER)' + ) + + # MQTT-specific configuration + parser.add_argument( + '--mqtt-host', + default=os.getenv('MQTT_HOST', 'localhost'), + help='MQTT broker host (default: localhost, env: MQTT_HOST)' + ) + + parser.add_argument( + '--mqtt-port', + type=int, + default=int(os.getenv('MQTT_PORT', '1883')), + help='MQTT broker port (default: 1883, env: MQTT_PORT)' + ) + + parser.add_argument( + '--mqtt-username', + default=os.getenv('MQTT_USERNAME', None), + help='MQTT username (env: MQTT_USERNAME)' + ) + + parser.add_argument( + '--mqtt-password', + default=os.getenv('MQTT_PASSWORD', None), + help='MQTT password (env: MQTT_PASSWORD)' + ) +``` + +**Função de Fábrica:** + +```python +# In base/pubsub.py or base/pubsub_factory.py +def get_pubsub(**config) -> PubSubBackend: + """ + Create and return a pub/sub backend based on configuration. + + Args: + config: Configuration dict from command-line args + Must include 'pubsub_backend' key + + Returns: + Backend instance (PulsarBackend, MQTTBackend, etc.) + """ + backend_type = config.get('pubsub_backend', 'pulsar') + + if backend_type == 'pulsar': + return PulsarBackend( + host=config.get('pulsar_host'), + api_key=config.get('pulsar_api_key'), + listener=config.get('pulsar_listener'), + ) + elif backend_type == 'mqtt': + return MQTTBackend( + host=config.get('mqtt_host'), + port=config.get('mqtt_port'), + username=config.get('mqtt_username'), + password=config.get('mqtt_password'), + ) + else: + raise ValueError(f"Unknown pub/sub backend: {backend_type}") +``` + +**Uso em AsyncProcessor:** + +```python +# In async_processor.py +class AsyncProcessor: + def __init__(self, **params): + self.id = params.get("id") + + # Create backend from config (replaces PulsarClient) + self.pubsub = get_pubsub(**params) + + # Rest of initialization... +``` + +### Interface de Backend + +```python +class PubSubBackend(Protocol): + """Protocol defining the interface all pub/sub backends must implement.""" + + def create_producer(self, topic: str, schema: type, **options) -> BackendProducer: + """ + Create a producer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + schema: Dataclass type for messages + options: Backend-specific options (e.g., chunking_enabled) + + Returns: + Backend-specific producer instance + """ + ... + + def create_consumer( + self, + topic: str, + subscription: str, + schema: type, + initial_position: str = 'latest', + consumer_type: str = 'shared', + **options + ) -> BackendConsumer: + """ + Create a consumer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + subscription: Subscription/consumer group name + schema: Dataclass type for messages + initial_position: 'earliest' or 'latest' (MQTT may ignore) + consumer_type: 'shared', 'exclusive', 'failover' (MQTT may ignore) + options: Backend-specific options + + Returns: + Backend-specific consumer instance + """ + ... + + def close(self) -> None: + """Close the backend connection.""" + ... +``` + +```python +class BackendProducer(Protocol): + """Protocol for backend-specific producer.""" + + def send(self, message: Any, properties: dict = {}) -> None: + """Send a message (dataclass instance) with optional properties.""" + ... + + def flush(self) -> None: + """Flush any buffered messages.""" + ... + + def close(self) -> None: + """Close the producer.""" + ... +``` + +```python +class BackendConsumer(Protocol): + """Protocol for backend-specific consumer.""" + + def receive(self, timeout_millis: int = 2000) -> Message: + """ + Receive a message from the topic. + + Raises: + TimeoutError: If no message received within timeout + """ + ... + + def acknowledge(self, message: Message) -> None: + """Acknowledge successful processing of a message.""" + ... + + def negative_acknowledge(self, message: Message) -> None: + """Negative acknowledge - triggers redelivery.""" + ... + + def unsubscribe(self) -> None: + """Unsubscribe from the topic.""" + ... + + def close(self) -> None: + """Close the consumer.""" + ... +``` + +```python +class Message(Protocol): + """Protocol for a received message.""" + + def value(self) -> Any: + """Get the deserialized message (dataclass instance).""" + ... + + def properties(self) -> dict: + """Get message properties/metadata.""" + ... +``` + +### Refatoração das Classes Existentes + +As classes existentes `Consumer`, `Producer`, `Publisher`, `Subscriber` permanecem em grande parte inalteradas: + +**Responsabilidades atuais (manter):** +Modelo de threading assíncrono e grupos de tarefas +Lógica de reconexão e tratamento de repetições +Coleta de métricas +Limitação de taxa +Gerenciamento de concorrência + +**Alterações necessárias:** +Remover importações diretas do Pulsar (`pulsar.schema`, `pulsar.InitialPosition`, etc.) +Aceitar `BackendProducer`/`BackendConsumer` em vez do cliente Pulsar +Delegar as operações reais de publicação/assinatura para instâncias de backend +Mapear conceitos genéricos para chamadas de backend + +**Exemplo de refatoração:** + +```python +# OLD - consumer.py +class Consumer: + def __init__(self, client, topic, subscriber, schema, ...): + self.client = client # Direct Pulsar client + # ... + + async def consumer_run(self): + # Uses pulsar.InitialPosition, pulsar.ConsumerType + self.consumer = self.client.subscribe( + topic=self.topic, + schema=JsonSchema(self.schema), + initial_position=pulsar.InitialPosition.Earliest, + consumer_type=pulsar.ConsumerType.Shared, + ) + +# NEW - consumer.py +class Consumer: + def __init__(self, backend_consumer, schema, ...): + self.backend_consumer = backend_consumer # Backend-specific consumer + self.schema = schema + # ... + + async def consumer_run(self): + # Backend consumer already created with right settings + # Just use it directly + while self.running: + msg = await asyncio.to_thread( + self.backend_consumer.receive, + timeout_millis=2000 + ) + await self.handle_message(msg) +``` + +### Comportamentos Específicos do Backend + +**Backend Pulsar:** +Mapeia `q0` → `non-persistent://`, `q1`/`q2` → `persistent://` +Suporta todos os tipos de consumidores (compartilhado, exclusivo, failover) +Suporta posição inicial (earliest/latest) +Reconhecimento nativo de mensagens +Suporte para registro de esquema + +**Backend MQTT:** +Mapeia `q0`/`q1`/`q2` → Níveis de QoS MQTT 0/1/2 +Inclui tenant/namespace no caminho do tópico para fins de namespace +Gera automaticamente IDs de cliente a partir de nomes de inscrição +Ignora a posição inicial (sem histórico de mensagens no MQTT básico) +Ignora o tipo de consumidor (o MQTT usa IDs de cliente, não grupos de consumidores) +Modelo de publicação/assinatura simples + +### Resumo das Decisões de Design + +1. ✅ **Nomeação genérica de filas**: Formato `qos/tenant/namespace/queue-name` +2. ✅ **QoS no ID da fila**: Determinado pela definição da fila, não pela configuração +3. ✅ **Reconexão**: Tratada pelas classes Consumer/Producer, não pelos backends +4. ✅ **Tópicos MQTT**: Incluem tenant/namespace para namespace adequado +5. ✅ **Histórico de mensagens**: O MQTT ignora o parâmetro `initial_position` (melhoria futura) +6. ✅ **IDs de cliente**: O backend MQTT gera automaticamente a partir do nome da inscrição + +### Melhorias Futuras + +**Histórico de mensagens MQTT:** +Poderia adicionar uma camada de persistência opcional (por exemplo, mensagens retidas, armazenamento externo) +Permitiria suportar `initial_position='earliest'` +Não é necessário para a implementação inicial + diff --git a/docs/tech-specs/pubsub.ru.md b/docs/tech-specs/pubsub.ru.md new file mode 100644 index 00000000..af1d4fcb --- /dev/null +++ b/docs/tech-specs/pubsub.ru.md @@ -0,0 +1,958 @@ +# Инфраструктура Pub/Sub + +## Обзор + +Этот документ содержит описание всех соединений между кодовой базой TrustGraph и инфраструктурой pub/sub. В настоящее время система жестко запрограммирована на использование Apache Pulsar. Этот анализ определяет все точки интеграции для будущей рефакторизации в сторону конфигурируемой абстракции pub/sub. + +## Текущее состояние: точки интеграции Pulsar + +### 1. Прямое использование клиента Pulsar + +**Местоположение:** `trustgraph-flow/trustgraph/gateway/service.py` + +API-шлюз напрямую импортирует и создает экземпляр клиента Pulsar: + +**Строка 20:** `import pulsar` +**Строки 54-61:** Прямая инициализация `pulsar.Client()` с необязательными параметрами `pulsar.AuthenticationToken()` +**Строки 33-35:** Конфигурация хоста Pulsar по умолчанию из переменных окружения +**Строки 178-192:** Аргументы командной строки для `--pulsar-host`, `--pulsar-api-key` и `--pulsar-listener` +**Строки 78, 124:** Передача `pulsar_client` в `ConfigReceiver` и `DispatcherManager` + +Это единственное место, где напрямую создается экземпляр клиента Pulsar за пределами слоя абстракции. + +### 2. Базовая платформа процессоров + +**Местоположение:** `trustgraph-base/trustgraph/base/async_processor.py` + +Базовый класс для всех процессоров обеспечивает подключение к Pulsar: + +**Строка 9:** `import _pulsar` (для обработки исключений) +**Строка 18:** `from . pubsub import PulsarClient` +**Строка 38:** Создание `pulsar_client_object = PulsarClient(**params)` +**Строки 104-108:** Свойства, предоставляющие доступ к `pulsar_host` и `pulsar_client` +**Строка 250:** Статический метод `add_args()` вызывает `PulsarClient.add_args(parser)` для аргументов командной строки +**Строки 223-225:** Обработка исключений для `_pulsar.Interrupted` + +Все процессоры наследуются от `AsyncProcessor`, что делает это центральной точкой интеграции. + +### 3. Абстракция потребителя + +**Местоположение:** `trustgraph-base/trustgraph/base/consumer.py` + +Потребляет сообщения из очередей и вызывает функции обработчиков: + +**Импорты Pulsar:** +**Строка 12:** `from pulsar.schema import JsonSchema` +**Строка 13:** `import pulsar` +**Строка 14:** `import _pulsar` + +**Использование, специфичное для Pulsar:** +**Строки 100, 102:** `pulsar.InitialPosition.Earliest` / `pulsar.InitialPosition.Latest` +**Строка 108:** Обертка `JsonSchema(self.schema)` +**Строка 110:** `pulsar.ConsumerType.Shared` +**Строки 104-111:** `self.client.subscribe()` с параметрами, специфичными для Pulsar +**Строки 143, 150, 65:** Методы `consumer.unsubscribe()` и `consumer.close()` +**Строка 162:** Исключение `_pulsar.Timeout` +**Строки 182, 205, 232:** `consumer.acknowledge()` / `consumer.negative_acknowledge()` + +**Спецификационный файл:** `trustgraph-base/trustgraph/base/consumer_spec.py` +**Строка 22:** Ссылка на `processor.pulsar_client` + +### 4. Абстракция производителя + +**Местоположение:** `trustgraph-base/trustgraph/base/producer.py` + +Отправляет сообщения в очереди: + +**Импорты Pulsar:** +**Строка 2:** `from pulsar.schema import JsonSchema` + +**Использование, специфичное для Pulsar:** +**Строка 49:** Обертка `JsonSchema(self.schema)` +**Строки 47-51:** `self.client.create_producer()` с параметрами, специфичными для Pulsar (тема, схема, включение фрагментации) +**Строки 31, 76:** Метод `producer.close()` +**Строки 64-65:** `producer.send()` с сообщением и свойствами + +**Спецификационный файл:** `trustgraph-base/trustgraph/base/producer_spec.py` +**Строка 18:** Ссылка на `processor.pulsar_client` + +### 5. Абстракция издателя + +**Местоположение:** `trustgraph-base/trustgraph/base/publisher.py` + +Асинхронная публикация сообщений с буферизацией очереди: + +**Импорты Pulsar:** +**Строка 2:** `from pulsar.schema import JsonSchema` +**Строка 6:** `import pulsar` + +**Использование, специфичное для Pulsar:** +**Строка 52:** Обертка `JsonSchema(self.schema)` +**Строки 50-54:** `self.client.create_producer()` с параметрами, специфичными для Pulsar +**Строки 101, 103:** `producer.send()` с сообщением и необязательными свойствами +**Строки 106-107:** Методы `producer.flush()` и `producer.close()` + +### 6. Абстракция подписчика + +**Местоположение:** `trustgraph-base/trustgraph/base/subscriber.py` + +Предоставляет распределение сообщений для нескольких получателей из очередей: + +**Импорт Pulsar:** +**Строка 6:** `from pulsar.schema import JsonSchema` +**Строка 8:** `import _pulsar` + +**Использование, специфичное для Pulsar:** +**Строка 55:** `JsonSchema(self.schema)` wrapper +**Строка 57:** `self.client.subscribe(**subscribe_args)` +**Строки 101, 136, 160, 167-172:** Исключения Pulsar: `_pulsar.Timeout`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +**Строки 159, 166, 170:** Методы потребителя: `negative_acknowledge()`, `unsubscribe()`, `close()` +**Строки 247, 251:** Подтверждение сообщений: `acknowledge()`, `negative_acknowledge()` + +**Файл спецификации:** `trustgraph-base/trustgraph/base/subscriber_spec.py` +**Строка 19:** Ссылается на `processor.pulsar_client` + +### 7. Система схем (Heart of Darkness) + +**Расположение:** `trustgraph-base/trustgraph/schema/` + +Каждая схема сообщения в системе определяется с использованием фреймворка схем Pulsar. + +**Основные примитивы:** `schema/core/primitives.py` +**Строка 2:** `from pulsar.schema import Record, String, Boolean, Array, Integer` +Все схемы наследуются от базового класса Pulsar `Record` +Все типы полей являются типами Pulsar: `String()`, `Integer()`, `Boolean()`, `Array()`, `Map()`, `Double()` + +**Примеры схем:** +`schema/services/llm.py` (Строка 2): `from pulsar.schema import Record, String, Array, Double, Integer, Boolean` +`schema/services/config.py` (Строка 2): `from pulsar.schema import Record, Bytes, String, Boolean, Array, Map, Integer` + +**Именование тем:** `schema/core/topic.py` +**Строки 2-3:** Формат темы: `{kind}://{tenant}/{namespace}/{topic}` +Эта структура URI специфична для Pulsar (например, `persistent://tg/flow/config`) + +**Влияние:** +Все определения сообщений запроса/ответа во всем коде используют схемы Pulsar +Это включает в себя сервисы для: config, flow, llm, prompt, query, storage, agent, collection, diagnosis, library, lookup, nlp_query, objects_query, retrieval, structured_query +Определения схем импортируются и используются во всех процессорах и сервисах. + +## Краткое описание + +### Зависимости Pulsar по категориям + +1. **Инициализация клиента:** + Прямая: `gateway/service.py` + Абстрактная: `async_processor.py` → `pubsub.py` (PulsarClient) + +2. **Транспортировка сообщений:** + Потребитель: `consumer.py`, `consumer_spec.py` + Издатель: `producer.py`, `producer_spec.py` + Публикатор: `publisher.py` + Подписчик: `subscriber.py`, `subscriber_spec.py` + +3. **Система схем:** + Базовые типы: `schema/core/primitives.py` + Все схемы сервисов: `schema/services/*.py` + Именование тем: `schema/core/topic.py` + +4. **Требуются концепции, специфичные для Pulsar:** + Сообщения на основе тем + Система схем (Record, типы полей) + Общие подписки + Подтверждение сообщений (положительное/отрицательное) + Позиционирование потребителя (самое начало/последнее) + Свойства сообщений + Начальные позиции и типы потребителей + Поддержка разбиения на части + Постоянные и непостоянные темы + +### Проблемы рефакторинга + +Хорошая новость: слой абстракции (Consumer, Producer, Publisher, Subscriber) обеспечивает четкую инкапсуляцию большинства взаимодействий с Pulsar. + +Проблемы: +1. **Всепроникающая система схем:** Каждое определение сообщения использует `pulsar.schema.Record` и типы Pulsar. +2. **Перечисления, специфичные для Pulsar:** `InitialPosition`, `ConsumerType` +3. **Исключения Pulsar:** `_pulsar.Timeout`, `_pulsar.Interrupted`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +4. **Сигнатуры методов:** `acknowledge()`, `negative_acknowledge()`, `subscribe()`, `create_producer()` и т.д. +5. **Формат URI темы:** Структура Pulsar `kind://tenant/namespace/topic` + +### Следующие шаги + +Чтобы сделать инфраструктуру публикации/подписки настраиваемой, нам нужно: + +1. Создать интерфейс абстракции для системы клиента/схем. +2. Абстрагировать перечисления и исключения, специфичные для Pulsar. +3. Создать обертки для схем или альтернативные определения схем. +4. Реализовать интерфейс как для Pulsar, так и для альтернативных систем (Kafka, RabbitMQ, Redis Streams и т.д.). +5. Обновить `pubsub.py`, чтобы он был настраиваемым и поддерживал несколько бэкендов. +6. Предоставить путь миграции для существующих развертываний. + +## Предварительный черновик подхода 1: Шаблон адаптера со слоем перевода схем + +### Ключевое понимание +**Система схем** является наиболее глубокой точкой интеграции - от нее зависит все остальное. Мы должны решить эту проблему в первую очередь, иначе нам придется переписывать весь код. + +### Стратегия: Минимальное нарушение с помощью адаптеров + +**1. Сохраняйте схемы Pulsar в качестве внутреннего представления** +Не переписывайте все определения схем. +Схемы остаются `pulsar.schema.Record` во внутреннем представлении. +Используйте адаптеры для преобразования данных на границе между нашим кодом и бэкендом pub/sub. + +**2. Создайте абстрактный слой pub/sub:** + +``` +┌─────────────────────────────────────┐ +│ Existing Code (unchanged) │ +│ - Uses Pulsar schemas internally │ +│ - Consumer/Producer/Publisher │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - Creates backend-specific client │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────┐ ┌────▼─────────┐ +│ PulsarAdapter│ │ KafkaAdapter │ etc... +│ (passthrough)│ │ (translates) │ +└──────────────┘ └──────────────┘ +``` + +**3. Определение абстрактных интерфейсов:** +`PubSubClient` - клиентское подключение +`PubSubProducer` - отправка сообщений +`PubSubConsumer` - получение сообщений +`SchemaAdapter` - преобразование схем Pulsar в/из JSON или форматы, специфичные для бэкенда + +**4. Детали реализации:** + +Для **адаптера Pulsar**: Практически без изменений, минимальное преобразование. + +Для **других бэкендов** (Kafka, RabbitMQ и т.д.): +Сериализация объектов Pulsar Record в JSON/байты. +Отображение понятий, таких как: + `InitialPosition.Earliest/Latest` → auto.offset.reset в Kafka + `acknowledge()` → commit в Kafka + `negative_acknowledge()` → Паттерн повторной отправки или DLQ (Dead Letter Queue) + URI тем → Имена тем, специфичные для бэкенда. + +### Анализ + +**Преимущества:** +✅ Минимальные изменения существующего кода. +✅ Схемы остаются без изменений (без необходимости масштабной переработки). +✅ Постепенный путь миграции. +✅ Пользователи Pulsar не заметят разницы. +✅ Новые бэкенды добавляются через адаптеры. + +**Недостатки:** +⚠️ Все еще присутствует зависимость от Pulsar (для определений схем). +⚠️ Некоторые несовместимости при преобразовании понятий. + +### Альтернативное решение + +Создать **систему схем TrustGraph**, которая является агностической к pub/sub (используя dataclasses или Pydantic), а затем генерировать схемы Pulsar/Kafka/и т.д. из нее. Это требует переписывания каждого файла схемы и может привести к несовместимым изменениям. + +### Рекомендации для версии 1 + +Начните с **подхода с использованием адаптеров**, потому что: +1. Это практичный подход, который работает с существующим кодом. +2. Подтверждает концепцию с минимальным риском. +3. Может быть усовершенствован до нативной системы схем в будущем, если это необходимо. +4. Управление конфигурацией: одна переменная окружения переключает бэкенды. + +## Подход, версия 2: Система схем, независимая от бэкенда, с использованием dataclasses + +### Основная концепция + +Используйте Python **dataclasses** в качестве нейтрального формата определения схемы. Каждый бэкенд pub/sub предоставляет свой собственный механизм сериализации/десериализации для dataclasses, что устраняет необходимость сохранения схем Pulsar в кодовой базе. + +### Полиморфизм схем на уровне фабрики + +Вместо преобразования схем Pulsar, **каждый бэкенд предоставляет собственную обработку схем**, которая работает со стандартными Python dataclasses. + +### Поток публикации + +```python +# 1. Get the configured backend from factory +pubsub = get_pubsub() # Returns PulsarBackend, MQTTBackend, etc. + +# 2. Get schema class from the backend +# (Can be imported directly - backend-agnostic) +from trustgraph.schema.services.llm import TextCompletionRequest + +# 3. Create a producer/publisher for a specific topic +producer = pubsub.create_producer( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend what schema to use +) + +# 4. Create message instances (same API regardless of backend) +request = TextCompletionRequest( + system="You are helpful", + prompt="Hello world", + streaming=False +) + +# 5. Send the message +producer.send(request) # Backend serializes appropriately +``` + +### Поток пользователей + +```python +# 1. Get the configured backend +pubsub = get_pubsub() + +# 2. Create a consumer +consumer = pubsub.subscribe( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend how to deserialize +) + +# 3. Receive and deserialize +msg = consumer.receive() +request = msg.value() # Returns TextCompletionRequest dataclass instance + +# 4. Use the data (type-safe access) +print(request.system) # "You are helpful" +print(request.prompt) # "Hello world" +print(request.streaming) # False +``` + +### Что происходит за кулисами + +**Для бэкенда Pulsar:** +`create_producer()` → создает производителя Pulsar с JSON-схемой или динамически генерируемой записью +`send(request)` → сериализует dataclass в формат JSON/Pulsar, отправляет в Pulsar +`receive()` → получает сообщение Pulsar, десериализует обратно в dataclass + +**Для бэкенда MQTT:** +`create_producer()` → подключается к MQTT-брокеру, регистрация схемы не требуется +`send(request)` → преобразует dataclass в JSON, публикует в MQTT-топик +`receive()` → подписывается на MQTT-топик, десериализует JSON в dataclass + +**Для бэкенда Kafka:** +`create_producer()` → создает производителя Kafka, регистрирует схему Avro, если необходимо +`send(request)` → сериализует dataclass в формат Avro, отправляет в Kafka +`receive()` → получает сообщение Kafka, десериализует Avro обратно в dataclass + +### Ключевые моменты проектирования + +1. **Создание объекта схемы**: Экземпляр dataclass (`TextCompletionRequest(...)`) идентичен независимо от бэкенда +2. **Бэкенд обрабатывает кодирование**: Каждый бэкенд знает, как сериализовать свой dataclass в формат для передачи данных +3. **Определение схемы при создании**: При создании производителя/потребителя вы указываете тип схемы +4. **Сохранение типобезопасности**: Вы получаете правильный объект `TextCompletionRequest`, а не словарь +5. **Отсутствие утечек бэкенда**: Код приложения никогда не импортирует библиотеки, специфичные для бэкенда + +### Пример преобразования + +**Текущий (специфичный для Pulsar):** +```python +# schema/services/llm.py +from pulsar.schema import Record, String, Boolean, Integer + +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() +``` + +**Новое (независимое от бэкенда):** +```python +# schema/services/llm.py +from dataclasses import dataclass + +@dataclass +class TextCompletionRequest: + system: str + prompt: str + streaming: bool = False +``` + +### Интеграция с бэкендом + +Каждый бэкенд отвечает за сериализацию/десериализацию dataclasses: + +**Бэкенд Pulsar:** +Динамически генерирует классы `pulsar.schema.Record` из dataclasses +Или сериализует dataclasses в JSON и использует JSON-схему Pulsar +Обеспечивает совместимость с существующими развертываниями Pulsar + +**Бэкенд MQTT/Redis:** +Прямая сериализация в JSON экземпляров dataclass +Использует `dataclasses.asdict()` / `from_dict()` +Легковесный, не требуется реестр схем + +**Бэкенд Kafka:** +Генерирует схемы Avro из определений dataclass +Использует реестр схем Confluent +Типобезопасная сериализация с поддержкой эволюции схемы + +### Архитектура + +``` +┌─────────────────────────────────────┐ +│ Application Code │ +│ - Uses dataclass schemas │ +│ - Backend-agnostic │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - get_pubsub() returns backend │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────────┐ ┌────▼──────────────┐ +│ PulsarBackend │ │ MQTTBackend │ +│ - JSON schema │ │ - JSON serialize │ +│ - or dynamic │ │ - Simple queues │ +│ Record gen │ │ │ +└─────────────────┘ └───────────────────┘ +``` + +### Детали реализации + +**1. Определение схем:** Простые классы данных с подсказками типов + `str`, `int`, `bool`, `float` для примитивов + `list[T]` для массивов + `dict[str, T]` для словарей + Вложенные классы данных для сложных типов + +**2. Каждый бэкенд предоставляет:** + Сериализатор: `dataclass → bytes/wire format` + Десериализатор: `bytes/wire format → dataclass` + Регистрация схемы (если необходимо, например, для Pulsar/Kafka) + +**3. Абстракция потребителя/производителя:** + Уже существует (consumer.py, producer.py) + Обновление для использования сериализации бэкенда + Удаление прямых импортов Pulsar + +**4. Отображение типов:** + Pulsar `String()` → Python `str` + Pulsar `Integer()` → Python `int` + Pulsar `Boolean()` → Python `bool` + Pulsar `Array(T)` → Python `list[T]` + Pulsar `Map(K, V)` → Python `dict[K, V]` + Pulsar `Double()` → Python `float` + Pulsar `Bytes()` → Python `bytes` + +### Путь миграции + +1. **Создайте версии классов данных** для всех схем в `trustgraph/schema/` +2. **Обновите классы бэкенда** (Consumer, Producer, Publisher, Subscriber) для использования сериализации, предоставляемой бэкендом +3. **Реализуйте PulsarBackend** с использованием JSON-схемы или динамической генерации записей +4. **Протестируйте с Pulsar**, чтобы обеспечить обратную совместимость с существующими развертываниями +5. **Добавьте новые бэкенды** (MQTT, Kafka, Redis и т. д.) по мере необходимости +6. **Удалите импорты Pulsar** из файлов схем + +### Преимущества + +✅ **Отсутствие зависимости от pub/sub** в определениях схем +✅ **Стандартный Python** - легко понять, проверить типы, документировать +✅ **Современные инструменты** - работает с mypy, автодополнением IDE, линтерами +✅ **Оптимизировано для бэкенда** - каждый бэкенд использует собственную сериализацию +✅ **Отсутствие накладных расходов на преобразование** - прямая сериализация, без адаптеров +✅ **Безопасность типов** - реальные объекты с правильными типами +✅ **Простая проверка** - можно использовать Pydantic, если необходимо + +### Проблемы и решения + +**Проблема:** У `Record` Pulsar есть проверка полей во время выполнения +**Решение:** Используйте классы данных Pydantic для проверки, если это необходимо, или функции Python 3.10+ для классов данных с `__post_init__` + +**Проблема:** Некоторые специфичные для Pulsar функции (например, тип `Bytes`) +**Решение:** Отобразите на тип `bytes` в классе данных, бэкенд обрабатывает кодирование соответствующим образом + +**Проблема:** Именование тем (`persistent://tenant/namespace/topic`) +**Решение:** Абстрагируйте имена тем в определениях схем, бэкенд преобразует в правильный формат + +**Проблема:** Эволюция и версионирование схем +**Решение:** Каждый бэкенд обрабатывает это в соответствии со своими возможностями (версии схем Pulsar, реестр схем Kafka и т. д.) + +**Проблема:** Вложенные сложные типы +**Решение:** Используйте вложенные классы данных, бэкенды рекурсивно сериализуют/десериализуют + +### Принятые решения + +1. **Обычные классы данных или Pydantic?** + ✅ **Решение: Используйте обычные классы данных Python** + Проще, без дополнительных зависимостей + Проверка не требуется на практике + Легче понять и поддерживать + +2. **Эволюция схемы:** + ✅ **Решение: Механизм версионирования не требуется** + Схемы стабильны и долговечны + Обновления обычно добавляют новые поля (обратная совместимость) + Бэкенды обрабатывают эволюцию схемы в соответствии со своими возможностями + +3. **Обратная совместимость:** + ✅ **Решение: Изменение основной версии, обратная совместимость не требуется** + Это будет изменение, нарушающее обратную совместимость, с инструкциями по миграции + Чистый разрыв позволяет лучше спроектировать систему + Будет предоставлено руководство по миграции для существующих развертываний + +4. **Вложенные типы и сложные структуры:** + ✅ **Решение: Используйте вложенные классы данных естественным образом** + Классы данных Python отлично справляются с вложенностью + `list[T]` для массивов, `dict[K, V]` для словарей + Бэкенды рекурсивно сериализуют/десериализуют + Пример: + ```python + @dataclass + class Value: + value: str + is_uri: bool + + @dataclass + class Triple: + s: Value # Nested dataclass + p: Value + o: Value + + @dataclass + class GraphQuery: + triples: list[Triple] # Array of nested dataclasses + metadata: dict[str, str] + ``` + +5. **Значения по умолчанию и необязательные поля:** + ✅ **Решение: Комбинация обязательных, полей со значениями по умолчанию и необязательных полей** + Обязательные поля: Не имеют значения по умолчанию. + Поля со значениями по умолчанию: Всегда присутствуют, имеют разумные значения по умолчанию. + Действительно необязательные поля: `T | None = None`, опускаются при сериализации, когда `None` + Пример: + ```python + @dataclass + class TextCompletionRequest: + system: str # Required, no default + prompt: str # Required, no default + streaming: bool = False # Optional with default value + metadata: dict | None = None # Truly optional, can be absent + ``` + + **Важные семантические аспекты сериализации:** + + Когда `metadata = None`: + ```json + { + "system": "...", + "prompt": "...", + "streaming": false + // metadata field NOT PRESENT + } + ``` + + Когда `metadata = {}` (явно пусто): + ```json + { + "system": "...", + "prompt": "...", + "streaming": false, + "metadata": {} // Field PRESENT but empty + } + ``` + + **Ключевое отличие:** + `None` → поле отсутствует в JSON (не сериализуется) + Пустое значение (`{}`, `[]`, `""`) → поле присутствует со значением "пусто" + Это имеет семантическое значение: "не предоставлено" против "явно пусто" + Механизмы сериализации должны пропускать поля `None`, а не кодировать их как `null` + +## Предварительный вариант 3: Детали реализации + +### Универсальный формат именования очередей + +Замените специфичные для каждого бэкенда имена очередей на универсальный формат, который бэкенды могут сопоставить соответствующим образом. + +**Формат:** `{qos}/{tenant}/{namespace}/{queue-name}` + +Где: +`qos`: Уровень качества обслуживания (QoS) + `q0` = best-effort (отправка без подтверждения) + `q1` = at-least-once (требуется подтверждение) + `q2` = exactly-once (двухфазное подтверждение) +`tenant`: Логическая группировка для многопользовательской среды +`namespace`: Подгруппа внутри арендатора +`queue-name`: Фактическое имя очереди/топика + +**Примеры:** +``` +q1/tg/flow/text-completion-requests +q2/tg/config/config-push +q0/tg/metrics/stats +``` + +### Отображение тем для бэкенда + +Каждый бэкенд преобразует общий формат в свой собственный формат: + +**Бэкенд Pulsar:** +```python +def map_topic(self, generic_topic: str) -> str: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS to persistence + persistence = 'persistent' if qos in ['q1', 'q2'] else 'non-persistent' + + # Return Pulsar URI: persistent://tg/flow/text-completion-requests + return f"{persistence}://{tenant}/{namespace}/{queue}" +``` + +**Бэкэнд MQTT:** +```python +def map_topic(self, generic_topic: str) -> tuple[str, int]: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS level + qos_level = {'q0': 0, 'q1': 1, 'q2': 2}[qos] + + # Build MQTT topic including tenant/namespace for proper namespacing + mqtt_topic = f"{tenant}/{namespace}/{queue}" + + return mqtt_topic, qos_level +``` + +### Обновленная вспомогательная функция для темы + +```python +# schema/core/topic.py +def topic(queue_name, qos='q1', tenant='tg', namespace='flow'): + """ + Create a generic topic identifier that can be mapped by backends. + + Args: + queue_name: The queue/topic name + qos: Quality of service + - 'q0' = best-effort (no ack) + - 'q1' = at-least-once (ack required) + - 'q2' = exactly-once (two-phase ack) + tenant: Tenant identifier for multi-tenancy + namespace: Namespace within tenant + + Returns: + Generic topic string: qos/tenant/namespace/queue_name + + Examples: + topic('my-queue') # q1/tg/flow/my-queue + topic('config', qos='q2', namespace='config') # q2/tg/config/config + """ + return f"{qos}/{tenant}/{namespace}/{queue_name}" +``` + +### Конфигурация и инициализация + +**Аргументы командной строки + переменные окружения:** + +```python +# In base/async_processor.py - add_args() method +@staticmethod +def add_args(parser): + # Pub/sub backend selection + parser.add_argument( + '--pubsub-backend', + default=os.getenv('PUBSUB_BACKEND', 'pulsar'), + choices=['pulsar', 'mqtt'], + help='Pub/sub backend (default: pulsar, env: PUBSUB_BACKEND)' + ) + + # Pulsar-specific configuration + parser.add_argument( + '--pulsar-host', + default=os.getenv('PULSAR_HOST', 'pulsar://localhost:6650'), + help='Pulsar host (default: pulsar://localhost:6650, env: PULSAR_HOST)' + ) + + parser.add_argument( + '--pulsar-api-key', + default=os.getenv('PULSAR_API_KEY', None), + help='Pulsar API key (env: PULSAR_API_KEY)' + ) + + parser.add_argument( + '--pulsar-listener', + default=os.getenv('PULSAR_LISTENER', None), + help='Pulsar listener name (env: PULSAR_LISTENER)' + ) + + # MQTT-specific configuration + parser.add_argument( + '--mqtt-host', + default=os.getenv('MQTT_HOST', 'localhost'), + help='MQTT broker host (default: localhost, env: MQTT_HOST)' + ) + + parser.add_argument( + '--mqtt-port', + type=int, + default=int(os.getenv('MQTT_PORT', '1883')), + help='MQTT broker port (default: 1883, env: MQTT_PORT)' + ) + + parser.add_argument( + '--mqtt-username', + default=os.getenv('MQTT_USERNAME', None), + help='MQTT username (env: MQTT_USERNAME)' + ) + + parser.add_argument( + '--mqtt-password', + default=os.getenv('MQTT_PASSWORD', None), + help='MQTT password (env: MQTT_PASSWORD)' + ) +``` + +**Фабричная функция:** + +```python +# In base/pubsub.py or base/pubsub_factory.py +def get_pubsub(**config) -> PubSubBackend: + """ + Create and return a pub/sub backend based on configuration. + + Args: + config: Configuration dict from command-line args + Must include 'pubsub_backend' key + + Returns: + Backend instance (PulsarBackend, MQTTBackend, etc.) + """ + backend_type = config.get('pubsub_backend', 'pulsar') + + if backend_type == 'pulsar': + return PulsarBackend( + host=config.get('pulsar_host'), + api_key=config.get('pulsar_api_key'), + listener=config.get('pulsar_listener'), + ) + elif backend_type == 'mqtt': + return MQTTBackend( + host=config.get('mqtt_host'), + port=config.get('mqtt_port'), + username=config.get('mqtt_username'), + password=config.get('mqtt_password'), + ) + else: + raise ValueError(f"Unknown pub/sub backend: {backend_type}") +``` + +**Использование в AsyncProcessor:** + +```python +# In async_processor.py +class AsyncProcessor: + def __init__(self, **params): + self.id = params.get("id") + + # Create backend from config (replaces PulsarClient) + self.pubsub = get_pubsub(**params) + + # Rest of initialization... +``` + +### Интерфейс бэкенда + +```python +class PubSubBackend(Protocol): + """Protocol defining the interface all pub/sub backends must implement.""" + + def create_producer(self, topic: str, schema: type, **options) -> BackendProducer: + """ + Create a producer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + schema: Dataclass type for messages + options: Backend-specific options (e.g., chunking_enabled) + + Returns: + Backend-specific producer instance + """ + ... + + def create_consumer( + self, + topic: str, + subscription: str, + schema: type, + initial_position: str = 'latest', + consumer_type: str = 'shared', + **options + ) -> BackendConsumer: + """ + Create a consumer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + subscription: Subscription/consumer group name + schema: Dataclass type for messages + initial_position: 'earliest' or 'latest' (MQTT may ignore) + consumer_type: 'shared', 'exclusive', 'failover' (MQTT may ignore) + options: Backend-specific options + + Returns: + Backend-specific consumer instance + """ + ... + + def close(self) -> None: + """Close the backend connection.""" + ... +``` + +```python +class BackendProducer(Protocol): + """Protocol for backend-specific producer.""" + + def send(self, message: Any, properties: dict = {}) -> None: + """Send a message (dataclass instance) with optional properties.""" + ... + + def flush(self) -> None: + """Flush any buffered messages.""" + ... + + def close(self) -> None: + """Close the producer.""" + ... +``` + +```python +class BackendConsumer(Protocol): + """Protocol for backend-specific consumer.""" + + def receive(self, timeout_millis: int = 2000) -> Message: + """ + Receive a message from the topic. + + Raises: + TimeoutError: If no message received within timeout + """ + ... + + def acknowledge(self, message: Message) -> None: + """Acknowledge successful processing of a message.""" + ... + + def negative_acknowledge(self, message: Message) -> None: + """Negative acknowledge - triggers redelivery.""" + ... + + def unsubscribe(self) -> None: + """Unsubscribe from the topic.""" + ... + + def close(self) -> None: + """Close the consumer.""" + ... +``` + +```python +class Message(Protocol): + """Protocol for a received message.""" + + def value(self) -> Any: + """Get the deserialized message (dataclass instance).""" + ... + + def properties(self) -> dict: + """Get message properties/metadata.""" + ... +``` + +### Рефакторинг существующих классов + +Существующие классы `Consumer`, `Producer`, `Publisher`, `Subscriber` остаются в основном без изменений: + +**Текущие обязанности (сохранить):** +Асинхронная модель потоков и группы задач +Логика повторного подключения и обработка повторных попыток +Сбор метрик +Ограничение скорости +Управление параллелизмом + +**Необходимые изменения:** +Удалить прямые импорты Pulsar (`pulsar.schema`, `pulsar.InitialPosition` и т.д.) +Принимать `BackendProducer`/`BackendConsumer` вместо клиента Pulsar +Передавать фактические операции публикации/подписки на экземпляры бэкенда +Отображать общие концепции на вызовы бэкенда + +**Пример рефакторинга:** + +```python +# OLD - consumer.py +class Consumer: + def __init__(self, client, topic, subscriber, schema, ...): + self.client = client # Direct Pulsar client + # ... + + async def consumer_run(self): + # Uses pulsar.InitialPosition, pulsar.ConsumerType + self.consumer = self.client.subscribe( + topic=self.topic, + schema=JsonSchema(self.schema), + initial_position=pulsar.InitialPosition.Earliest, + consumer_type=pulsar.ConsumerType.Shared, + ) + +# NEW - consumer.py +class Consumer: + def __init__(self, backend_consumer, schema, ...): + self.backend_consumer = backend_consumer # Backend-specific consumer + self.schema = schema + # ... + + async def consumer_run(self): + # Backend consumer already created with right settings + # Just use it directly + while self.running: + msg = await asyncio.to_thread( + self.backend_consumer.receive, + timeout_millis=2000 + ) + await self.handle_message(msg) +``` + +### Специфические для бэкенда особенности + +**Бэкенд Pulsar:** +Отображает `q0` → `non-persistent://`, `q1`/`q2` → `persistent://` +Поддерживает все типы потребителей (shared, exclusive, failover) +Поддерживает начальную позицию (earliest/latest) +Поддержка подтверждения получения сообщений +Поддержка реестра схем + +**Бэкенд MQTT:** +Отображает `q0`/`q1`/`q2` → уровни качества обслуживания (QoS) MQTT 0/1/2 +Включает арендатора/пространство имен в путь темы для обеспечения разделения имен +Автоматически генерирует идентификаторы клиентов из имен подписок +Игнорирует начальную позицию (нет истории сообщений в базовом MQTT) +Игнорирует тип потребителя (MQTT использует идентификаторы клиентов, а не группы потребителей) +Простая модель публикации/подписки + +### Краткое описание принятых решений + +1. ✅ **Универсальное именование очередей**: формат `qos/tenant/namespace/queue-name` +2. ✅ **QoS в идентификаторе очереди**: определяется определением очереди, а не конфигурацией +3. ✅ **Повторное подключение**: обрабатывается классами Consumer/Producer, а не бэкендами +4. ✅ **Темы MQTT**: включают арендатора/пространство имен для правильного разделения имен +5. ✅ **История сообщений**: MQTT игнорирует параметр `initial_position` (будущее улучшение) +6. ✅ **Идентификаторы клиентов**: бэкенд MQTT автоматически генерирует из имени подписки + +### Будущие улучшения + +**История сообщений MQTT:** +Можно добавить необязательный слой постоянного хранения (например, сохраненные сообщения, внешний хранилище) +Это позволит поддерживать `initial_position='earliest'` +Не требуется для первоначальной реализации + diff --git a/docs/tech-specs/pubsub.sw.md b/docs/tech-specs/pubsub.sw.md new file mode 100644 index 00000000..98401c2f --- /dev/null +++ b/docs/tech-specs/pubsub.sw.md @@ -0,0 +1,958 @@ +# Mifumo ya Uwasilishaji na Ufuatiliaji (Pub/Sub) + +## Muhtasari + +Hati hii inaorodhesha miunganisho yote kati ya mfumo wa TrustGraph na miundomino ya uwasilishaji na ufuatiliaji. Kwa sasa, mfumo huu umewekwa ili kutumia Apache Pulsar. Uchunguzi huu unaeleza maeneo yote ya kuunganisha ili kutoa taarifa kwa urekebishaji wa baadaye kuelekea uainishaji wa uwasilishaji na ufuatiliaji unaoweza kusanidiwa. + +## Hali ya Sasa: Maeneo ya Kuunganisha ya Pulsar + +### 1. Matumizi ya Moja kwa Moja ya Mteja wa Pulsar + +**Mahali:** `trustgraph-flow/trustgraph/gateway/service.py` + +Lango la API huleta na kuunda mteja wa Pulsar moja kwa moja: + +**Laini ya 20:** `import pulsar` +**Laini za 54-61:** Uundaji wa moja kwa moja wa `pulsar.Client()` pamoja na `pulsar.AuthenticationToken()` inayohitajika. +**Laini za 33-35:** Usanidi chaguo-msingi wa hosti wa Pulsar kutoka kwa vigezo vya mazingira. +**Laini za 178-192:** Vigezo vya CLI kwa `--pulsar-host`, `--pulsar-api-key`, na `--pulsar-listener`. +**Laini za 78, 124:** Hupitisha `pulsar_client` kwa `ConfigReceiver` na `DispatcherManager`. + +Hii ndio eneo pekee ambalo huunda mteja wa Pulsar moja kwa moja nje ya safu ya uainishaji. + +### 2. Muundo wa Msingi wa Mchakato + +**Mahali:** `trustgraph-base/trustgraph/base/async_processor.py` + +Darasa la msingi kwa mchakato wote hutoa uwezo wa kuunganisha na Pulsar: + +**Laini ya 9:** `import _pulsar` (kwa usimamizi wa makosa) +**Laini ya 18:** `from . pubsub import PulsarClient` +**Laini ya 38:** Huunda `pulsar_client_object = PulsarClient(**params)` +**Laini za 104-108:** Vipengele ambavyo huonyesha `pulsar_host` na `pulsar_client` +**Laini ya 250:** Njia ya tuli `add_args()` huita `PulsarClient.add_args(parser)` kwa vigezo vya CLI +**Laini za 223-225:** Usimamizi wa makosa kwa `_pulsar.Interrupted` + +Mchakato wote hurithi kutoka kwa `AsyncProcessor`, na hivyo kuwa eneo kuu la kuunganisha. + +### 3. Uainishaji wa Mtumiaji + +**Mahali:** `trustgraph-base/trustgraph/base/consumer.py` + +Huchukua meseji kutoka kwa folyo na kutoa kazi za utendaji: + +**Uingizaji wa Pulsar:** +**Laini ya 12:** `from pulsar.schema import JsonSchema` +**Laini ya 13:** `import pulsar` +**Laini ya 14:** `import _pulsar` + +**Matumizi maalum ya Pulsar:** +**Laini za 100, 102:** `pulsar.InitialPosition.Earliest` / `pulsar.InitialPosition.Latest` +**Laini ya 108:** `JsonSchema(self.schema)` wrapper +**Laini ya 110:** `pulsar.ConsumerType.Shared` +**Laini za 104-111:** `self.client.subscribe()` pamoja na vigezo maalum ya Pulsar +**Laini za 143, 150, 65:** `consumer.unsubscribe()` na `consumer.close()` methods +**Laini ya 162:** `_pulsar.Timeout` exception +**Laini za 182, 205, 232:** `consumer.acknowledge()` / `consumer.negative_acknowledge()` + +**Faili ya spec:** `trustgraph-base/trustgraph/base/consumer_spec.py` +**Laini ya 22:** Inarejelea `processor.pulsar_client` + +### 4. Uainishaji wa Mtume + +**Mahali:** `trustgraph-base/trustgraph/base/producer.py` + +Hutuma meseji kwa folyo: + +**Uingizaji wa Pulsar:** +**Laini ya 2:** `from pulsar.schema import JsonSchema` + +**Matumizi maalum ya Pulsar:** +**Laini ya 49:** `JsonSchema(self.schema)` wrapper +**Laini za 47-51:** `self.client.create_producer()` pamoja na vigezo maalum ya Pulsar (mada, schema, chunking_enabled) +**Laini za 31, 76:** `producer.close()` method +**Laini za 64-65:** `producer.send()` pamoja na meseji na vipengele + +**Faili ya spec:** `trustgraph-base/trustgraph/base/producer_spec.py` +**Laini ya 18:** Inarejelea `processor.pulsar_client` + +### 5. Uainishaji wa Mchapishaji + +**Mahali:** `trustgraph-base/trustgraph/base/publisher.py` + +Uchapishaji wa meseji usiohusisha na uwekaji wa folyo: + +**Uingizaji wa Pulsar:** +**Laini ya 2:** `from pulsar.schema import JsonSchema` +**Laini ya 6:** `import pulsar` + +**Matumizi maalum ya Pulsar:** +**Laini ya 52:** `JsonSchema(self.schema)` wrapper +**Laini za 50-54:** `self.client.create_producer()` pamoja na vigezo maalum ya Pulsar +**Laini za 101, 103:** `producer.send()` pamoja na meseji na vipengele vya hiari +**Laini za 106-107:** `producer.flush()` na `producer.close()` methods + +### 6. Uainishaji wa Mlisani + +**Mahali:** `trustgraph-base/trustgraph/base/subscriber.py` + +Inatoa usambazaji wa ujumbe kwa wapokeaji wengi kutoka kwa folyo: + +**Uingizaji kutoka Pulsar:** +**Laini ya 6:** `from pulsar.schema import JsonSchema` +**Laini ya 8:** `import _pulsar` + +**Matumizi maalum ya Pulsar:** +**Laini ya 55:** `JsonSchema(self.schema)` wrapper +**Laini ya 57:** `self.client.subscribe(**subscribe_args)` +**Laini 101, 136, 160, 167-172:** Vizuizi vya Pulsar: `_pulsar.Timeout`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +**Laini 159, 166, 170:** Mbinu za mtumiaji: `negative_acknowledge()`, `unsubscribe()`, `close()` +**Laini 247, 251:** Utambuzi wa ujumbe: `acknowledge()`, `negative_acknowledge()` + +**Faili ya spec:** `trustgraph-base/trustgraph/base/subscriber_spec.py` +**Laini ya 19:** Inarejelea `processor.pulsar_client` + +### 7. Mfumo wa Schemas (Heart of Darkness) + +**Mahali:** `trustgraph-base/trustgraph/schema/` + +Schemas kila ujumbe katika mfumo huu imefafanuliwa kwa kutumia mfumo wa schemas wa Pulsar. + +**Vipengele muhimu:** `schema/core/primitives.py` +**Laini ya 2:** `from pulsar.schema import Record, String, Boolean, Array, Integer` +Schemas zote hurithi kutoka kwa darasa la msingi la Pulsar `Record` +Aina zote za sehemu ni aina za Pulsar: `String()`, `Integer()`, `Boolean()`, `Array()`, `Map()`, `Double()` + +**Sampuli za schemas:** +`schema/services/llm.py` (Laini ya 2): `from pulsar.schema import Record, String, Array, Double, Integer, Boolean` +`schema/services/config.py` (Laini ya 2): `from pulsar.schema import Record, Bytes, String, Boolean, Array, Map, Integer` + +**Jina la mada:** `schema/core/topic.py` +**Laini 2-3:** Muundo wa mada: `{kind}://{tenant}/{namespace}/{topic}` +Muundo huu wa URI ni maalum kwa Pulsar (k.m.e., `persistent://tg/flow/config`) + +**Athari:** +Ufafanuzi wote wa ujumbe wa ombi/jibu katika msimbo wote hutumia schemas za Pulsar +Hii inajumuisha huduma za: config, flow, llm, prompt, query, storage, agent, collection, diagnosis, library, lookup, nlp_query, objects_query, retrieval, structured_query +Ufafanuzi wa schemas huingizwa na kutumika kwa kina katika processors na huduma zote + +## Muhtasari + +### Utegemezi wa Pulsar kwa Kategoria + +1. **Uundaji wa mteja:** + Moja kwa moja: `gateway/service.py` + Imefichwa: `async_processor.py` → `pubsub.py` (PulsarClient) + +2. **Usafirishaji wa ujumbe:** + Mtumiaji: `consumer.py`, `consumer_spec.py` + Mtayarishaji: `producer.py`, `producer_spec.py` + Mchapishaji: `publisher.py` + Msubiri: `subscriber.py`, `subscriber_spec.py` + +3. **Mfumo wa schemas:** + Aina za msingi: `schema/core/primitives.py` + Schemas zote za huduma: `schema/services/*.py` + Jina la mada: `schema/core/topic.py` + +4. **Dhima maalum za Pulsar zinazohitajika:** + Ujumbe unaotegemea mada + Mfumo wa schemas (Rekodi, aina za sehemu) + Usajili uliogawanywa + Utambuzi wa ujumbe (chanya/hasi) + Nafasi ya mtumiaji (mapema/ya hivi karibuni) + Sifa za ujumbe + Nafasi ya awali na aina za mtumiaji + Usaidizi wa chunking + Mada za kudumu vs. zisizo za kudumu + +### Changamoto za Urekebishaji + +Habari njema: Safu ya uainishaji (Mtumiaji, Mtayarishaji, Mchapishaji, Msubiri) hutoa uainishaji safi wa mwingiliano mwingi wa Pulsar. + +Changamoto: +1. **Ukuaji wa mfumo wa schemas:** Ufafanuzi kila ujumbe hutumia `pulsar.schema.Record` na aina za Pulsar +2. **Enums maalum za Pulsar:** `InitialPosition`, `ConsumerType` +3. **Vizuizi vya Pulsar:** `_pulsar.Timeout`, `_pulsar.Interrupted`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +4. **Mifumo ya mbinu:** `acknowledge()`, `negative_acknowledge()`, `subscribe()`, `create_producer()`, n.k. +5. **Muundo wa URI ya mada:** Muundo wa `kind://tenant/namespace/topic` wa Pulsar + +### Hatua Zinazofuata + +Ili kufanya miundombinu ya p/s kuwa configurable, tunahitaji: + +1. Kuunda kiolesura cha uainishaji kwa mfumo wa mteja/schema +2. Kuainisha enums na vizuizi maalum za Pulsar +3. Kuunda wrappers za schemas au ufafanuzi mbadala wa schemas +4. Kutekeleza kiolesura kwa wateja na mifumo mingine (Kafka, RabbitMQ, Redis Streams, n.k.) +5. Kusasisha `pubsub.py` ili iwe configurable na iunge mkono mifumo mingi +6. Kutoa njia ya uhamishaji kwa usakinishaji uliopo + +## Mfumo Mkuu wa 1: Mfumo wa Adapta na Safu ya Tafsiri ya Schemas + +### Maarifa Muhimu +Mfumo wa schemas ndio msingi wa mfumo huu. + + + +**1. Endelea kutumia muundo wa Pulsar kama uwakilishi wa ndani** +Usiandike upya maelezo yote ya muundo. +Muundo utabaki `pulsar.schema.Record` ndani. +Tumia adapta ili kutafsiri katika eneo kati ya programu yetu na mfumo wa utumaji/kupokea. + +**2. Unda safu ya utengwa kwa utumaji/kupokea:** + +``` +┌─────────────────────────────────────┐ +│ Existing Code (unchanged) │ +│ - Uses Pulsar schemas internally │ +│ - Consumer/Producer/Publisher │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - Creates backend-specific client │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────┐ ┌────▼─────────┐ +│ PulsarAdapter│ │ KafkaAdapter │ etc... +│ (passthrough)│ │ (translates) │ +└──────────────┘ └──────────────┘ +``` + +**3. Tafakikata viambishi vya dhahabu:** +`PubSubClient` - muunganisho wa mteja +`PubSubProducer` - kutuma ujumbe +`PubSubConsumer` - kupokea ujumbe +`SchemaAdapter` - kutafsiri muundo wa Pulsar kuwa/kutoka JSON au muundo maalum wa mfumo wa nyuma + +**4. Maelezo ya utekelezaji:** + +Kwa **adapta ya Pulsar**: Karibu kupita moja kwa moja, tafsiri ndogo. + +Kwa **mfumo mwingine wa nyuma** (Kafka, RabbitMQ, n.k.): +Tafsiri vitu vya rekodi ya Pulsar kuwa JSON/bytes +Linganisha dhana kama: + `InitialPosition.Earliest/Latest` → auto.offset.reset ya Kafka + `acknowledge()` → kukubali kwa Kafka + `negative_acknowledge()` → mfumo wa kurudisha au DLQ + URI za mada → majina ya mada maalum ya mfumo wa nyuma + +### Uchambuzi + +**Faida:** +✅ Mabadiliko madogo ya msimbo kwa huduma zilizopo +✅ Muundo unaendelea kuwa kama ilivyo (hakuna marekebisho makubwa) +✅ Njia ya hatua kwa hatua ya uhamishaji +✅ Watumiaji wa Pulsar hawona tofauti +✅ Mifumo mipya ya nyuma inaongezwa kupitia adapta + +**Hasara:** +⚠️ Bado ina utegemezi wa Pulsar (kwa maelezo ya muundo) +⚠️ Mizozo mingine inapotafsiri dhana + +### Toleo Mbadala + +Unda **mfumo wa muundo wa TrustGraph** ambao hautegemei mfumo wowote wa kutuma na kupokea (kwa kutumia madarasa ya data au Pydantic), kisha uzalisha muundo wa Pulsar/Kafka/n.k. kutoka humo. Hii inahitaji kuandikewa tena kila faili ya muundo na inaweza kusababisha mabadiliko. + +### Mapendekezo kwa Rasimu ya 1 + +Anza na **mbinu ya adapta** kwa sababu: +1. Ni ya vitendo - inafanya kazi na msimbo uliopo +2. Inathibitisha dhana kwa hatari ndogo +3. Inaweza kubadilika kuwa mfumo wa asili wa muundo baadaye ikiwa inahitajika +4. Inadumishwa kupitia usanidi: variable moja ya mazingira inabadilisha mifumo ya nyuma + +## Mbinu ya Rasimu ya 2: Mfumo wa Muundo Usio na Utendaji wa Nyuma na Madarasa ya Data + +### Dhana Kuu + +Tumia **madarasa ya data ya Python** kama muundo wa muundo wa kati. Kila mfumo wa nyuma wa kutuma na kupokea hutoa utafsiri wake mwenyewe wa kuandika/kusoma kwa madarasa ya data, na kuondoa hitaji kwamba muundo wa Pulsar uendelee kuwa katika msimbo. + +### Ulinganifu wa Muundo katika Kiwango cha Kiwanda + +Badala ya kutafsiri muundo wa Pulsar, **kila mfumo wa nyuma hutoa utunzaji wake mwenyewe wa muundo** ambao unafanya kazi na madarasa ya data ya Python ya kawaida. + +### Mtiririko wa Mchapishaji + +```python +# 1. Get the configured backend from factory +pubsub = get_pubsub() # Returns PulsarBackend, MQTTBackend, etc. + +# 2. Get schema class from the backend +# (Can be imported directly - backend-agnostic) +from trustgraph.schema.services.llm import TextCompletionRequest + +# 3. Create a producer/publisher for a specific topic +producer = pubsub.create_producer( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend what schema to use +) + +# 4. Create message instances (same API regardless of backend) +request = TextCompletionRequest( + system="You are helpful", + prompt="Hello world", + streaming=False +) + +# 5. Send the message +producer.send(request) # Backend serializes appropriately +``` + +### Mchakato wa Mtumiaji + +```python +# 1. Get the configured backend +pubsub = get_pubsub() + +# 2. Create a consumer +consumer = pubsub.subscribe( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend how to deserialize +) + +# 3. Receive and deserialize +msg = consumer.receive() +request = msg.value() # Returns TextCompletionRequest dataclass instance + +# 4. Use the data (type-safe access) +print(request.system) # "You are helpful" +print(request.prompt) # "Hello world" +print(request.streaming) # False +``` + +### Kile Kinachotokea Nyuma ya Kulabu + +**Kwa mfumo wa nyuma (backend) wa Pulsar:** +`create_producer()` → huunda mtayarishaji (producer) wa Pulsar ukitumia schema ya JSON au rekodi iliyoundwa moja kwa moja. +`send(request)` → huhifadhi (hufanya serialization) darasa la data (dataclass) kuwa muundo wa JSON/Pulsar, na hutuma kwa Pulsar. +`receive()` → hupokea ujumbe wa Pulsar, na huhifadhi tena (hufanya deserialization) kurudi kuwa darasa la data. + +**Kwa mfumo wa nyuma (backend) wa MQTT:** +`create_producer()` → huunganisha na programu (broker) ya MQTT, hakuna haja ya usajili wa schema. +`send(request)` → hubadilisha darasa la data kuwa JSON, na hutuma kwenye mada (topic) ya MQTT. +`receive()` → huhudhuria mada (topic) ya MQTT, na huhifadhi tena JSON kurudi kuwa darasa la data. + +**Kwa mfumo wa nyuma (backend) wa Kafka:** +`create_producer()` → huunda mtayarishaji (producer) wa Kafka, na husajili schema ya Avro ikiwa inahitajika. +`send(request)` → huhifadhi darasa la data kuwa muundo wa Avro, na hutuma kwa Kafka. +`receive()` → hupokea ujumbe wa Kafka, na huhifadhi tena Avro kurudi kuwa darasa la data. + +### Vipengele Muhimu vya Ubunifu + +1. **Uundaji wa kitu (object) cha schema:** Kitu (object) cha darasa la data (dataclass) (`TextCompletionRequest(...)`) ni sawa bila kujali mfumo wa nyuma (backend). +2. **Mfumo wa nyuma (backend) hutunza uhifadhi:** Kila mfumo wa nyuma (backend) unajua jinsi ya kuhifadhi darasa lake la data kuwa muundo unaotumwa. +3. **Ufafanuzi wa schema wakati wa uundaji:** Unapounda mtayarishaji (producer)/mpokeaji (consumer), unataja aina ya schema. +4. **Usalama wa aina (type) unahifadhiwa:** Unapata kitu (object) sahihi cha `TextCompletionRequest`, sio kamusi (dict). +5. **Hakuna uvujaji wa mfumo wa nyuma (backend):** Msimbo wa programu kamwe hauingize maktaba maalum za mfumo wa nyuma (backend). + +### Mfano wa Ubadilishaji + +**Hali ya sasa (maalum kwa Pulsar):** +```python +# schema/services/llm.py +from pulsar.schema import Record, String, Boolean, Integer + +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() +``` + +**Mpya (Sio tegemezi ya mfumo wa nyuma):** +```python +# schema/services/llm.py +from dataclasses import dataclass + +@dataclass +class TextCompletionRequest: + system: str + prompt: str + streaming: bool = False +``` + +### Uunganisho wa Seva ya Nyuma (Backend) + +Kila seva ya nyuma hushughulikia us serialization/deserialization wa madatakesi: + +**Seva ya nyuma ya Pulsar:** +Huunda madatakesi `pulsar.schema.Record` moja kwa moja kutoka kwa madatakesi. +Au huserialize madatakesi hadi JSON na kutumia mfumo wa JSON wa Pulsar. +Inaendelea kudumisha utangamano na matumizi ya sasa ya Pulsar. + +**Seva ya nyuma ya MQTT/Redis:** +Huserialize madatakesi ya aina ya JSON moja kwa moja. +Tumia `dataclasses.asdict()` / `from_dict()`. +Nyepesi, haihitaji usajili wa mfumo. + +**Seva ya nyuma ya Kafka:** +Huunda mifumo ya Avro kutoka kwa maelezo ya madatakesi. +Tumia usajili wa mfumo wa Confluent. +Us serialization wa salama wa aina na udhamini wa mabadiliko ya mfumo. + +### Muundo + +``` +┌─────────────────────────────────────┐ +│ Application Code │ +│ - Uses dataclass schemas │ +│ - Backend-agnostic │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - get_pubsub() returns backend │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────────┐ ┌────▼──────────────┐ +│ PulsarBackend │ │ MQTTBackend │ +│ - JSON schema │ │ - JSON serialize │ +│ - or dynamic │ │ - Simple queues │ +│ Record gen │ │ │ +└─────────────────┘ └───────────────────┘ +``` + +### Maelezo ya Utendaji + +**1. Ufafanuzi wa muundo:** Darasa za data za kawaida na maelezo ya aina + `str`, `int`, `bool`, `float` kwa vipengele vya msingi + `list[T]` kwa safu + `dict[str, T]` kwa ramani + Darasa za data zilizounganishwa kwa aina ngumu + +**2. Kila mfumo hutoa:** + Mfumo wa ubadilishaji: `dataclass → bytes/wire format` + Mfumo wa kurejesha: `bytes/wire format → dataclass` + Usajili wa muundo (ikiwa inahitajika, kama Pulsar/Kafka) + +**3. Dhana ya mtumiaji/mtayarishaji:** + Tayari ipo (consumer.py, producer.py) + Sasisha ili kutumia ubadilishaji wa mfumo + Ondoa uingizaji wa moja kwa moja wa Pulsar + +**4. Ulinganisho wa aina:** + Pulsar `String()` → Python `str` + Pulsar `Integer()` → Python `int` + Pulsar `Boolean()` → Python `bool` + Pulsar `Array(T)` → Python `list[T]` + Pulsar `Map(K, V)` → Python `dict[K, V]` + Pulsar `Double()` → Python `float` + Pulsar `Bytes()` → Python `bytes` + +### Njia ya Uhamishaji + +1. **Tengeneza matoleo ya darasa za data** ya muundo wote katika `trustgraph/schema/` +2. **Sasisha madarasa ya mfumo** (Mtumiaji, Mtayarishaji, Mchapishaji, Mwasili) ili kutumia ubadilishaji unaotolewa na mfumo +3. **Teleza PulsarBackend** na muundo wa JSON au uzalishaji wa Rekodi wa moja kwa moja +4. **Jaribu na Pulsar** ili kuhakikisha utangamano wa nyuma na matumizi yaliyopo +5. **Ongeza mifumo mipya** (MQTT, Kafka, Redis, n.k.) kama inahitajika +6. **Ondoa uingizaji wa Pulsar** kutoka kwa faili za muundo + +### Faida + +✅ **Hakuna utegemezi wa pub/sub** katika ufafanuzi wa muundo +✅ **Python ya kawaida** - rahisi kuelewa, kuangalia aina, na kutoa maelezo +✅ **Zana za kisasa** - inafanya kazi na mypy, kukamilisha kiotomatiki kwa IDE, na vichujio +✅ **Imeboreshwa kwa mfumo** - kila mfumo hutumia ubadilishaji wa asili +✅ **Hakuna gharama ya tafsiri** - ubadilishaji wa moja kwa moja, hakuna adapta +✅ **Usalama wa aina** - vitu halisi na aina sahihi +✅ **Uthibitisho rahisi** - inaweza kutumia Pydantic ikiwa inahitajika + +### Changamoto na Suluhisho + +**Changamoto:** `Record` ya Pulsar ina uthibitisho wa uwanja wakati wa utekelezaji +**Suluhisho:** Tumia darasa za data za Pydantic kwa uthibitisho ikiwa inahitajika, au vipengele vya darasa za data ya Python 3.10+ na `__post_init__` + +**Changamoto:** Vipengele vingine maalum vya Pulsar (kama aina ya `Bytes`) +**Suluhisho:** Linganisha na aina ya `bytes` katika darasa ya data, mfumo hutunza uandikaji ipasavyo + +**Changamoto:** Majina ya mada (`persistent://tenant/namespace/topic`) +**Suluhisho:** Dhani majina ya mada katika ufafanuzi wa muundo, mfumo hubadilisha kuwa muundo sahihi + +**Changamoto:** Maendeleo na toleo la muundo +**Suluhisho:** Kila mfumo hushughulikia hii kulingana na uwezo wake (matoleo ya muundo ya Pulsar, rejista ya muundo ya Kafka, n.k.) + +**Changamoto:** Aina ngumu zilizounganishwa +**Suluhisho:** Tumia darasa za data zilizounganishwa, mifumo inabadilisha/kurejesha kwa uangalifu + +### Maamuzi ya Ubunifu + +1. **Darasa za data za kawaida au Pydantic?** + ✅ **Maamuzi: Tumia darasa za data za Python za kawaida** + Rahisi, hakuna utegemezi wa ziada + Uthibitisho hauhitajiki kwa mazoea + Rahisi kuelewa na kudumisha + +2. **Maendeleo ya muundo:** + ✅ **Maamuzi: Hakuna utaratibu wa toleo unaohitajika** + Miondoko ni thabiti na ya muda mrefu + Marekebisho kawaida huongeza sehemu mpya (utangamano wa nyuma) + Mifumo inashughulikia maendeleo ya muundo kulingana na uwezo wake + +3. **Ulingano wa nyuma:** + ✅ **Maamuzi: Mabadiliko makubwa ya toleo, utangamano wa nyuma hauhitajiki** + Itakuwa mabadiliko ya kuvunja na maagizo ya uhamishaji + Kutoa mtego huruhusu muundo bora + Mwongozo wa uhamishaji utatolewa kwa matumizi yaliyopo + +4. **Aina zilizounganishwa na miundo ngumu:** + ✅ **Maamuzi: Tumia darasa za data zilizounganishwa kwa asili** + Darasa za data za Python zinashughulikia uunganishaji kikamilifu + `list[T]` kwa safu, `dict[K, V]` kwa ramani + Mifumo inabadilisha/kurejesha kwa uangalifu + Mfano: + ```python + @dataclass + class Value: + value: str + is_uri: bool + + @dataclass + class Triple: + s: Value # Nested dataclass + p: Value + o: Value + + @dataclass + class GraphQuery: + triples: list[Triple] # Array of nested dataclasses + metadata: dict[str, str] + ``` + +5. **Maelezo ya msingi na sehemu za hiari:** + ✅ **Uamuzi: Mchanganyiko wa sehemu za lazima, maelezo ya msingi, na sehemu za hiari** + Sehemu za lazima: Hakuna maelezo ya msingi + Sehemu zilizo na maelezo ya msingi: Zipo kila wakati, zina maelezo ya msingi yanayofaa + Sehemu za hiari kabisa: `T | None = None`, huachwa kutoka kwenye serialization wakati `None` + Mfano: + ```python + @dataclass + class TextCompletionRequest: + system: str # Required, no default + prompt: str # Required, no default + streaming: bool = False # Optional with default value + metadata: dict | None = None # Truly optional, can be absent + ``` + + **Maana muhimu ya usanifu:** + + Wakati `metadata = None`: + ```json + { + "system": "...", + "prompt": "...", + "streaming": false + // metadata field NOT PRESENT + } + ``` + + Wakati `metadata = {}` (tupu wazi): + ```json + { + "system": "...", + "prompt": "...", + "streaming": false, + "metadata": {} // Field PRESENT but empty + } + ``` + + **Tofauti kuu:** + `None` → sehemu ambayo haina katika JSON (hairekebishwi) + Thamani tupu (`{}`, `[]`, `""`) → sehemu inayoonekana na thamani tupu + Hii ina umuhimu wa maana: "haiyapatikani" dhidi ya "tupu kwa uwazi" + Mifumo ya kurekebisha data lazima zisipite sehemu za `None`, badala ya kuzirekebisha kama `null` + +## Mfumo wa Awali wa 3: Maelezo ya Utendaji + +### Muundo wa Jina la Kawaida la Kundi + +Badilisha majina ya kundi maalum ya kila mfumo na muundo wa kawaida ambao mifumo inaweza kulinganisha ipasavyo. + +**Muundo:** `{qos}/{tenant}/{namespace}/{queue-name}` + +Ambako: +`qos`: Ngazi ya Huduma ya Ubora + `q0` = juhudi za kawaida (tuma na usisahau, hakuna utambuzi) + `q1` = angalau mara moja (inahitaji utambuzi) + `q2` = hasiwa mara moja (utambuzi wa awamu mbili) +`tenant`: Kikundi cha mantiki kwa ushirikaji wa wateja wengi +`namespace`: Kikundi kidogo ndani ya mteja +`queue-name`: Jina halisi la kundi/mada + +**Mfano:** +``` +q1/tg/flow/text-completion-requests +q2/tg/config/config-push +q0/tg/metrics/stats +``` + +### Ramani ya Mada za Seva ya Nyuma (Backend) + +Kila seva ya nyuma (backend) inaunganisha muundo wa jumla na muundo wake wa asili: + +**Seva ya Nyuma ya Pulsar:** +```python +def map_topic(self, generic_topic: str) -> str: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS to persistence + persistence = 'persistent' if qos in ['q1', 'q2'] else 'non-persistent' + + # Return Pulsar URI: persistent://tg/flow/text-completion-requests + return f"{persistence}://{tenant}/{namespace}/{queue}" +``` + +**Umfumo wa Nyuma wa MQTT:** +```python +def map_topic(self, generic_topic: str) -> tuple[str, int]: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS level + qos_level = {'q0': 0, 'q1': 1, 'q2': 2}[qos] + + # Build MQTT topic including tenant/namespace for proper namespacing + mqtt_topic = f"{tenant}/{namespace}/{queue}" + + return mqtt_topic, qos_level +``` + +### Kazi ya Msaidizi ya Mada Iliyosasishwa + +```python +# schema/core/topic.py +def topic(queue_name, qos='q1', tenant='tg', namespace='flow'): + """ + Create a generic topic identifier that can be mapped by backends. + + Args: + queue_name: The queue/topic name + qos: Quality of service + - 'q0' = best-effort (no ack) + - 'q1' = at-least-once (ack required) + - 'q2' = exactly-once (two-phase ack) + tenant: Tenant identifier for multi-tenancy + namespace: Namespace within tenant + + Returns: + Generic topic string: qos/tenant/namespace/queue_name + + Examples: + topic('my-queue') # q1/tg/flow/my-queue + topic('config', qos='q2', namespace='config') # q2/tg/config/config + """ + return f"{qos}/{tenant}/{namespace}/{queue_name}" +``` + +### Usanidi na Uanzishaji + +**Vigezo vya Amri na Vigezo vya Mazingira:** + +```python +# In base/async_processor.py - add_args() method +@staticmethod +def add_args(parser): + # Pub/sub backend selection + parser.add_argument( + '--pubsub-backend', + default=os.getenv('PUBSUB_BACKEND', 'pulsar'), + choices=['pulsar', 'mqtt'], + help='Pub/sub backend (default: pulsar, env: PUBSUB_BACKEND)' + ) + + # Pulsar-specific configuration + parser.add_argument( + '--pulsar-host', + default=os.getenv('PULSAR_HOST', 'pulsar://localhost:6650'), + help='Pulsar host (default: pulsar://localhost:6650, env: PULSAR_HOST)' + ) + + parser.add_argument( + '--pulsar-api-key', + default=os.getenv('PULSAR_API_KEY', None), + help='Pulsar API key (env: PULSAR_API_KEY)' + ) + + parser.add_argument( + '--pulsar-listener', + default=os.getenv('PULSAR_LISTENER', None), + help='Pulsar listener name (env: PULSAR_LISTENER)' + ) + + # MQTT-specific configuration + parser.add_argument( + '--mqtt-host', + default=os.getenv('MQTT_HOST', 'localhost'), + help='MQTT broker host (default: localhost, env: MQTT_HOST)' + ) + + parser.add_argument( + '--mqtt-port', + type=int, + default=int(os.getenv('MQTT_PORT', '1883')), + help='MQTT broker port (default: 1883, env: MQTT_PORT)' + ) + + parser.add_argument( + '--mqtt-username', + default=os.getenv('MQTT_USERNAME', None), + help='MQTT username (env: MQTT_USERNAME)' + ) + + parser.add_argument( + '--mqtt-password', + default=os.getenv('MQTT_PASSWORD', None), + help='MQTT password (env: MQTT_PASSWORD)' + ) +``` + +**Fungua Kazi:** + +```python +# In base/pubsub.py or base/pubsub_factory.py +def get_pubsub(**config) -> PubSubBackend: + """ + Create and return a pub/sub backend based on configuration. + + Args: + config: Configuration dict from command-line args + Must include 'pubsub_backend' key + + Returns: + Backend instance (PulsarBackend, MQTTBackend, etc.) + """ + backend_type = config.get('pubsub_backend', 'pulsar') + + if backend_type == 'pulsar': + return PulsarBackend( + host=config.get('pulsar_host'), + api_key=config.get('pulsar_api_key'), + listener=config.get('pulsar_listener'), + ) + elif backend_type == 'mqtt': + return MQTTBackend( + host=config.get('mqtt_host'), + port=config.get('mqtt_port'), + username=config.get('mqtt_username'), + password=config.get('mqtt_password'), + ) + else: + raise ValueError(f"Unknown pub/sub backend: {backend_type}") +``` + +**Matumizi katika AsyncProcessor:** + +```python +# In async_processor.py +class AsyncProcessor: + def __init__(self, **params): + self.id = params.get("id") + + # Create backend from config (replaces PulsarClient) + self.pubsub = get_pubsub(**params) + + # Rest of initialization... +``` + +### Kiolesura cha Nyuma + +```python +class PubSubBackend(Protocol): + """Protocol defining the interface all pub/sub backends must implement.""" + + def create_producer(self, topic: str, schema: type, **options) -> BackendProducer: + """ + Create a producer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + schema: Dataclass type for messages + options: Backend-specific options (e.g., chunking_enabled) + + Returns: + Backend-specific producer instance + """ + ... + + def create_consumer( + self, + topic: str, + subscription: str, + schema: type, + initial_position: str = 'latest', + consumer_type: str = 'shared', + **options + ) -> BackendConsumer: + """ + Create a consumer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + subscription: Subscription/consumer group name + schema: Dataclass type for messages + initial_position: 'earliest' or 'latest' (MQTT may ignore) + consumer_type: 'shared', 'exclusive', 'failover' (MQTT may ignore) + options: Backend-specific options + + Returns: + Backend-specific consumer instance + """ + ... + + def close(self) -> None: + """Close the backend connection.""" + ... +``` + +```python +class BackendProducer(Protocol): + """Protocol for backend-specific producer.""" + + def send(self, message: Any, properties: dict = {}) -> None: + """Send a message (dataclass instance) with optional properties.""" + ... + + def flush(self) -> None: + """Flush any buffered messages.""" + ... + + def close(self) -> None: + """Close the producer.""" + ... +``` + +```python +class BackendConsumer(Protocol): + """Protocol for backend-specific consumer.""" + + def receive(self, timeout_millis: int = 2000) -> Message: + """ + Receive a message from the topic. + + Raises: + TimeoutError: If no message received within timeout + """ + ... + + def acknowledge(self, message: Message) -> None: + """Acknowledge successful processing of a message.""" + ... + + def negative_acknowledge(self, message: Message) -> None: + """Negative acknowledge - triggers redelivery.""" + ... + + def unsubscribe(self) -> None: + """Unsubscribe from the topic.""" + ... + + def close(self) -> None: + """Close the consumer.""" + ... +``` + +```python +class Message(Protocol): + """Protocol for a received message.""" + + def value(self) -> Any: + """Get the deserialized message (dataclass instance).""" + ... + + def properties(self) -> dict: + """Get message properties/metadata.""" + ... +``` + +### Urekebishaji wa Darasa Zilizopo + +Madarasa yaliyopo ya `Consumer`, `Producer`, `Publisher`, `Subscriber` yanabaki kwa kiasi kikubwa bila kubadilishwa: + +**Jukumu la sasa (hakikisha):** +Mfumo wa uzi usio na usumbufu na vikundi vya kazi +Mantiki ya kuunganisha tena na udhibiti wa kujaribu tena +Ukusanyaji wa metriki +Udhibiti wa kiwango +Usimamizi wa ushindani + +**Mabadiliko yanayohitajika:** +Ondoa uingizaji wa moja kwa moja wa Pulsar (`pulsar.schema`, `pulsar.InitialPosition`, n.k.) +Kubali `BackendProducer`/`BackendConsumer` badala ya mteja wa Pulsar +Agiza shughuli halisi za kutuma/kupokea kwa mifumo ya nyuma +Linganisha dhana za jumla na simu za mfumo wa nyuma + +**Mfano wa urekebishaji:** + +```python +# OLD - consumer.py +class Consumer: + def __init__(self, client, topic, subscriber, schema, ...): + self.client = client # Direct Pulsar client + # ... + + async def consumer_run(self): + # Uses pulsar.InitialPosition, pulsar.ConsumerType + self.consumer = self.client.subscribe( + topic=self.topic, + schema=JsonSchema(self.schema), + initial_position=pulsar.InitialPosition.Earliest, + consumer_type=pulsar.ConsumerType.Shared, + ) + +# NEW - consumer.py +class Consumer: + def __init__(self, backend_consumer, schema, ...): + self.backend_consumer = backend_consumer # Backend-specific consumer + self.schema = schema + # ... + + async def consumer_run(self): + # Backend consumer already created with right settings + # Just use it directly + while self.running: + msg = await asyncio.to_thread( + self.backend_consumer.receive, + timeout_millis=2000 + ) + await self.handle_message(msg) +``` + +### Tabia Maalum za Seva (Backend) + +**Seva ya Pulsar:** +Inahusisha `q0` → `non-persistent://`, `q1`/`q2` → `persistent://` +Inasaidia aina zote za watumiaji (walioshirikiana, wa kipekee, wa chechezi) +Inasaidia nafasi ya awali (ya kwanza/ya mwisho) +Utambuzi wa asili wa ujumbe +Inasaidia usajili wa schema + +**Seva ya MQTT:** +Inahusisha `q0`/`q1`/`q2` → Viwango vya QoS vya MQTT 0/1/2 +Inajumuisha mpangilio/nafasi katika njia ya mada kwa ajili ya utenganishaji +Inazalisha kiotomatiki vitambulisho vya wateja kutoka kwa majina ya usajili +Inapuuza nafasi ya awali (hakuna historia ya ujumbe katika MQTT ya msingi) +Inapuuza aina ya mtumiaji (MQTT hutumia vitambulisho vya wateja, sio vikundi vya watumiaji) +Mfumo rahisi wa kuchapisha/kusajili + +### Muhtasari wa Maamuzi ya Ubunifu + +1. ✅ **Jina la kawaida la folyo:** Muundo wa `qos/tenant/namespace/queue-name` +2. ✅ **QoS katika kitambulisho cha folyo:** Huamuliwa na ufafanuzi wa folyo, sio usanidi +3. ✅ **Uunganishaji upya:** Unashughulikiwa na madarasa ya Mtumiaji/Mzalishaji, sio seva +4. ✅ **Mada za MQTT:** Zijumuishie mpangilio/nafasi kwa ajili ya utenganishaji sahihi +5. ✅ **Historia ya ujumbe:** MQTT inapuuza parameter ya `initial_position` (ongezeko la baadaye) +6. ✅ **Vitambulisho vya wateja:** Seva ya MQTT inazalisha kiotomatiki kutoka kwa jina la usajili + +### Ongezeko za Baadaye + +**Historia ya ujumbe wa MQTT:** +Inaweza kuongeza safu ya hiari ya kudumu (k.m., ujumbe uliokaguliwa, duka la nje) +Itaruhusu kuunga mkono `initial_position='earliest'` +Haihitajiki kwa utekelezaji wa awali + diff --git a/docs/tech-specs/pubsub.tr.md b/docs/tech-specs/pubsub.tr.md new file mode 100644 index 00000000..cda180c2 --- /dev/null +++ b/docs/tech-specs/pubsub.tr.md @@ -0,0 +1,958 @@ +# Pub/Sub Altyapısı + +## Genel Bakış + +Bu belge, TrustGraph kod tabanı ile pub/sub altyapısı arasındaki tüm bağlantıları listeler. Şu anda sistem, Apache Pulsar'ı kullanmak üzere sabit kodlanmıştır. Bu analiz, yapılandırılabilir bir pub/sub soyutlamasına yönelik gelecekteki yeniden düzenlemeleri bilgilendirmek için tüm entegrasyon noktalarını belirler. + +## Mevcut Durum: Pulsar Entegrasyon Noktaları + +### 1. Doğrudan Pulsar İstemci Kullanımı + +**Konum:** `trustgraph-flow/trustgraph/gateway/service.py` + +API ağ geçidi, doğrudan Pulsar istemcisini içe aktarır ve örnekler: + +**Satır 20:** `import pulsar` +**Satırlar 54-61:** `pulsar.Client()`'ın doğrudan örneklenmesi, isteğe bağlı `pulsar.AuthenticationToken()` ile birlikte +**Satırlar 33-35:** Ortam değişkenlerinden varsayılan Pulsar ana bilgisayarı yapılandırması +**Satırlar 178-192:** `--pulsar-host`, `--pulsar-api-key` ve `--pulsar-listener` için CLI argümanları +**Satırlar 78, 124:** `pulsar_client`'ı `ConfigReceiver` ve `DispatcherManager`'ye geçirir + +Bu, bir soyutlama katmanı dışında bir Pulsar istemcisinin doğrudan örneklenmesini yapan tek konumdur. + +### 2. Temel İşlemci Çerçevesi + +**Konum:** `trustgraph-base/trustgraph/base/async_processor.py` + +Tüm işlemciler için temel sınıf, Pulsar bağlantısı sağlar: + +**Satır 9:** `import _pulsar` (istisna işleme için) +**Satır 18:** `from . pubsub import PulsarClient` +**Satır 38:** `pulsar_client_object = PulsarClient(**params)` oluşturur +**Satırlar 104-108:** `pulsar_host` ve `pulsar_client`'i ortaya koyan özellikler +**Satır 250:** Statik yöntem `add_args()`, CLI argümanları için `PulsarClient.add_args(parser)`'i çağırır +**Satırlar 223-225:** `_pulsar.Interrupted` için istisna işleme + +Tüm işlemciler `AsyncProcessor`'dan türetildiği için, bu merkezi bir entegrasyon noktasıdır. + +### 3. Tüketici Soyutlaması + +**Konum:** `trustgraph-base/trustgraph/base/consumer.py` + +Kuyruklardan mesajlar tüketir ve işleyici fonksiyonlarını çağırır: + +**Pulsar içe aktarmaları:** +**Satır 12:** `from pulsar.schema import JsonSchema` +**Satır 13:** `import pulsar` +**Satır 14:** `import _pulsar` + +**Pulsar'a özgü kullanım:** +**Satırlar 100, 102:** `pulsar.InitialPosition.Earliest` / `pulsar.InitialPosition.Latest` +**Satır 108:** `JsonSchema(self.schema)` sarmalayıcısı +**Satır 110:** `pulsar.ConsumerType.Shared` +**Satırlar 104-111:** Pulsar'a özgü parametrelerle `self.client.subscribe()` +**Satırlar 143, 150, 65:** `consumer.unsubscribe()` ve `consumer.close()` yöntemleri +**Satır 162:** `_pulsar.Timeout` istisnası +**Satırlar 182, 205, 232:** `consumer.acknowledge()` / `consumer.negative_acknowledge()` + +**Belge dosyası:** `trustgraph-base/trustgraph/base/consumer_spec.py` +**Satır 22:** `processor.pulsar_client`'a referans + +### 4. Yayıncı Soyutlaması + +**Konum:** `trustgraph-base/trustgraph/base/producer.py` + +Kuyruklara mesaj gönderir: + +**Pulsar içe aktarmaları:** +**Satır 2:** `from pulsar.schema import JsonSchema` + +**Pulsar'a özgü kullanım:** +**Satır 49:** `JsonSchema(self.schema)` sarmalayıcısı +**Satırlar 47-51:** Pulsar'a özgü parametrelerle (konu, şema, chunking_enabled) `self.client.create_producer()` +**Satırlar 31, 76:** `producer.close()` yöntemi +**Satırlar 64-65:** Mesaj ve özelliklerle `producer.send()` + +**Belge dosyası:** `trustgraph-base/trustgraph/base/producer_spec.py` +**Satır 18:** `processor.pulsar_client`'a referans + +### 5. Yayıncı Soyutlaması + +**Konum:** `trustgraph-base/trustgraph/base/publisher.py` + +Kuyruklu tamponlama ile asenkron mesaj yayınlama: + +**Pulsar içe aktarmaları:** +**Satır 2:** `from pulsar.schema import JsonSchema` +**Satır 6:** `import pulsar` + +**Pulsar'a özgü kullanım:** +**Satır 52:** `JsonSchema(self.schema)` sarmalayıcısı +**Satırlar 50-54:** Pulsar'a özgü parametrelerle `self.client.create_producer()` +**Satırlar 101, 103:** Mesaj ve isteğe bağlı özelliklerle `producer.send()` +**Satırlar 106-107:** `producer.flush()` ve `producer.close()` yöntemleri + +### 6. Abonelik Soyutlaması + +**Konum:** `trustgraph-base/trustgraph/base/subscriber.py` + +Kuyruklardan çoklu alıcıya mesaj dağıtımı sağlar: + +**Pulsar importları:** +**6. Satır:** `from pulsar.schema import JsonSchema` +**8. Satır:** `import _pulsar` + +**Pulsar'a özgü kullanım:** +**55. Satır:** `JsonSchema(self.schema)` wrapper +**57. Satır:** `self.client.subscribe(**subscribe_args)` +**101, 136, 160, 167-172. Satırlar:** Pulsar istisnaları: `_pulsar.Timeout`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +**159, 166, 170. Satırlar:** Tüketici metotları: `negative_acknowledge()`, `unsubscribe()`, `close()` +**247, 251. Satırlar:** Mesaj onayı: `acknowledge()`, `negative_acknowledge()` + +**Spec dosyası:** `trustgraph-base/trustgraph/base/subscriber_spec.py` +**19. Satır:** `processor.pulsar_client`'a referans + +### 7. Şema Sistemi (Heart of Darkness) + +**Konum:** `trustgraph-base/trustgraph/schema/` + +Sistemdeki her mesaj şeması, Pulsar'ın şema çerçevesi kullanılarak tanımlanır. + +**Temel öğeler:** `schema/core/primitives.py` +**2. Satır:** `from pulsar.schema import Record, String, Boolean, Array, Integer` +Tüm şemalar, Pulsar'ın `Record` temel sınıfından türetilir. +Tüm alan türleri Pulsar türleridir: `String()`, `Integer()`, `Boolean()`, `Array()`, `Map()`, `Double()` + +**Örnek şemalar:** +`schema/services/llm.py` (2. Satır): `from pulsar.schema import Record, String, Array, Double, Integer, Boolean` +`schema/services/config.py` (2. Satır): `from pulsar.schema import Record, Bytes, String, Boolean, Array, Map, Integer` + +**Konu adlandırması:** `schema/core/topic.py` +**2-3. Satırlar:** Konu formatı: `{kind}://{tenant}/{namespace}/{topic}` +Bu URI yapısı Pulsar'a özgüdür (örneğin, `persistent://tg/flow/config`) + +**Etki:** +Kod tabanındaki tüm istek/yanıt mesaj tanımları, Pulsar şemalarını kullanır. +Bu, aşağıdaki hizmetler için geçerlidir: yapılandırma, akış, LLM, istem, sorgu, depolama, aracı, koleksiyon, tanı, kütüphane, arama, NLP sorgusu, nesne sorgusu, alma, yapılandırılmış sorgu. +Şema tanımları, tüm işlemciler ve hizmetler genelinde kapsamlı bir şekilde içe aktarılır ve kullanılır. + +## Özet + +### Kategoriye Göre Pulsar Bağımlılıkları + +1. **İstem oluşturma:** + Doğrudan: `gateway/service.py` + Soyutlanmış: `async_processor.py` → `pubsub.py` (PulsarClient) + +2. **Mesaj taşıma:** + Tüketici: `consumer.py`, `consumer_spec.py` + Üretici: `producer.py`, `producer_spec.py` + Yayıncı: `publisher.py` + Abonelik: `subscriber.py`, `subscriber_spec.py` + +3. **Şema sistemi:** + Temel türler: `schema/core/primitives.py` + Tüm hizmet şemaları: `schema/services/*.py` + Konu adlandırması: `schema/core/topic.py` + +4. **Gereken Pulsar'a özgü kavramlar:** + Konuya dayalı mesajlaşma + Şema sistemi (Kayıt, alan türleri) + Paylaşımlı abonelikler + Mesaj onayı (olumlu/olumsuz) + Tüketici konumlandırması (en erken/en son) + Mesaj özellikleri + Başlangıç konumları ve tüketici türleri + Parçalama desteği + Kalıcı ve kalıcı olmayan konular + +### Yeniden Düzenleme Zorlukları + +İyi haber: Soyutlama katmanı (Tüketici, Üretici, Yayıncı, Abonelik), çoğu Pulsar etkileşimini temiz bir şekilde kapsar. + +Zorluklar: +1. **Şema sisteminin yaygınlığı:** Her mesaj tanımı `pulsar.schema.Record` ve Pulsar alan türlerini kullanır. +2. **Pulsar'a özgü numaralandırmalar:** `InitialPosition`, `ConsumerType` +3. **Pulsar istisnaları:** `_pulsar.Timeout`, `_pulsar.Interrupted`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +4. **Metot imzaları:** `acknowledge()`, `negative_acknowledge()`, `subscribe()`, `create_producer()`, vb. +5. **Konu URI formatı:** Pulsar'ın `kind://tenant/namespace/topic` yapısı + +### Sonraki Adımlar + +Yayın/abone altyapısını yapılandırılabilir hale getirmek için şunları yapmamız gerekiyor: + +1. İstem/şema sistemi için bir soyutlama arayüzü oluşturun. +2. Pulsar'a özgü numaralandırmaları ve istisnaları soyutlayın. +3. Şema sargıları veya alternatif şema tanımları oluşturun. +4. Arayüzü hem Pulsar hem de alternatif sistemler (Kafka, RabbitMQ, Redis Streams, vb.) için uygulayın. +5. `pubsub.py`'ı yapılandırılabilir hale getirin ve çoklu arka uçları destekleyin. +6. Mevcut dağıtımlar için bir geçiş yolu sağlayın. + +## Yaklaşım Taslağı 1: Şema Çeviri Katmanıyla Adaptör Kalıbı + +### Temel Bilgi +**Şema sistemi**, en derin entegrasyon noktasıdır - her şey ondan kaynaklanır. Önce bunu çözmemiz gerekiyor, aksi takdirde tüm kodu yeniden yazmamız gerekecek. + +### Strateji: Minimum Bozulma ile Adaptörler + +**1. Pulsar şemalarını, dahili gösterim olarak koruyun** +Tüm şema tanımlarını yeniden yazmayın +Şemalar, dahili olarak `pulsar.schema.Record` olarak kalır +Adaptörleri, kendi kodumuz ile yayın/abonelik arka ucu arasındaki sınırdaki çevirileri yapmak için kullanın + +**2. Bir yayın/abonelik soyutlama katmanı oluşturun:** + +``` +┌─────────────────────────────────────┐ +│ Existing Code (unchanged) │ +│ - Uses Pulsar schemas internally │ +│ - Consumer/Producer/Publisher │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - Creates backend-specific client │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────┐ ┌────▼─────────┐ +│ PulsarAdapter│ │ KafkaAdapter │ etc... +│ (passthrough)│ │ (translates) │ +└──────────────┘ └──────────────┘ +``` + +**3. Soyut arayüzleri tanımlayın:** +`PubSubClient` - istemci bağlantısı +`PubSubProducer` - mesaj gönderme +`PubSubConsumer` - mesaj alma +`SchemaAdapter` - Pulsar şemalarını JSON'a veya arka uç özel formatlarına dönüştürme/dönüştürme + +**4. Uygulama detayları:** + +**Pulsar adaptörü için:** Neredeyse doğrudan geçiş, minimum çeviri + +**Diğer arka uçlar için** (Kafka, RabbitMQ, vb.): +Pulsar Kayıt nesnelerini JSON/byte'a serileştirin +Aşağıdaki kavramları eşleyin: + `InitialPosition.Earliest/Latest` → Kafka'nın auto.offset.reset'i + `acknowledge()` → Kafka'nın commit'i + `negative_acknowledge()` → Yeniden kuyruklama veya DLQ deseni + Konu URI'leri → Arka uç özel konu adları + +### Analiz + +**Artıları:** +✅ Mevcut hizmetlerde minimum kod değişikliği +✅ Şemalar olduğu gibi kalır (büyük bir yeniden yazım olmaz) +✅ Aşamalı geçiş yolu +✅ Pulsar kullanıcıları hiçbir fark görmez +✅ Yeni arka uçlar adaptörler aracılığıyla eklenir + +**Eksileri:** +⚠️ Hala Pulsar bağımlılığı taşır (şema tanımları için) +⚠️ Kavramları çevirirken bazı uyumsuzluklar olabilir + +### Alternatif Düşünce + +Bir **TrustGraph şema sistemi** oluşturun; bu sistem, pub/sub'dan bağımsızdır (dataclass'lar veya Pydantic kullanarak). Ardından, bu sistemden Pulsar/Kafka/vb. şemalarını oluşturun. Bu, her şema dosyasının yeniden yazılmasını gerektirir ve potansiyel olarak uyumsuzluklara neden olabilir. + +### Taslak 1 için Öneri + +**Adaptör yaklaşımıyla** başlayın çünkü: +1. Pratik bir yaklaşımdır - mevcut kodla çalışır +2. Minimum riskle kavramı kanıtlar +3. Gerekirse daha sonra yerel bir şema sistemine dönüştürülebilir +4. Yapılandırma odaklıdır: tek bir ortam değişkeni arka uçları değiştirir + +## Yaklaşım Taslağı 2: Dataclass'larla Arka Uçtan Bağımsız Şema Sistemi + +### Temel Kavram + +Python **dataclass'ları** tarafsız şema tanımı formatı olarak kullanın. Her pub/sub arka ucu, dataclass'lar için kendi serileştirme/deserileştirme işlemlerini sağlar; bu, Pulsar şemalarının kod tabanında kalma ihtiyacını ortadan kaldırır. + +### Fabrika Seviyesinde Şema Çok Biçimliliği + +Pulsar şemalarını çevirmek yerine, **her arka uç, standart Python dataclass'larıyla çalışan kendi şema işleme yöntemini sağlar**. + +### Yayıncı Akışı + +```python +# 1. Get the configured backend from factory +pubsub = get_pubsub() # Returns PulsarBackend, MQTTBackend, etc. + +# 2. Get schema class from the backend +# (Can be imported directly - backend-agnostic) +from trustgraph.schema.services.llm import TextCompletionRequest + +# 3. Create a producer/publisher for a specific topic +producer = pubsub.create_producer( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend what schema to use +) + +# 4. Create message instances (same API regardless of backend) +request = TextCompletionRequest( + system="You are helpful", + prompt="Hello world", + streaming=False +) + +# 5. Send the message +producer.send(request) # Backend serializes appropriately +``` + +### Tüketici Akışı + +```python +# 1. Get the configured backend +pubsub = get_pubsub() + +# 2. Create a consumer +consumer = pubsub.subscribe( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend how to deserialize +) + +# 3. Receive and deserialize +msg = consumer.receive() +request = msg.value() # Returns TextCompletionRequest dataclass instance + +# 4. Use the data (type-safe access) +print(request.system) # "You are helpful" +print(request.prompt) # "Hello world" +print(request.streaming) # False +``` + +### Sahne Arkasındaki Olaylar + +**Pulsar arka ucu için:** +`create_producer()` → JSON şeması veya dinamik olarak oluşturulmuş bir kayıtla Pulsar üreticisi oluşturur. +`send(request)` → veri sınıfını JSON/Pulsar formatına serileştirir ve Pulsar'a gönderir. +`receive()` → Pulsar mesajını alır, veri sınıfına geri serileştirir. + +**MQTT arka ucu için:** +`create_producer()` → MQTT aracısına bağlanır, şema kaydı gerektirmez. +`send(request)` → veri sınıfını JSON'a dönüştürür ve MQTT konusuna yayınlar. +`receive()` → MQTT konusuna abone olur, JSON'ı veri sınıfına geri serileştirir. + +**Kafka arka ucu için:** +`create_producer()` → Kafka üreticisini oluşturur, gerekirse Avro şemasını kaydeder. +`send(request)` → veri sınıfını Avro formatına serileştirir ve Kafka'ya gönderir. +`receive()` → Kafka mesajını alır, Avro'yu veri sınıfına geri serileştirir. + +### Temel Tasarım Noktaları + +1. **Şema nesnesi oluşturma**: Veri sınıfı örneği (`TextCompletionRequest(...)`), arka uçtan bağımsız olarak aynıdır. +2. **Arka uç, kodlamayı yönetir**: Her arka uç, veri sınıfını kablo formatına nasıl serileştireceğini bilir. +3. **Oluşturma sırasında şema tanımı**: Üretici/tüketici oluştururken, şema türünü belirtirsiniz. +4. **Tür güvenliği korunur**: Doğru bir `TextCompletionRequest` nesnesi alırsınız, bir sözlük değil. +5. **Arka uç sızıntısı yok**: Uygulama kodu, arka uçla ilgili özel kütüphaneleri asla içe aktarmaz. + +### Örnek Dönüşüm + +**Mevcut (Pulsar'a özel):** +```python +# schema/services/llm.py +from pulsar.schema import Record, String, Boolean, Integer + +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() +``` + +**Yeni (Arka uçtan bağımsız):** +```python +# schema/services/llm.py +from dataclasses import dataclass + +@dataclass +class TextCompletionRequest: + system: str + prompt: str + streaming: bool = False +``` + +### Arka Uç Entegrasyonu + +Her arka uç, veri sınıflarının serileştirme/deserileştirme işlemlerini gerçekleştirir: + +**Pulsar arka ucu:** +Veri sınıflarından dinamik olarak `pulsar.schema.Record` sınıfları oluşturun +Veya veri sınıflarını JSON'a serileştirin ve Pulsar'ın JSON şemasını kullanın +Mevcut Pulsar kurulumlarıyla uyumluluğu korur + +**MQTT/Redis arka ucu:** +Veri sınıfı örneklerinin doğrudan JSON serileştirilmesi +`dataclasses.asdict()` / `from_dict()` kullanın +Hafif, şema kayıt defterine gerek yok + +**Kafka arka ucu:** +Veri sınıfı tanımlarından Avro şemaları oluşturun +Confluent'ın şema kayıt defterini kullanın +Şema evrimi desteğiyle tür güvenli serileştirme + +### Mimari + +``` +┌─────────────────────────────────────┐ +│ Application Code │ +│ - Uses dataclass schemas │ +│ - Backend-agnostic │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - get_pubsub() returns backend │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────────┐ ┌────▼──────────────┐ +│ PulsarBackend │ │ MQTTBackend │ +│ - JSON schema │ │ - JSON serialize │ +│ - or dynamic │ │ - Simple queues │ +│ Record gen │ │ │ +└─────────────────┘ └───────────────────┘ +``` + +### Uygulama Detayları + +**1. Şema tanımları:** Basit dataclass'lar ve tür ipuçları + `str`, `int`, `bool`, `float` temel veri tipleri için + `list[T]` diziler için + `dict[str, T]` haritalar için + Karmaşık tipler için iç içe dataclass'lar + +**2. Her arka uç şunları sağlar:** + Serileştirici: `dataclass → bytes/wire format` + Seri dışa aktarıcı: `bytes/wire format → dataclass` + Şema kaydı (gerekirse, örneğin Pulsar/Kafka) + +**3. Tüketici/Üretici soyutlaması:** + Zaten mevcut (consumer.py, producer.py) + Arka uç tarafından sağlanan seri dışa aktarmayı kullanmak için güncellenmeli + Doğrudan Pulsar içe aktarmalarını kaldırmalı + +**4. Tür eşlemeleri:** + Pulsar `String()` → Python `str` + Pulsar `Integer()` → Python `int` + Pulsar `Boolean()` → Python `bool` + Pulsar `Array(T)` → Python `list[T]` + Pulsar `Map(K, V)` → Python `dict[K, V]` + Pulsar `Double()` → Python `float` + Pulsar `Bytes()` → Python `bytes` + +### Geçiş Yolu + +1. `trustgraph/schema/` içindeki tüm şemaların **dataclass versiyonlarını oluşturun** +2. Arka uç tarafından sağlanan seri dışa aktarmayı kullanmak için **arka uç sınıflarını (Tüketici, Üretici, Yayıncı, Abonelik) güncelleyin** +3. JSON şemasını veya dinamik Kayıt oluşturmayı kullanarak **PulsarBackend'i uygulayın** +4. **Mevcut dağıtımlarla geriye dönük uyumluluğu sağlamak için Pulsar ile test edin** +5. Gerekirse **yeni arka uçlar ekleyin (MQTT, Kafka, Redis, vb.)** +6. Şema dosyalarından **Pulsar içe aktarmalarını kaldırın** + +### Avantajlar + +✅ **Şema tanımlarında herhangi bir yayın/abonelik bağımlılığı yok** +✅ **Standart Python** - anlaşılması, tür denetimi yapılması ve belgelenmesi kolay +✅ **Modern araçlar** - mypy, IDE otomatik tamamlama, lint araçlarıyla çalışır +✅ **Arka uç odaklı** - her arka uç yerel seri dışa aktarmayı kullanır +✅ **Çeviri ek yükü yok** - doğrudan seri dışa aktarma, adaptörler yok +✅ **Tür güvenliği** - uygun türlere sahip gerçek nesneler +✅ **Kolay doğrulama** - gerekirse Pydantic kullanılabilir + +### Zorluklar & Çözümler + +**Zorluk:** Pulsar'ın `Record`'ı çalışma zamanı alan doğrulamasına sahiptir +**Çözüm:** Gerekirse doğrulama için Pydantic dataclass'larını kullanın veya `__post_init__` ile Python 3.10+ dataclass özelliklerini kullanın + +**Zorluk:** Bazı Pulsar'a özgü özellikler (örneğin `Bytes` türü) +**Çözüm:** Bu türü dataclass'ta `bytes` türüne eşleyin, arka uç uygun şekilde kodlamayı işler + +**Zorluk:** Konu adlandırması (`persistent://tenant/namespace/topic`) +**Çözüm:** Şema tanımlarında konu adlarını soyutlayın, arka uç uygun formata dönüştürür + +**Zorluk:** Şema evrimi ve sürüm oluşturma +**Çözüm:** Her arka uç, yeteneklerine göre bunu işler (Pulsar şema sürümleri, Kafka şema kaydı, vb.) + +**Zorluk:** İç içe karmaşık türler +**Çözüm:** İç içe dataclass'ları kullanın, arka uçlar yinelemeli olarak seri dışa aktarır/serileştirir + +### Tasarım Kararları + +1. **Basit dataclass'lar mı yoksa Pydantic mi?** + ✅ **Karar: Basit Python dataclass'ları kullanın** + Daha basit, ek bağımlılık yok + Uygulamada doğrulama gerekli değil + Anlaşılması ve bakımı daha kolay + +2. **Şema evrimi:** + ✅ **Karar: Herhangi bir sürüm oluşturma mekanizmasına gerek yok** + Şemalar kararlı ve uzun ömürlü + Güncellemeler genellikle yeni alanlar ekler (geriye dönük uyumlu) + Arka uçlar, yeteneklerine göre şema evrimini işler + +3. **Geriye dönük uyumluluk:** + ✅ **Karar: Ana sürüm değişikliği, geriye dönük uyumluluk gerekli değil** + Bu, bir kopma değişikliği olacak ve geçiş talimatları sağlanacak + Temiz bir kopma, daha iyi bir tasarım sağlar + Mevcut dağıtımlar için bir geçiş kılavuzu sağlanacaktır + +4. **İç içe türler ve karmaşık yapılar:** + ✅ **Karar: İç içe dataclass'ları doğal olarak kullanın** + Python dataclass'ları iç içe geçmeyi mükemmel şekilde işler + Diziler için `list[T]`, haritalar için `dict[K, V]` + Arka uçlar yinelemeli olarak seri dışa aktarır/serileştirir + Örnek: + ```python + @dataclass + class Value: + value: str + is_uri: bool + + @dataclass + class Triple: + s: Value # Nested dataclass + p: Value + o: Value + + @dataclass + class GraphQuery: + triples: list[Triple] # Array of nested dataclasses + metadata: dict[str, str] + ``` + +5. **Varsayılan değerler ve isteğe bağlı alanlar:** + ✅ **Karar: Gerekli, varsayılan ve isteğe bağlı alanların birleşimi** + Gerekli alanlar: Herhangi bir varsayılan değer yok + Varsayılan değerlere sahip alanlar: Her zaman mevcut, anlamlı varsayılan değerlere sahip + Tamamen isteğe bağlı alanlar: `T | None = None`, `None` olduğunda serileştirmeden çıkarılır + Örnek: + ```python + @dataclass + class TextCompletionRequest: + system: str # Required, no default + prompt: str # Required, no default + streaming: bool = False # Optional with default value + metadata: dict | None = None # Truly optional, can be absent + ``` + + **Önemli serileştirme kuralları:** + + `metadata = None` olduğunda: + ```json + { + "system": "...", + "prompt": "...", + "streaming": false + // metadata field NOT PRESENT + } + ``` + + `metadata = {}` (açıkça boş) olduğunda: + ```json + { + "system": "...", + "prompt": "...", + "streaming": false, + "metadata": {} // Field PRESENT but empty + } + ``` + + **Temel ayrım:** + `None` → JSON'da bulunmayan alan (serileştirilmiyor) + Boş değer (`{}`, `[]`, `""`) → alan, boş bir değerle mevcut + Bu, anlamsal olarak önemlidir: "sağlanmadı" ile "açıkça boş" + Serileştirme arka uçları, `None` alanlarını atlamalı, bunları `null` olarak kodlamamalıdır. + +## Yaklaşım Taslağı 3: Uygulama Detayları + +### Genel Kuyruk Adlandırma Formatı + +Arka uçlara özgü kuyruk adlarını, arka uçların uygun şekilde eşleyebileceği genel bir formata dönüştürün. + +**Format:** `{qos}/{tenant}/{namespace}/{queue-name}` + +Nerede: +`qos`: Hizmet kalitesi seviyesi + `q0` = en iyi çaba (ateşle ve unut, onay yok) + `q1` = en az bir kez (onay gerektirir) + `q2` = tam olarak bir kez (iki aşamalı onay) +`tenant`: Çok kiracılılık için mantıksal gruplandırma +`namespace`: Kiracı içindeki alt gruplandırma +`queue-name`: Gerçek kuyruk/konu adı + +**Örnekler:** +``` +q1/tg/flow/text-completion-requests +q2/tg/config/config-push +q0/tg/metrics/stats +``` + +### Arka Uç Konu Eşlemesi + +Her arka uç, genel formatı kendi yerel formatına eşler: + +**Pulsar Arka Ucu:** +```python +def map_topic(self, generic_topic: str) -> str: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS to persistence + persistence = 'persistent' if qos in ['q1', 'q2'] else 'non-persistent' + + # Return Pulsar URI: persistent://tg/flow/text-completion-requests + return f"{persistence}://{tenant}/{namespace}/{queue}" +``` + +**MQTT Altyapısı:** +```python +def map_topic(self, generic_topic: str) -> tuple[str, int]: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS level + qos_level = {'q0': 0, 'q1': 1, 'q2': 2}[qos] + + # Build MQTT topic including tenant/namespace for proper namespacing + mqtt_topic = f"{tenant}/{namespace}/{queue}" + + return mqtt_topic, qos_level +``` + +### Güncellenmiş Konu Yardımcı Fonksiyonu + +```python +# schema/core/topic.py +def topic(queue_name, qos='q1', tenant='tg', namespace='flow'): + """ + Create a generic topic identifier that can be mapped by backends. + + Args: + queue_name: The queue/topic name + qos: Quality of service + - 'q0' = best-effort (no ack) + - 'q1' = at-least-once (ack required) + - 'q2' = exactly-once (two-phase ack) + tenant: Tenant identifier for multi-tenancy + namespace: Namespace within tenant + + Returns: + Generic topic string: qos/tenant/namespace/queue_name + + Examples: + topic('my-queue') # q1/tg/flow/my-queue + topic('config', qos='q2', namespace='config') # q2/tg/config/config + """ + return f"{qos}/{tenant}/{namespace}/{queue_name}" +``` + +### Yapılandırma ve Başlatma + +**Komut Satırı Argümanları + Ortam Değişkenleri:** + +```python +# In base/async_processor.py - add_args() method +@staticmethod +def add_args(parser): + # Pub/sub backend selection + parser.add_argument( + '--pubsub-backend', + default=os.getenv('PUBSUB_BACKEND', 'pulsar'), + choices=['pulsar', 'mqtt'], + help='Pub/sub backend (default: pulsar, env: PUBSUB_BACKEND)' + ) + + # Pulsar-specific configuration + parser.add_argument( + '--pulsar-host', + default=os.getenv('PULSAR_HOST', 'pulsar://localhost:6650'), + help='Pulsar host (default: pulsar://localhost:6650, env: PULSAR_HOST)' + ) + + parser.add_argument( + '--pulsar-api-key', + default=os.getenv('PULSAR_API_KEY', None), + help='Pulsar API key (env: PULSAR_API_KEY)' + ) + + parser.add_argument( + '--pulsar-listener', + default=os.getenv('PULSAR_LISTENER', None), + help='Pulsar listener name (env: PULSAR_LISTENER)' + ) + + # MQTT-specific configuration + parser.add_argument( + '--mqtt-host', + default=os.getenv('MQTT_HOST', 'localhost'), + help='MQTT broker host (default: localhost, env: MQTT_HOST)' + ) + + parser.add_argument( + '--mqtt-port', + type=int, + default=int(os.getenv('MQTT_PORT', '1883')), + help='MQTT broker port (default: 1883, env: MQTT_PORT)' + ) + + parser.add_argument( + '--mqtt-username', + default=os.getenv('MQTT_USERNAME', None), + help='MQTT username (env: MQTT_USERNAME)' + ) + + parser.add_argument( + '--mqtt-password', + default=os.getenv('MQTT_PASSWORD', None), + help='MQTT password (env: MQTT_PASSWORD)' + ) +``` + +**Fabrika Fonksiyonu:** + +```python +# In base/pubsub.py or base/pubsub_factory.py +def get_pubsub(**config) -> PubSubBackend: + """ + Create and return a pub/sub backend based on configuration. + + Args: + config: Configuration dict from command-line args + Must include 'pubsub_backend' key + + Returns: + Backend instance (PulsarBackend, MQTTBackend, etc.) + """ + backend_type = config.get('pubsub_backend', 'pulsar') + + if backend_type == 'pulsar': + return PulsarBackend( + host=config.get('pulsar_host'), + api_key=config.get('pulsar_api_key'), + listener=config.get('pulsar_listener'), + ) + elif backend_type == 'mqtt': + return MQTTBackend( + host=config.get('mqtt_host'), + port=config.get('mqtt_port'), + username=config.get('mqtt_username'), + password=config.get('mqtt_password'), + ) + else: + raise ValueError(f"Unknown pub/sub backend: {backend_type}") +``` + +**AsyncProcessor'da Kullanım:** + +```python +# In async_processor.py +class AsyncProcessor: + def __init__(self, **params): + self.id = params.get("id") + + # Create backend from config (replaces PulsarClient) + self.pubsub = get_pubsub(**params) + + # Rest of initialization... +``` + +### Arka Uç Arayüzü + +```python +class PubSubBackend(Protocol): + """Protocol defining the interface all pub/sub backends must implement.""" + + def create_producer(self, topic: str, schema: type, **options) -> BackendProducer: + """ + Create a producer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + schema: Dataclass type for messages + options: Backend-specific options (e.g., chunking_enabled) + + Returns: + Backend-specific producer instance + """ + ... + + def create_consumer( + self, + topic: str, + subscription: str, + schema: type, + initial_position: str = 'latest', + consumer_type: str = 'shared', + **options + ) -> BackendConsumer: + """ + Create a consumer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + subscription: Subscription/consumer group name + schema: Dataclass type for messages + initial_position: 'earliest' or 'latest' (MQTT may ignore) + consumer_type: 'shared', 'exclusive', 'failover' (MQTT may ignore) + options: Backend-specific options + + Returns: + Backend-specific consumer instance + """ + ... + + def close(self) -> None: + """Close the backend connection.""" + ... +``` + +```python +class BackendProducer(Protocol): + """Protocol for backend-specific producer.""" + + def send(self, message: Any, properties: dict = {}) -> None: + """Send a message (dataclass instance) with optional properties.""" + ... + + def flush(self) -> None: + """Flush any buffered messages.""" + ... + + def close(self) -> None: + """Close the producer.""" + ... +``` + +```python +class BackendConsumer(Protocol): + """Protocol for backend-specific consumer.""" + + def receive(self, timeout_millis: int = 2000) -> Message: + """ + Receive a message from the topic. + + Raises: + TimeoutError: If no message received within timeout + """ + ... + + def acknowledge(self, message: Message) -> None: + """Acknowledge successful processing of a message.""" + ... + + def negative_acknowledge(self, message: Message) -> None: + """Negative acknowledge - triggers redelivery.""" + ... + + def unsubscribe(self) -> None: + """Unsubscribe from the topic.""" + ... + + def close(self) -> None: + """Close the consumer.""" + ... +``` + +```python +class Message(Protocol): + """Protocol for a received message.""" + + def value(self) -> Any: + """Get the deserialized message (dataclass instance).""" + ... + + def properties(self) -> dict: + """Get message properties/metadata.""" + ... +``` + +### Mevcut Sınıfların Yeniden Düzenlenmesi + +Mevcut `Consumer`, `Producer`, `Publisher`, `Subscriber` sınıfları büyük ölçüde aynı kalacaktır: + +**Mevcut sorumluluklar (saklanacak):** +Asenkron iş parçacığı modeli ve görev grupları +Yeniden bağlantı mantığı ve tekrar deneme işleme +Ölçüm toplama +Hız sınırlama +Eşzamanlılık yönetimi + +**Gerekli değişiklikler:** +Doğrudan Pulsar içe aktarmalarını kaldırın (`pulsar.schema`, `pulsar.InitialPosition`, vb.) +`BackendProducer`/`BackendConsumer`'i Pulsar istemcisi yerine kullanın +Gerçek yayın/abonelik işlemlerini arka uç örneklerine devredin +Genel kavramları arka uç çağrılarına eşleyin + +**Örnek yeniden düzenleme:** + +```python +# OLD - consumer.py +class Consumer: + def __init__(self, client, topic, subscriber, schema, ...): + self.client = client # Direct Pulsar client + # ... + + async def consumer_run(self): + # Uses pulsar.InitialPosition, pulsar.ConsumerType + self.consumer = self.client.subscribe( + topic=self.topic, + schema=JsonSchema(self.schema), + initial_position=pulsar.InitialPosition.Earliest, + consumer_type=pulsar.ConsumerType.Shared, + ) + +# NEW - consumer.py +class Consumer: + def __init__(self, backend_consumer, schema, ...): + self.backend_consumer = backend_consumer # Backend-specific consumer + self.schema = schema + # ... + + async def consumer_run(self): + # Backend consumer already created with right settings + # Just use it directly + while self.running: + msg = await asyncio.to_thread( + self.backend_consumer.receive, + timeout_millis=2000 + ) + await self.handle_message(msg) +``` + +### Arka Uç Özel Davranışlar + +**Pulsar Arka Uç:** +`q0`'ı `non-persistent://`'e, `q1`/`q2`'ü `persistent://`'e eşler. +Tüm tüketici türlerini (paylaşımlı, özel, yedekli) destekler. +Başlangıç konumunu (en erken/en son) destekler. +Yerel mesaj onayı. +Şema kayıt defteri desteği. + +**MQTT Arka Uç:** +`q0`/`q1`/`q2`'yi MQTT QoS seviyeleri 0/1/2'ye eşler. +Adlandırma için konu yoluna kiracı/isim alanı ekler. +Abonelik adlarından otomatik olarak istemci kimlikleri oluşturur. +Başlangıç konumunu yoksayar (temel MQTT'de mesaj geçmişi yoktur). +Tüketici türünü yoksayar (MQTT, tüketici grupları yerine istemci kimlikleri kullanır). +Basit yayın/abone modeli. + +### Tasarım Kararları Özeti + +1. ✅ **Genel kuyruk adlandırması**: `qos/tenant/namespace/queue-name` formatı +2. ✅ **Kuyruk kimliğindeki QoS**: Kuyruk tanımı tarafından belirlenir, yapılandırma ile değil. +3. ✅ **Yeniden bağlanma**: Tüketici/Üretici sınıfları tarafından işlenir, arka uçlar tarafından değil. +4. ✅ **MQTT konuları**: Doğru adlandırma için kiracı/isim alanı içerir. +5. ✅ **Mesaj geçmişi**: MQTT, `initial_position` parametresini yoksayar (gelecek geliştirmeler). +6. ✅ **İstemci kimlikleri**: MQTT arka ucu, abonelik adından otomatik olarak oluşturur. + +### Gelecek Geliştirmeler + +**MQTT mesaj geçmişi:** +İsteğe bağlı bir kalıcılık katmanı eklenebilir (örneğin, saklanan mesajlar, harici depolama). +`initial_position='earliest'`'ı desteklemeyi mümkün kılacaktır. +Başlangıç uygulamasında gerekli değildir. + diff --git a/docs/tech-specs/pubsub.zh-cn.md b/docs/tech-specs/pubsub.zh-cn.md new file mode 100644 index 00000000..31e79294 --- /dev/null +++ b/docs/tech-specs/pubsub.zh-cn.md @@ -0,0 +1,958 @@ +# Pub/Sub 基础设施 + +## 概述 + +本文档记录了 TrustGraph 代码库与 pub/sub 基础设施之间的所有连接。目前,系统是硬编码为使用 Apache Pulsar。此分析识别了所有集成点,以促进未来向可配置的 pub/sub 抽象的重构。 + +## 当前状态:Pulsar 集成点 + +### 1. 直接 Pulsar 客户端使用 + +**位置:** `trustgraph-flow/trustgraph/gateway/service.py` + +API 网关直接导入和实例化 Pulsar 客户端: + +**第 20 行:** `import pulsar` +**第 54-61 行:** 直接实例化 `pulsar.Client()`,带可选 `pulsar.AuthenticationToken()` +**第 33-35 行:** 从环境变量获取默认 Pulsar 主机配置 +**第 178-192 行:** CLI 参数,用于 `--pulsar-host`、`--pulsar-api-key` 和 `--pulsar-listener` +**第 78、124 行:** 将 `pulsar_client` 传递给 `ConfigReceiver` 和 `DispatcherManager` + +这是唯一直接在抽象层之外实例化 Pulsar 客户端的位置。 + +### 2. 基础处理器框架 + +**位置:** `trustgraph-base/trustgraph/base/async_processor.py` + +所有处理器的基本类提供 Pulsar 连接: + +**第 9 行:** `import _pulsar` (用于异常处理) +**第 18 行:** `from . pubsub import PulsarClient` +**第 38 行:** 创建 `pulsar_client_object = PulsarClient(**params)` +**第 104-108 行:** 暴露 `pulsar_host` 和 `pulsar_client` 的属性 +**第 250 行:** 静态方法 `add_args()` 调用 `PulsarClient.add_args(parser)` 以获取 CLI 参数 +**第 223-225 行:** `_pulsar.Interrupted` 的异常处理 + +所有处理器都继承自 `AsyncProcessor`,使其成为主要的集成点。 + +### 3. 消费者抽象 + +**位置:** `trustgraph-base/trustgraph/base/consumer.py` + +从队列中消耗消息并调用处理函数: + +**Pulsar 导入:** +**第 12 行:** `from pulsar.schema import JsonSchema` +**第 13 行:** `import pulsar` +**第 14 行:** `import _pulsar` + +**Pulsar 特定的用法:** +**第 100、102 行:** `pulsar.InitialPosition.Earliest` / `pulsar.InitialPosition.Latest` +**第 108 行:** `JsonSchema(self.schema)` 包装器 +**第 110 行:** `pulsar.ConsumerType.Shared` +**第 104-111 行:** `self.client.subscribe()`,带有 Pulsar 特定的参数 +**第 143、150、65 行:** `consumer.unsubscribe()` 和 `consumer.close()` 方法 +**第 162 行:** `_pulsar.Timeout` 异常 +**第 182、205、232 行:** `consumer.acknowledge()` / `consumer.negative_acknowledge()` + +**Spec 文件:** `trustgraph-base/trustgraph/base/consumer_spec.py` +**第 22 行:** 引用 `processor.pulsar_client` + +### 4. 生产者抽象 + +**位置:** `trustgraph-base/trustgraph/base/producer.py` + +向队列发送消息: + +**Pulsar 导入:** +**第 2 行:** `from pulsar.schema import JsonSchema` + +**Pulsar 特定的用法:** +**第 49 行:** `JsonSchema(self.schema)` 包装器 +**第 47-51 行:** `self.client.create_producer()`,带有 Pulsar 特定的参数 (topic, schema, chunking_enabled) +**第 31、76 行:** `producer.close()` 方法 +**第 64-65 行:** `producer.send()`,带有消息和属性 + +**Spec 文件:** `trustgraph-base/trustgraph/base/producer_spec.py` +**第 18 行:** 引用 `processor.pulsar_client` + +### 5. 发布者抽象 + +**位置:** `trustgraph-base/trustgraph/base/publisher.py` + +具有队列缓冲的异步消息发布: + +**Pulsar 导入:** +**第 2 行:** `from pulsar.schema import JsonSchema` +**第 6 行:** `import pulsar` + +**Pulsar 特定的用法:** +**第 52 行:** `JsonSchema(self.schema)` 包装器 +**第 50-54 行:** `self.client.create_producer()`,带有 Pulsar 特定的参数 +**第 101、103 行:** `producer.send()`,带有消息和可选属性 +**第 106-107 行:** `producer.flush()` 和 `producer.close()` 方法 + +### 6. 订阅者抽象 + +**位置:** `trustgraph-base/trustgraph/base/subscriber.py` + +提供从队列分发给多个接收者的消息功能: + +**Pulsar 导入:** +**第 6 行:** `from pulsar.schema import JsonSchema` +**第 8 行:** `import _pulsar` + +**Pulsar 特定的用法:** +**第 55 行:** `JsonSchema(self.schema)` 包装器 +**第 57 行:** `self.client.subscribe(**subscribe_args)` +**第 101、136、160、167-172 行:** Pulsar 异常:`_pulsar.Timeout`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +**第 159、166、170 行:** 消费者方法:`negative_acknowledge()`, `unsubscribe()`, `close()` +**第 247、251 行:** 消息确认:`acknowledge()`, `negative_acknowledge()` + +**Spec 文件:** `trustgraph-base/trustgraph/base/subscriber_spec.py` +**第 19 行:** 引用 `processor.pulsar_client` + +### 7. Schema 系统 (黑暗之心) + +**位置:** `trustgraph-base/trustgraph/schema/` + +系统中的每个消息模式都使用 Pulsar 的模式框架定义。 + +**核心原语:** `schema/core/primitives.py` +**第 2 行:** `from pulsar.schema import Record, String, Boolean, Array, Integer` +所有模式都继承自 Pulsar 的 `Record` 基类 +所有字段类型都是 Pulsar 类型:`String()`, `Integer()`, `Boolean()`, `Array()`, `Map()`, `Double()` + +**示例模式:** +`schema/services/llm.py` (第 2 行):`from pulsar.schema import Record, String, Array, Double, Integer, Boolean` +`schema/services/config.py` (第 2 行):`from pulsar.schema import Record, Bytes, String, Boolean, Array, Map, Integer` + +**主题命名:** `schema/core/topic.py` +**第 2-3 行:** 主题格式:`{kind}://{tenant}/{namespace}/{topic}` +此 URI 结构是 Pulsar 特定的(例如,`persistent://tg/flow/config`) + +**影响:** +代码库中所有请求/响应消息定义都使用 Pulsar 模式 +这包括用于:config、flow、llm、prompt、query、storage、agent、collection、diagnosis、library、lookup、nlp_query、objects_query、retrieval、structured_query 的服务 +模式定义被导入并广泛地用于所有处理器和服务中 + +## 总结 + +### Pulsar 依赖项按类别划分 + +1. **客户端实例化:** + 直接:`gateway/service.py` + 抽象:`async_processor.py` → `pubsub.py` (PulsarClient) + +2. **消息传输:** + 消费者:`consumer.py`, `consumer_spec.py` + 生产者:`producer.py`, `producer_spec.py` + 发布者:`publisher.py` + 订阅者:`subscriber.py`, `subscriber_spec.py` + +3. **模式系统:** + 基本类型:`schema/core/primitives.py` + 所有服务模式:`schema/services/*.py` + 主题命名:`schema/core/topic.py` + +4. **需要 Pulsar 特定的概念:** + 基于主题的消息 + 模式系统 (Record, 字段类型) + 共享订阅 + 消息确认 (肯定/否定) + 消费者定位 (最早/最新) + 消息属性 + 初始位置和消费者类型 + 分块支持 + 持久化与非持久化主题 + +### 重构挑战 + +好的消息:抽象层 (Consumer, Producer, Publisher, Subscriber) 提供了一个干净的 Pulsar 交互的封装。 + +挑战: +1. **模式系统的普遍性:** 每个消息定义都使用 `pulsar.schema.Record` 和 Pulsar 字段类型 +2. **Pulsar 特定的枚举:** `InitialPosition`, `ConsumerType` +3. **Pulsar 异常:** `_pulsar.Timeout`, `_pulsar.Interrupted`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed` +4. **方法签名:** `acknowledge()`, `negative_acknowledge()`, `subscribe()`, `create_producer()`, 等等。 +5. **主题 URI 格式:** Pulsar 的 `kind://tenant/namespace/topic` 结构 + +### 下一步 + +为了使 pub/sub 基础设施可配置,我们需要: + +1. 为客户端/模式系统创建抽象接口 +2. 抽象 Pulsar 特定的枚举和异常 +3. 创建模式包装器或替代模式定义 +4. 为 Pulsar 和其他系统(Kafka、RabbitMQ、Redis Streams 等)实现该接口 +5. 更新 `pubsub.py` 以使其可配置并支持多个后端 +6. 提供现有部署的迁移路径 + +## 方法草案 1:带模式转换层的适配器模式 + +### 关键洞察 +**模式系统** 是最深入的集成点 - 其他一切都由此而产生。 我们需要首先解决这个问题,否则我们将重写整个代码库。 + +### 策略:通过适配器实现最小的干扰 + +**1. 保持 Pulsar 模式作为内部表示** +不要重写所有的模式定义 +模式在内部仍然是 `pulsar.schema.Record` +使用适配器在我们的代码和发布/订阅后端之间的边界进行转换 + +**2. 创建一个发布/订阅抽象层:** + +``` +┌─────────────────────────────────────┐ +│ Existing Code (unchanged) │ +│ - Uses Pulsar schemas internally │ +│ - Consumer/Producer/Publisher │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - Creates backend-specific client │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────┐ ┌────▼─────────┐ +│ PulsarAdapter│ │ KafkaAdapter │ etc... +│ (passthrough)│ │ (translates) │ +└──────────────┘ └──────────────┘ +``` + +**3. 定义抽象接口:** +`PubSubClient` - 客户端连接 +`PubSubProducer` - 发送消息 +`PubSubConsumer` - 接收消息 +`SchemaAdapter` - 将 Pulsar 模式转换为 JSON 或后端特定的格式,反之亦然 + +**4. 实现细节:** + +对于 **Pulsar 适配器**: 几乎是直通模式,最小化转换 + +对于 **其他后端** (Kafka, RabbitMQ 等): +将 Pulsar Record 对象序列化为 JSON/字节 +映射概念,例如: + `InitialPosition.Earliest/Latest` → Kafka 的 auto.offset.reset + `acknowledge()` → Kafka 的 commit + `negative_acknowledge()` → 重试或 DLQ 模式 + Topic URI → 后端特定的主题名称 + +### 分析 + +**优点:** +✅ 对现有服务的代码更改最小 +✅ 模式保持不变 (无需大规模重写) +✅ 逐步迁移路径 +✅ Pulsar 用户不会看到任何差异 +✅ 通过适配器添加新的后端 + +**缺点:** +⚠️ 仍然依赖 Pulsar (用于模式定义) +⚠️ 在转换概念时存在一些阻抗不匹配 + +### 替代方案 + +创建一个 **TrustGraph 模式系统**,该系统与 pub/sub 无关 (使用 dataclasses 或 Pydantic),然后从该系统生成 Pulsar/Kafka/等的模式。 这需要重写每个模式文件,并且可能导致不兼容的更改。 + +### 草案 1 的建议 + +从 **适配器方法** 开始,因为: +1. 它实用 - 与现有代码兼容 +2. 以最小的风险验证概念 +3. 如果需要,可以演变为原生模式系统 +4. 基于配置:一个环境变量切换后端 + +## 草案 2 方法:具有 Dataclasses 的后端无关模式系统 + +### 核心概念 + +使用 Python **dataclasses** 作为中立的模式定义格式。 每个 pub/sub 后端都提供自己的序列化/反序列化,以处理 dataclasses,从而无需在代码库中保留 Pulsar 模式。 + +### 工厂级别的模式多态 + +而是翻译 Pulsar 模式,**每个后端都提供自己的模式处理**,该处理方式适用于标准的 Python dataclasses。 + +### 发布者流程 + +```python +# 1. Get the configured backend from factory +pubsub = get_pubsub() # Returns PulsarBackend, MQTTBackend, etc. + +# 2. Get schema class from the backend +# (Can be imported directly - backend-agnostic) +from trustgraph.schema.services.llm import TextCompletionRequest + +# 3. Create a producer/publisher for a specific topic +producer = pubsub.create_producer( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend what schema to use +) + +# 4. Create message instances (same API regardless of backend) +request = TextCompletionRequest( + system="You are helpful", + prompt="Hello world", + streaming=False +) + +# 5. Send the message +producer.send(request) # Backend serializes appropriately +``` + +### 消费者流程 + +```python +# 1. Get the configured backend +pubsub = get_pubsub() + +# 2. Create a consumer +consumer = pubsub.subscribe( + topic="text-completion-requests", + schema=TextCompletionRequest # Tells backend how to deserialize +) + +# 3. Receive and deserialize +msg = consumer.receive() +request = msg.value() # Returns TextCompletionRequest dataclass instance + +# 4. Use the data (type-safe access) +print(request.system) # "You are helpful" +print(request.prompt) # "Hello world" +print(request.streaming) # False +``` + +### 幕后发生了什么 + +**对于 Pulsar 后端:** +`create_producer()` → 创建具有 JSON 模式或动态生成的记录的 Pulsar 生产者。 +`send(request)` → 将数据类序列化为 JSON/Pulsar 格式,并发送到 Pulsar。 +`receive()` → 获取 Pulsar 消息,将其反序列化回数据类。 + +**对于 MQTT 后端:** +`create_producer()` → 连接到 MQTT 代理,无需注册模式。 +`send(request)` → 将数据类转换为 JSON,并发布到 MQTT 主题。 +`receive()` → 订阅 MQTT 主题,并将 JSON 反序列化为数据类。 + +**对于 Kafka 后端:** +`create_producer()` → 创建 Kafka 生产者,如果需要,注册 Avro 模式。 +`send(request)` → 将数据类序列化为 Avro 格式,并发送到 Kafka。 +`receive()` → 获取 Kafka 消息,并将 Avro 反序列化回数据类。 + +### 关键设计点 + +1. **模式对象创建:** 数据类实例 (`TextCompletionRequest(...)`) 无论后端如何都是相同的。 +2. **后端处理编码:** 每个后端都知道如何将数据类序列化为线格式。 +3. **在创建时定义模式:** 在创建生产者/消费者时,您指定模式类型。 +4. **保留类型安全:** 您会得到一个正确的 `TextCompletionRequest` 对象,而不是一个字典。 +5. **没有后端泄漏:** 应用程序代码永远不会导入特定于后端的库。 + +### 示例转换 + +**当前(特定于 Pulsar):** +```python +# schema/services/llm.py +from pulsar.schema import Record, String, Boolean, Integer + +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() +``` + +**新功能(与后端无关):** +```python +# schema/services/llm.py +from dataclasses import dataclass + +@dataclass +class TextCompletionRequest: + system: str + prompt: str + streaming: bool = False +``` + +### 后端集成 + +每个后端负责数据类的序列化/反序列化: + +**Pulsar 后端:** +从数据类动态生成 `pulsar.schema.Record` 类 +或者将数据类序列化为 JSON,并使用 Pulsar 的 JSON 模式 +保持与现有 Pulsar 部署的兼容性 + +**MQTT/Redis 后端:** +直接对数据类实例进行 JSON 序列化 +使用 `dataclasses.asdict()` / `from_dict()` +轻量级,无需模式注册表 + +**Kafka 后端:** +从数据类定义生成 Avro 模式 +使用 Confluent 的模式注册表 +具有模式演进支持的类型安全序列化 + +### 架构 + +``` +┌─────────────────────────────────────┐ +│ Application Code │ +│ - Uses dataclass schemas │ +│ - Backend-agnostic │ +└──────────────┬──────────────────────┘ + │ +┌──────────────┴──────────────────────┐ +│ PubSubFactory (configurable) │ +│ - get_pubsub() returns backend │ +└──────────────┬──────────────────────┘ + │ + ┌──────┴──────┐ + │ │ +┌───────▼─────────┐ ┌────▼──────────────┐ +│ PulsarBackend │ │ MQTTBackend │ +│ - JSON schema │ │ - JSON serialize │ +│ - or dynamic │ │ - Simple queues │ +│ Record gen │ │ │ +└─────────────────┘ └───────────────────┘ +``` + +### 实现细节 + +**1. 模式定义:** 使用带有类型提示的简单数据类 + `str`, `int`, `bool`, `float` 用于基本类型 + `list[T]` 用于数组 + `dict[str, T]` 用于映射 + 用于复杂类型的嵌套数据类 + +**2. 每个后端提供:** + 序列化器:`dataclass → bytes/wire format` + 反序列化器:`bytes/wire format → dataclass` + 模式注册(如果需要,例如 Pulsar/Kafka) + +**3. 消费者/生产者抽象:** + 已经存在 (consumer.py, producer.py) + 更新以使用后端的序列化 + 移除直接的 Pulsar 导入 + +**4. 类型映射:** + Pulsar `String()` → Python `str` + Pulsar `Integer()` → Python `int` + Pulsar `Boolean()` → Python `bool` + Pulsar `Array(T)` → Python `list[T]` + Pulsar `Map(K, V)` → Python `dict[K, V]` + Pulsar `Double()` → Python `float` + Pulsar `Bytes()` → Python `bytes` + +### 迁移路径 + +1. **创建所有模式的数据类版本**,位于 `trustgraph/schema/` +2. **更新后端类**(Consumer, Producer, Publisher, Subscriber),以使用后端提供的序列化 +3. **实现 PulsarBackend**,使用 JSON 模式或动态 Record 生成 +4. **使用 Pulsar 进行测试**,以确保与现有部署的向后兼容性 +5. **添加新的后端**(MQTT, Kafka, Redis 等),如果需要 +6. **从模式文件中移除 Pulsar 导入** + +### 优点 + +✅ **模式定义中没有 pub/sub 依赖** +✅ **标准 Python** - 易于理解、类型检查和记录 +✅ **现代工具** - 与 mypy、IDE 自动完成、linter 兼容 +✅ **后端优化** - 每个后端使用本机序列化 +✅ **没有翻译开销** - 直接序列化,没有适配器 +✅ **类型安全** - 具有正确类型的真实对象 +✅ **易于验证** - 如果需要,可以使用 Pydantic + +### 挑战与解决方案 + +**挑战:** Pulsar 的 `Record` 具有运行时字段验证 +**解决方案:** 如果需要,可以使用 Pydantic 数据类进行验证,或者使用 Python 3.10+ 数据类功能,并结合 `__post_init__` + +**挑战:** 一些 Pulsar 特定的功能(例如 `Bytes` 类型) +**解决方案:** 将其映射到数据类中的 `bytes` 类型,后端负责适当的编码 + +**挑战:** 主题命名(`persistent://tenant/namespace/topic`) +**解决方案:** 在模式定义中抽象主题名称,后端将其转换为正确的格式 + +**挑战:** 模式演化和版本控制 +**解决方案:** 每个后端根据其功能处理此问题(Pulsar 模式版本、Kafka 模式注册等) + +**挑战:** 嵌套的复杂类型 +**解决方案:** 使用嵌套的数据类,后端递归地序列化/反序列化 + +### 设计决策 + +1. **使用纯数据类还是 Pydantic?** + ✅ **决策:使用纯 Python 数据类** + 更简单,没有额外的依赖 + 实际上不需要验证 + 更容易理解和维护 + +2. **模式演化:** + ✅ **决策:不需要版本机制** + 模式是稳定且持久的 + 更新通常会添加新字段(向后兼容) + 后端根据其功能处理模式演化 + +3. **向后兼容性:** + ✅ **决策:进行主要版本更改,不需要向后兼容** + 这将是一个破坏性更改,并提供迁移说明 + 清理的断开允许更好的设计 + 将为现有部署提供迁移指南 + +4. **嵌套类型和复杂结构:** + ✅ **决策:自然地使用嵌套的数据类** + Python 数据类完美地处理嵌套 + `list[T]` 用于数组,`dict[K, V]` 用于映射 + 后端递归地序列化/反序列化 + 示例: + ```python + @dataclass + class Value: + value: str + is_uri: bool + + @dataclass + class Triple: + s: Value # Nested dataclass + p: Value + o: Value + + @dataclass + class GraphQuery: + triples: list[Triple] # Array of nested dataclasses + metadata: dict[str, str] + ``` + +5. **默认值和可选字段:** + ✅ **决策:强制、默认和可选字段的组合** + 强制字段:没有默认值 + 具有默认值的字段:始终存在,具有合理的默认值 + 真正可选的字段:`T | None = None`,当`None`时,从序列化中省略 + 示例: + ```python + @dataclass + class TextCompletionRequest: + system: str # Required, no default + prompt: str # Required, no default + streaming: bool = False # Optional with default value + metadata: dict | None = None # Truly optional, can be absent + ``` + + **重要的序列化语义:** + + 当 `metadata = None`: + ```json + { + "system": "...", + "prompt": "...", + "streaming": false + // metadata field NOT PRESENT + } + ``` + + 当 `metadata = {}` (显式为空): + ```json + { + "system": "...", + "prompt": "...", + "streaming": false, + "metadata": {} // Field PRESENT but empty + } + ``` + + **关键区别:** + `None` → JSON 中不存在的字段(未序列化) + 空值(`{}`, `[]`, `""`)→ 字段存在,但值为空 + 这在语义上很重要:“未提供”与“显式为空” + 序列化后端必须跳过 `None` 字段,而不是将其编码为 `null` + +## 方案草案 3:实现细节 + +### 通用队列命名格式 + +将后端特定的队列名称替换为一种通用格式,以便后端可以进行适当的映射。 + +**格式:** `{qos}/{tenant}/{namespace}/{queue-name}` + +其中: +`qos`:服务质量级别 + `q0` = 尽力而为(发送并忘记,无需确认) + `q1` = 至少一次(需要确认) + `q2` = 恰好一次(两阶段确认) +`tenant`:多租户逻辑分组 +`namespace`:租户内的子分组 +`queue-name`:实际的队列/主题名称 + +**示例:** +``` +q1/tg/flow/text-completion-requests +q2/tg/config/config-push +q0/tg/metrics/stats +``` + +### 后端主题映射 + +每个后端将通用格式映射到其原生格式: + +**Pulsar 后端:** +```python +def map_topic(self, generic_topic: str) -> str: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS to persistence + persistence = 'persistent' if qos in ['q1', 'q2'] else 'non-persistent' + + # Return Pulsar URI: persistent://tg/flow/text-completion-requests + return f"{persistence}://{tenant}/{namespace}/{queue}" +``` + +**MQTT 后端:** +```python +def map_topic(self, generic_topic: str) -> tuple[str, int]: + # Parse: q1/tg/flow/text-completion-requests + qos, tenant, namespace, queue = generic_topic.split('/', 3) + + # Map QoS level + qos_level = {'q0': 0, 'q1': 1, 'q2': 2}[qos] + + # Build MQTT topic including tenant/namespace for proper namespacing + mqtt_topic = f"{tenant}/{namespace}/{queue}" + + return mqtt_topic, qos_level +``` + +### 更新后的主题辅助函数 + +```python +# schema/core/topic.py +def topic(queue_name, qos='q1', tenant='tg', namespace='flow'): + """ + Create a generic topic identifier that can be mapped by backends. + + Args: + queue_name: The queue/topic name + qos: Quality of service + - 'q0' = best-effort (no ack) + - 'q1' = at-least-once (ack required) + - 'q2' = exactly-once (two-phase ack) + tenant: Tenant identifier for multi-tenancy + namespace: Namespace within tenant + + Returns: + Generic topic string: qos/tenant/namespace/queue_name + + Examples: + topic('my-queue') # q1/tg/flow/my-queue + topic('config', qos='q2', namespace='config') # q2/tg/config/config + """ + return f"{qos}/{tenant}/{namespace}/{queue_name}" +``` + +### 配置和初始化 + +**命令行参数 + 环境变量:** + +```python +# In base/async_processor.py - add_args() method +@staticmethod +def add_args(parser): + # Pub/sub backend selection + parser.add_argument( + '--pubsub-backend', + default=os.getenv('PUBSUB_BACKEND', 'pulsar'), + choices=['pulsar', 'mqtt'], + help='Pub/sub backend (default: pulsar, env: PUBSUB_BACKEND)' + ) + + # Pulsar-specific configuration + parser.add_argument( + '--pulsar-host', + default=os.getenv('PULSAR_HOST', 'pulsar://localhost:6650'), + help='Pulsar host (default: pulsar://localhost:6650, env: PULSAR_HOST)' + ) + + parser.add_argument( + '--pulsar-api-key', + default=os.getenv('PULSAR_API_KEY', None), + help='Pulsar API key (env: PULSAR_API_KEY)' + ) + + parser.add_argument( + '--pulsar-listener', + default=os.getenv('PULSAR_LISTENER', None), + help='Pulsar listener name (env: PULSAR_LISTENER)' + ) + + # MQTT-specific configuration + parser.add_argument( + '--mqtt-host', + default=os.getenv('MQTT_HOST', 'localhost'), + help='MQTT broker host (default: localhost, env: MQTT_HOST)' + ) + + parser.add_argument( + '--mqtt-port', + type=int, + default=int(os.getenv('MQTT_PORT', '1883')), + help='MQTT broker port (default: 1883, env: MQTT_PORT)' + ) + + parser.add_argument( + '--mqtt-username', + default=os.getenv('MQTT_USERNAME', None), + help='MQTT username (env: MQTT_USERNAME)' + ) + + parser.add_argument( + '--mqtt-password', + default=os.getenv('MQTT_PASSWORD', None), + help='MQTT password (env: MQTT_PASSWORD)' + ) +``` + +**工厂函数:** + +```python +# In base/pubsub.py or base/pubsub_factory.py +def get_pubsub(**config) -> PubSubBackend: + """ + Create and return a pub/sub backend based on configuration. + + Args: + config: Configuration dict from command-line args + Must include 'pubsub_backend' key + + Returns: + Backend instance (PulsarBackend, MQTTBackend, etc.) + """ + backend_type = config.get('pubsub_backend', 'pulsar') + + if backend_type == 'pulsar': + return PulsarBackend( + host=config.get('pulsar_host'), + api_key=config.get('pulsar_api_key'), + listener=config.get('pulsar_listener'), + ) + elif backend_type == 'mqtt': + return MQTTBackend( + host=config.get('mqtt_host'), + port=config.get('mqtt_port'), + username=config.get('mqtt_username'), + password=config.get('mqtt_password'), + ) + else: + raise ValueError(f"Unknown pub/sub backend: {backend_type}") +``` + +**在 AsyncProcessor 中的用法:** + +```python +# In async_processor.py +class AsyncProcessor: + def __init__(self, **params): + self.id = params.get("id") + + # Create backend from config (replaces PulsarClient) + self.pubsub = get_pubsub(**params) + + # Rest of initialization... +``` + +### 后端接口 + +```python +class PubSubBackend(Protocol): + """Protocol defining the interface all pub/sub backends must implement.""" + + def create_producer(self, topic: str, schema: type, **options) -> BackendProducer: + """ + Create a producer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + schema: Dataclass type for messages + options: Backend-specific options (e.g., chunking_enabled) + + Returns: + Backend-specific producer instance + """ + ... + + def create_consumer( + self, + topic: str, + subscription: str, + schema: type, + initial_position: str = 'latest', + consumer_type: str = 'shared', + **options + ) -> BackendConsumer: + """ + Create a consumer for a topic. + + Args: + topic: Generic topic format (qos/tenant/namespace/queue) + subscription: Subscription/consumer group name + schema: Dataclass type for messages + initial_position: 'earliest' or 'latest' (MQTT may ignore) + consumer_type: 'shared', 'exclusive', 'failover' (MQTT may ignore) + options: Backend-specific options + + Returns: + Backend-specific consumer instance + """ + ... + + def close(self) -> None: + """Close the backend connection.""" + ... +``` + +```python +class BackendProducer(Protocol): + """Protocol for backend-specific producer.""" + + def send(self, message: Any, properties: dict = {}) -> None: + """Send a message (dataclass instance) with optional properties.""" + ... + + def flush(self) -> None: + """Flush any buffered messages.""" + ... + + def close(self) -> None: + """Close the producer.""" + ... +``` + +```python +class BackendConsumer(Protocol): + """Protocol for backend-specific consumer.""" + + def receive(self, timeout_millis: int = 2000) -> Message: + """ + Receive a message from the topic. + + Raises: + TimeoutError: If no message received within timeout + """ + ... + + def acknowledge(self, message: Message) -> None: + """Acknowledge successful processing of a message.""" + ... + + def negative_acknowledge(self, message: Message) -> None: + """Negative acknowledge - triggers redelivery.""" + ... + + def unsubscribe(self) -> None: + """Unsubscribe from the topic.""" + ... + + def close(self) -> None: + """Close the consumer.""" + ... +``` + +```python +class Message(Protocol): + """Protocol for a received message.""" + + def value(self) -> Any: + """Get the deserialized message (dataclass instance).""" + ... + + def properties(self) -> dict: + """Get message properties/metadata.""" + ... +``` + +### 现有类的重构 + +现有的 `Consumer`、`Producer`、`Publisher`、`Subscriber` 类在很大程度上保持不变: + +**当前职责(保留):** +异步线程模型和任务组 +重连逻辑和重试处理 +指标收集 +速率限制 +并发管理 + +**需要更改的内容:** +移除直接的 Pulsar 导入(`pulsar.schema`、`pulsar.InitialPosition` 等) +接受 `BackendProducer`/`BackendConsumer` 而不是 Pulsar 客户端 +将实际的发布/订阅操作委托给后端实例 +将通用概念映射到后端调用 + +**重构示例:** + +```python +# OLD - consumer.py +class Consumer: + def __init__(self, client, topic, subscriber, schema, ...): + self.client = client # Direct Pulsar client + # ... + + async def consumer_run(self): + # Uses pulsar.InitialPosition, pulsar.ConsumerType + self.consumer = self.client.subscribe( + topic=self.topic, + schema=JsonSchema(self.schema), + initial_position=pulsar.InitialPosition.Earliest, + consumer_type=pulsar.ConsumerType.Shared, + ) + +# NEW - consumer.py +class Consumer: + def __init__(self, backend_consumer, schema, ...): + self.backend_consumer = backend_consumer # Backend-specific consumer + self.schema = schema + # ... + + async def consumer_run(self): + # Backend consumer already created with right settings + # Just use it directly + while self.running: + msg = await asyncio.to_thread( + self.backend_consumer.receive, + timeout_millis=2000 + ) + await self.handle_message(msg) +``` + +### 后端特定行为 + +**Pulsar 后端:** +将 `q0` 映射到 `non-persistent://`,将 `q1`/`q2` 映射到 `persistent://` +支持所有类型的消费者(共享、独占、故障转移) +支持初始位置(最早/最新) +原生消息确认 +模式注册支持 + +**MQTT 后端:** +将 `q0`/`q1`/`q2` 映射到 MQTT QoS 等级 0/1/2 +在主题路径中包含租户/命名空间,以进行命名空间划分 +根据订阅名称自动生成客户端 ID +忽略初始位置(基本的 MQTT 中没有消息历史) +忽略消费者类型(MQTT 使用客户端 ID,而不是消费者组) +简单的发布/订阅模型 + +### 设计决策摘要 + +1. ✅ **通用队列命名:** `qos/tenant/namespace/queue-name` 格式 +2. ✅ **队列 ID 中的 QoS:** 由队列定义确定,而不是配置 +3. ✅ **重连:** 由 Consumer/Producer 类处理,而不是后端 +4. ✅ **MQTT 主题:** 包含租户/命名空间以进行正确的命名空间划分 +5. ✅ **消息历史:** MQTT 忽略 `initial_position` 参数(未来增强) +6. ✅ **客户端 ID:** MQTT 后端根据订阅名称自动生成 + +### 未来增强 + +**MQTT 消息历史:** +可以添加可选的持久层(例如,保留的消息、外部存储) +将允许支持 `initial_position='earliest'` +不适用于初始实现 + diff --git a/docs/tech-specs/python-api-refactor.ar.md b/docs/tech-specs/python-api-refactor.ar.md new file mode 100644 index 00000000..c6c225c3 --- /dev/null +++ b/docs/tech-specs/python-api-refactor.ar.md @@ -0,0 +1,1508 @@ +# مواصفات فنية لإعادة هيكلة واجهة برمجة التطبيقات (API) الخاصة بـ Python + +## نظرة عامة + +تصف هذه المواصفات إعادة هيكلة شاملة لمكتبة عميل واجهة برمجة التطبيقات (API) الخاصة بـ Python لـ TrustGraph لتحقيق التوافق مع واجهة برمجة التطبيقات (API) والبوابة وإضافة دعم لأنماط الاتصال في الوقت الفعلي الحديثة. + +تعالج عملية إعادة الهيكلة أربعة استخدامات رئيسية: + +1. **تفاعلات LLM المتدفقة**: تمكين التدفق في الوقت الفعلي لنتائج LLM (الوكيل، والبحث الدلالي في الرسم البياني، والبحث الدلالي في المستند، وإكمال النص، والموجهات) مع زمن انتقال أقل بنسبة 60 مرة (500 مللي ثانية مقابل 30 ثانية للرمز المميز الأول). +2. **عمليات البيانات المجمعة**: دعم الاستيراد/التصدير المجمع الفعال للثلاثيات، وتضمينات الرسم البياني، وتضمينات المستند لإدارة الرسوم البيانية المعرفية واسعة النطاق. +3. **التوافق مع واجهة برمجة التطبيقات (API)**: التأكد من أن كل نقطة نهاية في واجهة برمجة التطبيقات (API) والبوابة لديها طريقة واجهة برمجة تطبيقات (API) Python مقابلة، بما في ذلك استعلام تضمينات الرسم البياني. +4. **اتصالات مستمرة**: تمكين الاتصال المستند إلى WebSocket للطلبات متعددة المهام وتقليل النفقات العامة للاتصال. + +## الأهداف + +**التوافق مع واجهة برمجة التطبيقات (API)**: كل خدمة في واجهة برمجة التطبيقات (API) والبوابة لديها طريقة واجهة برمجة تطبيقات (API) Python مقابلة. +**دعم التدفق**: تدعم جميع الخدمات القادرة على التدفق (الوكيل، والبحث الدلالي، وإكمال النص، والموجه) التدفق في واجهة برمجة تطبيقات (API) Python. +**طبقة نقل WebSocket**: إضافة طبقة نقل WebSocket اختيارية للاتصالات المستمرة والتجميع. +**العمليات المجمعة**: إضافة استيراد/تصدير مجمع فعال للثلاثيات، وتضمينات الرسم البياني، وتضمينات المستند. +**دعم كامل غير متزامن**: تطبيق كامل لـ async/await لجميع الواجهات (REST، WebSocket، العمليات المجمعة، المقاييس). +**التوافق مع الإصدارات السابقة**: يستمر الكود الحالي في العمل دون تعديل. +**أمان النوع**: الحفاظ على واجهات آمنة من النوع باستخدام dataclasses وتلميحات النوع. +**التحسين التدريجي**: التدفق وغير المتزامن هما خياران ويمكن تفعيلهما من خلال اختيار الواجهة الصريح. +**الأداء**: تحقيق تحسين بنسبة 60٪ في زمن الانتقال لعمليات التدفق. +**Python حديثة**: دعم كل من نماذج المزامنة وغير المتزامنة لأقصى قدر من المرونة. + +## الخلفية + +### الحالة الحالية + +واجهة برمجة التطبيقات (API) الخاصة بـ Python (`trustgraph-base/trustgraph/api/`) هي مكتبة عميل REST فقط مع الوحدات التالية: + +`flow.py`: إدارة التدفق والخدمات ذات النطاق التدريجي (50 طريقة). +`library.py`: عمليات مكتبة المستندات (9 طرق). +`knowledge.py`: إدارة النواة الخاصة بالرسم البياني (4 طرق). +`collection.py`: بيانات وصف المجموعة (3 طرق). +`config.py`: إدارة التكوين (6 طرق). +`types.py`: تعريفات أنواع البيانات (5 dataclasses). + +**إجمالي العمليات**: 50/59 (تغطية بنسبة 85٪). + +### القيود الحالية + +**العمليات المفقودة**: +استعلام تضمينات الرسم البياني (البحث الدلالي عن كيانات الرسم البياني). +استيراد/تصدير مجمع للثلاثيات، وتضمينات الرسم البياني، وتضمينات المستند، وسياقات الكيانات، والكائنات. +نقطة نهاية المقاييس. + +**القدرات المفقودة**: +دعم البث لخدمات نماذج اللغة الكبيرة (LLM). +بروتوكول نقل WebSocket. +طلبات متزامنة متعددة. +اتصالات مستمرة. + +**مشكلات الأداء**: +زمن انتقال مرتفع لتفاعلات نماذج اللغة الكبيرة (حوالي 30 ثانية للرمز الأول). +نقل بيانات مجمعة غير فعال (طلب REST لكل عنصر). +تكلفة الاتصال لعمليات متسلسلة متعددة. + +**مشكلات تجربة المستخدم**: +عدم وجود ملاحظات في الوقت الفعلي أثناء توليد نماذج اللغة الكبيرة. +عدم القدرة على إلغاء العمليات الطويلة الأمد لنماذج اللغة الكبيرة. +قابلية توسع ضعيفة للعمليات المجمعة. + +### التأثير + +أدى التحسين الذي تم تقديمه في نوفمبر 2024 للبث في واجهة برمجة التطبيقات (API) للـ Gateway إلى تحسين زمن الانتقال بمقدار 60 مرة (500 مللي ثانية مقابل 30 ثانية للرمز الأول) لتفاعلات نماذج اللغة الكبيرة، ولكن مستخدمي واجهة برمجة التطبيقات Python لا يمكنهم الاستفادة من هذه الإمكانية. وهذا يخلق فجوة كبيرة في تجربة المستخدم بين مستخدمي Python وغير مستخدمي Python. + +## التصميم التقني + +### البنية + +تستخدم واجهة برمجة التطبيقات Python المعاد تصميمها **نهج واجهة معيارية** مع كائنات منفصلة لأنماط الاتصال المختلفة. تتوفر جميع الواجهات في كل من الإصدارات **المزامنة وغير المتزامنة**: + +1. **واجهة REST** (موجودة، مُحسّنة) + **المزامنة**: `api.flow()`، `api.library()`، `api.knowledge()`، `api.collection()`، `api.config()` + **غير متزامنة**: `api.async_flow()` + طلب/استجابة متزامنة/غير متزامنة. + نموذج اتصال بسيط. + الافتراضي للتوافق مع الإصدارات السابقة. + +2. **واجهة WebSocket** (جديدة) + **المزامنة**: `api.socket()` + **غير متزامنة**: `api.async_socket()` + اتصال مستمر. + طلبات متعددة. + دعم البث. + نفس توقيعات الأساليب مثل REST حيث تتداخل الوظائف. + +3. **واجهة العمليات المجمعة** (جديدة) + **المزامنة**: `api.bulk()` + **غير متزامنة**: `api.async_bulk()` + تعتمد على WebSocket للكفاءة. + استيراد/تصدير يعتمد على المكرر/AsyncIterator. + تتعامل مع مجموعات البيانات الكبيرة. + +4. **واجهة المقاييس** (جديدة) + **المزامنة**: `api.metrics()` + **غير متزامنة**: `api.async_metrics()` + الوصول إلى مقاييس Prometheus. + +```python +import asyncio + +# Synchronous interfaces +api = Api(url="http://localhost:8088/") + +# REST (existing, unchanged) +flow = api.flow().id("default") +response = flow.agent(question="...", user="...") + +# WebSocket (new) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="...", user="...") +for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk) + +# Bulk operations (new) +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Asynchronous interfaces +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST (new) + flow = api.async_flow().id("default") + response = await flow.agent(question="...", user="...") + + # Async WebSocket (new) + socket_flow = api.async_socket().flow("default") + async for chunk in socket_flow.agent(question="...", streaming=True): + print(chunk) + + # Async bulk operations (new) + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + +asyncio.run(main()) +``` + +**المبادئ الأساسية للتصميم:** +**نفس عنوان URL لجميع الواجهات:** `Api(url="http://localhost:8088/")` يعمل مع جميع الواجهات. +**التماثل بين المتزامن وغير المتزامن:** كل واجهة لديها إصدارات متزامنة وغير متزامنة مع توقيعات طرق متطابقة. +**توقيعات متطابقة:** حيث تتداخل الوظائف، تكون توقيعات الطرق متطابقة بين REST و WebSocket، والمتزامن وغير المتزامن. +**التحسين التدريجي:** اختر الواجهة بناءً على الاحتياجات (REST للعمليات البسيطة، WebSocket للبث، Bulk لمجموعات البيانات الكبيرة، وغير المتزامن للإطارات الحديثة). +**نية صريحة:** `api.socket()` يشير إلى WebSocket، و `api.async_socket()` يشير إلى WebSocket غير المتزامن. +**متوافق مع الإصدارات السابقة:** الكود الحالي لا يتغير. + +### المكونات + +#### 1. فئة واجهة برمجة التطبيقات الأساسية (معدلة) + +الوحدة: `trustgraph-base/trustgraph/api/api.py` + +**فئة واجهة برمجة التطبيقات المحسنة:** + +```python +class Api: + def __init__(self, url: str, timeout: int = 60, token: Optional[str] = None): + self.url = url + self.timeout = timeout + self.token = token # Optional bearer token for REST, query param for WebSocket + self._socket_client = None + self._bulk_client = None + self._async_flow = None + self._async_socket_client = None + self._async_bulk_client = None + + # Existing synchronous methods (unchanged) + def flow(self) -> Flow: + """Synchronous REST-based flow interface""" + pass + + def library(self) -> Library: + """Synchronous REST-based library interface""" + pass + + def knowledge(self) -> Knowledge: + """Synchronous REST-based knowledge interface""" + pass + + def collection(self) -> Collection: + """Synchronous REST-based collection interface""" + pass + + def config(self) -> Config: + """Synchronous REST-based config interface""" + pass + + # New synchronous methods + def socket(self) -> SocketClient: + """Synchronous WebSocket-based interface for streaming operations""" + if self._socket_client is None: + self._socket_client = SocketClient(self.url, self.timeout, self.token) + return self._socket_client + + def bulk(self) -> BulkClient: + """Synchronous bulk operations interface for import/export""" + if self._bulk_client is None: + self._bulk_client = BulkClient(self.url, self.timeout, self.token) + return self._bulk_client + + def metrics(self) -> Metrics: + """Synchronous metrics interface""" + return Metrics(self.url, self.timeout, self.token) + + # New asynchronous methods + def async_flow(self) -> AsyncFlow: + """Asynchronous REST-based flow interface""" + if self._async_flow is None: + self._async_flow = AsyncFlow(self.url, self.timeout, self.token) + return self._async_flow + + def async_socket(self) -> AsyncSocketClient: + """Asynchronous WebSocket-based interface for streaming operations""" + if self._async_socket_client is None: + self._async_socket_client = AsyncSocketClient(self.url, self.timeout, self.token) + return self._async_socket_client + + def async_bulk(self) -> AsyncBulkClient: + """Asynchronous bulk operations interface for import/export""" + if self._async_bulk_client is None: + self._async_bulk_client = AsyncBulkClient(self.url, self.timeout, self.token) + return self._async_bulk_client + + def async_metrics(self) -> AsyncMetrics: + """Asynchronous metrics interface""" + return AsyncMetrics(self.url, self.timeout, self.token) + + # Resource management + def close(self) -> None: + """Close all synchronous connections""" + if self._socket_client: + self._socket_client.close() + if self._bulk_client: + self._bulk_client.close() + + async def aclose(self) -> None: + """Close all asynchronous connections""" + if self._async_socket_client: + await self._async_socket_client.aclose() + if self._async_bulk_client: + await self._async_bulk_client.aclose() + if self._async_flow: + await self._async_flow.aclose() + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + async def __aenter__(self): + return self + + async def __aexit__(self, *args): + await self.aclose() +``` + +#### 2. عميل WebSocket المتزامن + +الوحدة: `trustgraph-base/trustgraph/api/socket_client.py` (جديد) + +**فئة SocketClient:** + +```python +class SocketClient: + """Synchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> SocketFlowInstance: + """Get flow instance for WebSocket operations""" + return SocketFlowInstance(self, flow_id) + + def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Uses asyncio.run() internally to wrap async websockets library + pass + + def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + # Synchronous wrapper around async WebSocket calls + pass + + def close(self) -> None: + """Close WebSocket connection""" + pass + +class SocketFlowInstance: + """Synchronous WebSocket flow instance with same interface as REST FlowInstance""" + def __init__(self, client: SocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance + def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, Iterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**الميزات الرئيسية:** +اتصال كسول (يتصل فقط عند إرسال الطلب الأول) +تعدد الطلبات (حتى 15 طلبًا متزامنًا) +إعادة الاتصال التلقائي عند الانفصال +تحليل الاستجابة المتدفقة +تشغيل آمن للخيوط +غلاف متزامن حول مكتبة WebSocket غير المتزامنة + +#### 3. عميل WebSocket غير المتزامن + +الوحدة: `trustgraph-base/trustgraph/api/async_socket_client.py` (جديد) + +**فئة AsyncSocketClient:** + +```python +class AsyncSocketClient: + """Asynchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> AsyncSocketFlowInstance: + """Get async flow instance for WebSocket operations""" + return AsyncSocketFlowInstance(self, flow_id) + + async def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Native async websockets library + pass + + async def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + pass + + async def aclose(self) -> None: + """Close WebSocket connection""" + pass + +class AsyncSocketFlowInstance: + """Asynchronous WebSocket flow instance""" + def __init__(self, client: AsyncSocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance (but async) + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, AsyncIterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**الميزات الرئيسية:** +دعم أصلي لـ async/await. +فعال للتطبيقات غير المتزامنة (FastAPI, aiohttp). +لا يوجد حظر للخيوط. +نفس الواجهة مثل الإصدار المتزامن. +AsyncIterator للتدفق. + +#### 4. عميل العمليات المجمعة المتزامنة + +الوحدة: `trustgraph-base/trustgraph/api/bulk_client.py` (جديد) + +**فئة BulkClient:** + +```python +class BulkClient: + """Synchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + def import_triples( + self, + flow: str, + triples: Iterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + def export_triples( + self, + flow: str, + **kwargs + ) -> Iterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + def import_graph_embeddings( + self, + flow: str, + embeddings: Iterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> Iterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + def close(self) -> None: + """Close connections""" + pass +``` + +**الميزات الرئيسية:** +يعتمد على التكرار لاستخدام ذاكرة ثابتة. +اتصالات WebSocket مخصصة لكل عملية. +تتبع التقدم (وظيفة رد اتصال اختيارية). +معالجة الأخطاء مع إمكانية الإبلاغ عن النجاح الجزئي. + +#### 5. عميل العمليات المجمعة غير المتزامنة + +الوحدة: `trustgraph-base/trustgraph/api/async_bulk_client.py` (جديد) + +**فئة AsyncBulkClient:** + +```python +class AsyncBulkClient: + """Asynchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + async def import_triples( + self, + flow: str, + triples: AsyncIterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + async def export_triples( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + async def import_graph_embeddings( + self, + flow: str, + embeddings: AsyncIterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + async def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + async def aclose(self) -> None: + """Close connections""" + pass +``` + +**الميزات الرئيسية:** +يعتمد على AsyncIterator للاستهلاك الثابت للذاكرة. +فعال للتطبيقات غير المتزامنة. +دعم أصلي لـ async/await. +نفس الواجهة مثل الإصدار المتزامن. + +#### 6. واجهة برمجة تطبيقات REST (متزامنة - دون تغيير) + +الوحدة: `trustgraph-base/trustgraph/api/flow.py` + +تظل واجهة برمجة تطبيقات REST **دون أي تغيير** لضمان التوافق مع الإصدارات السابقة. جميع الطرق الحالية تظل تعمل: + +`Flow.list()`، `Flow.start()`، `Flow.stop()`، إلخ. +`FlowInstance.agent()`، `FlowInstance.text_completion()`، `FlowInstance.graph_rag()`، إلخ. +تم الحفاظ على جميع التوقيعات وأنواع الإرجاع الحالية. + +**جديد:** إضافة `graph_embeddings_query()` إلى REST FlowInstance لتحقيق التوافق في الميزات: + +```python +class FlowInstance: + # All existing methods unchanged... + + # New: Graph embeddings query (REST) + def graph_embeddings_query( + self, + text: str, + user: str, + collection: str, + limit: int = 10, + **kwargs + ) -> List[Dict[str, Any]]: + """Query graph embeddings for semantic search""" + # Calls POST /api/v1/flow/{flow}/service/graph-embeddings + pass +``` + +#### 7. واجهة برمجة تطبيقات REST غير المتزامنة + +الوحدة: `trustgraph-base/trustgraph/api/async_flow.py` (جديد) + +**الفئات AsyncFlow و AsyncFlowInstance:** + +```python +class AsyncFlow: + """Asynchronous REST-based flow interface""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def list(self) -> List[Dict[str, Any]]: + """List all flows""" + pass + + async def get(self, id: str) -> Dict[str, Any]: + """Get flow definition""" + pass + + async def start(self, class_name: str, id: str, description: str, parameters: Dict) -> None: + """Start a flow""" + pass + + async def stop(self, id: str) -> None: + """Stop a flow""" + pass + + def id(self, flow_id: str) -> AsyncFlowInstance: + """Get async flow instance""" + return AsyncFlowInstance(self.url, self.timeout, self.token, flow_id) + + async def aclose(self) -> None: + """Close connection""" + pass + +class AsyncFlowInstance: + """Asynchronous REST flow instance""" + + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + **kwargs + ) -> Dict[str, Any]: + """Async agent execution""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + **kwargs + ) -> str: + """Async text completion""" + pass + + async def graph_rag( + self, + question: str, + user: str, + collection: str, + **kwargs + ) -> str: + """Async graph RAG""" + pass + + # ... all other FlowInstance methods as async versions +``` + +**الميزات الرئيسية:** +دعم غير متزامن لبروتوكول HTTP باستخدام `aiohttp` أو `httpx`. +نفس توقيعات الأساليب لواجهة برمجة تطبيقات REST المتزامنة. +لا يوجد بث (استخدم `async_socket()` للبث). +فعال للتطبيقات غير المتزامنة. + +#### 8. واجهة برمجة تطبيقات المقاييس + +الوحدة: `trustgraph-base/trustgraph/api/metrics.py` (جديد). + +**المقاييس المتزامنة:** + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +**المقاييس غير المتزامنة:** + +```python +class AsyncMetrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +#### 9. الأنواع المحسنة + +الوحدة: `trustgraph-base/trustgraph/api/types.py` (معدلة) + +**أنواع جديدة:** + +```python +from typing import Iterator, Union, Dict, Any +import dataclasses + +@dataclasses.dataclass +class StreamingChunk: + """Base class for streaming chunks""" + content: str + end_of_message: bool = False + +@dataclasses.dataclass +class AgentThought(StreamingChunk): + """Agent reasoning chunk""" + chunk_type: str = "thought" + +@dataclasses.dataclass +class AgentObservation(StreamingChunk): + """Agent tool observation chunk""" + chunk_type: str = "observation" + +@dataclasses.dataclass +class AgentAnswer(StreamingChunk): + """Agent final answer chunk""" + chunk_type: str = "final-answer" + end_of_dialog: bool = False + +@dataclasses.dataclass +class RAGChunk(StreamingChunk): + """RAG streaming chunk""" + end_of_stream: bool = False + error: Optional[Dict[str, str]] = None + +# Type aliases for clarity +AgentStream = Iterator[Union[AgentThought, AgentObservation, AgentAnswer]] +RAGStream = Iterator[RAGChunk] +CompletionStream = Iterator[str] +``` + +#### 6. واجهة برمجة التطبيقات (API) للمقاييس + +الوحدة: `trustgraph-base/trustgraph/api/metrics.py` (جديد) + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +### نهج التنفيذ + +#### المرحلة الأولى: تحسين واجهة برمجة التطبيقات الأساسية (الأسبوع الأول) + +1. إضافة طرق `socket()` و `bulk()` و `metrics()` إلى الفئة `Api` +2. تنفيذ التهيئة الكسولة لعملاء WebSocket والكمية الكبيرة +3. إضافة دعم لإدارة السياق (`__enter__`، `__exit__`) +4. إضافة طريقة `close()` للتنظيف +5. إضافة اختبارات وحدة لتحسينات فئة واجهة برمجة التطبيقات +6. التحقق من التوافق مع الإصدارات السابقة + +**التوافق مع الإصدارات السابقة**: لا توجد تغييرات تؤثر على الإصدارات السابقة. طرق جديدة فقط. + +#### المرحلة الثانية: عميل WebSocket (الأسبوعان الثاني والثالث) + +1. تنفيذ الفئة `SocketClient` مع إدارة الاتصال +2. تنفيذ `SocketFlowInstance` بنفس توقيعات الطرق مثل `FlowInstance` +3. إضافة دعم لتقسيم الطلبات (حتى 15 طلبًا متزامنًا) +4. إضافة تحليل استجابة التدفق لأنواع أجزاء مختلفة +5. إضافة منطق إعادة الاتصال التلقائي +6. إضافة اختبارات الوحدة والتكامل +7. توثيق أنماط استخدام WebSocket + +**التوافق مع الإصدارات السابقة**: واجهة جديدة فقط. لا يوجد تأثير على التعليمات البرمجية الحالية. + +#### المرحلة الثالثة: دعم التدفق (الأسبوعان الثالث والرابع) + +1. إضافة فئات أنواع أجزاء التدفق (`AgentThought`، `AgentObservation`، `AgentAnswer`، `RAGChunk`) +2. تنفيذ تحليل استجابة التدفق في `SocketClient` +3. إضافة معلمة التدفق إلى جميع طرق LLM في `SocketFlowInstance` +4. التعامل مع حالات الخطأ أثناء التدفق +5. إضافة اختبارات الوحدة والتكامل للتدفق +6. إضافة أمثلة التدفق إلى الوثائق + +**التوافق مع الإصدارات السابقة**: واجهة جديدة فقط. واجهة برمجة تطبيقات REST الحالية لم تتغير. + +#### المرحلة الرابعة: العمليات المجمعة (الأسبوعان الرابع والخامس) + +1. تنفيذ الفئة `BulkClient` +2. إضافة طرق الاستيراد/التصدير المجمعة للثلاثيات والتضمينات والسياقات والكائنات +3. تنفيذ المعالجة القائمة على المكرر للذاكرة الثابتة +4. إضافة تتبع التقدم (وظيفة رد اتصال اختيارية) +5. إضافة معالجة الأخطاء مع الإبلاغ عن النجاح الجزئي +6. إضافة اختبارات الوحدة والتكامل +7. إضافة أمثلة للعمليات المجمعة + +**التوافق مع الإصدارات السابقة**: واجهة جديدة فقط. لا يوجد تأثير على التعليمات البرمجية الحالية. + +#### المرحلة الخامسة: تحقيق التكافؤ والتحسين (الأسبوع الخامس) + +1. إضافة `graph_embeddings_query()` إلى REST `FlowInstance` +2. تنفيذ الفئة `Metrics` +3. إضافة اختبارات تكامل شاملة +4. قياس الأداء +5. تحديث جميع الوثائق +6. إنشاء دليل ترحيل + +**التوافق مع الإصدارات السابقة**: طرق جديدة فقط. لا يوجد تأثير على التعليمات البرمجية الحالية. + +### نماذج البيانات + +#### اختيار الواجهة + +```python +# Single API instance, same URL for all interfaces +api = Api(url="http://localhost:8088/") + +# Synchronous interfaces +rest_flow = api.flow().id("default") # Sync REST +socket_flow = api.socket().flow("default") # Sync WebSocket +bulk = api.bulk() # Sync bulk operations +metrics = api.metrics() # Sync metrics + +# Asynchronous interfaces +async_rest_flow = api.async_flow().id("default") # Async REST +async_socket_flow = api.async_socket().flow("default") # Async WebSocket +async_bulk = api.async_bulk() # Async bulk operations +async_metrics = api.async_metrics() # Async metrics +``` + +#### أنواع الاستجابة المتدفقة + +**تدفق الوكيل (Agent Streaming):** + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - non-streaming (same signature) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - streaming (new) +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentThought): + print(f"Thinking: {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"Observed: {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"Answer: {chunk.content}") + if chunk.end_of_dialog: + break +``` + +**البث المتدفق (RAG Streaming):** + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.graph_rag(question="What is Python?", user="user123", collection="default") +print(response) + +# WebSocket interface - streaming (new) +socket_flow = api.socket().flow("default") +for chunk in socket_flow.graph_rag( + question="What is Python?", + user="user123", + collection="default", + streaming=True +): + print(chunk.content, end="", flush=True) + if chunk.end_of_stream: + break +``` + +**العمليات المجمعة (المزامنة):** + +```python +api = Api(url="http://localhost:8088/") + +# Bulk import triples +def triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Bulk export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +**العمليات المجمعة (غير متزامنة):** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async bulk import triples + async def async_triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + + # Async bulk export triples + async for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") + +asyncio.run(main()) +``` + +**مثال REST غير المتزامن:** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST flow operations + flow = api.async_flow().id("default") + response = await flow.agent(question="What is ML?", user="user123") + print(response["response"]) + +asyncio.run(main()) +``` + +**مثال على بث WebSocket غير المتزامن:** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async WebSocket streaming + socket = api.async_socket() + flow = socket.flow("default") + + async for chunk in flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) + if chunk.end_of_dialog: + break + +asyncio.run(main()) +``` + +### واجهات برمجة التطبيقات (APIs) + +#### واجهات برمجة تطبيقات جديدة + +1. **فئة واجهة برمجة التطبيقات الأساسية (Core API Class)**: + **متزامن (Synchronous)**: + `Api.socket()` - الحصول على عميل WebSocket متزامن + `Api.bulk()` - الحصول على عميل العمليات المجمعة متزامن + `Api.metrics()` - الحصول على عميل المقاييس متزامن + `Api.close()` - إغلاق جميع الاتصالات المتزامنة + دعم مدير السياق (`__enter__`, `__exit__`) + **غير متزامن (Asynchronous)**: + `Api.async_flow()` - الحصول على عميل تدفق REST غير متزامن + `Api.async_socket()` - الحصول على عميل WebSocket غير متزامن + `Api.async_bulk()` - الحصول على عميل العمليات المجمعة غير متزامن + `Api.async_metrics()` - الحصول على عميل المقاييس غير متزامن + `Api.aclose()` - إغلاق جميع الاتصالات غير المتزامنة + دعم مدير السياق غير المتزامن (`__aenter__`, `__aexit__`) + +2. **عميل WebSocket متزامن**: + `SocketClient.flow(flow_id)` - الحصول على مثيل تدفق WebSocket + `SocketFlowInstance.agent(..., streaming: bool = False)` - وكيل مع دعم اختياري للتدفق + `SocketFlowInstance.text_completion(..., streaming: bool = False)` - إكمال النص مع دعم اختياري للتدفق + `SocketFlowInstance.graph_rag(..., streaming: bool = False)` - استعلام Graph RAG مع دعم اختياري للتدفق + `SocketFlowInstance.document_rag(..., streaming: bool = False)` - استعلام Document RAG مع دعم اختياري للتدفق + `SocketFlowInstance.prompt(..., streaming: bool = False)` - استعلام Prompt مع دعم اختياري للتدفق + `SocketFlowInstance.graph_embeddings_query()` - استعلام تضمينات الرسم البياني + جميع طرق FlowInstance الأخرى بنفس التوقيعات + +3. **عميل WebSocket غير متزامن**: + `AsyncSocketClient.flow(flow_id)` - الحصول على مثيل تدفق WebSocket غير متزامن + `AsyncSocketFlowInstance.agent(..., streaming: bool = False)` - وكيل غير متزامن مع دعم اختياري للتدفق + `AsyncSocketFlowInstance.text_completion(..., streaming: bool = False)` - إكمال نص غير متزامن مع دعم اختياري للتدفق + `AsyncSocketFlowInstance.graph_rag(..., streaming: bool = False)` - استعلام Graph RAG غير متزامن مع دعم اختياري للتدفق + `AsyncSocketFlowInstance.document_rag(..., streaming: bool = False)` - استعلام Document RAG غير متزامن مع دعم اختياري للتدفق + `AsyncSocketFlowInstance.prompt(..., streaming: bool = False)` - استعلام Prompt غير متزامن مع دعم اختياري للتدفق + `AsyncSocketFlowInstance.graph_embeddings_query()` - استعلام تضمينات الرسم البياني غير المتزامن + جميع طرق FlowInstance الأخرى كإصدارات غير متزامنة + +4. **عميل العمليات المجمعة متزامن**: + `BulkClient.import_triples(flow, triples)` - استيراد مجمع ثلاثيات + `BulkClient.export_triples(flow)` - تصدير مجمع ثلاثيات + `BulkClient.import_graph_embeddings(flow, embeddings)` - استيراد مجمع تضمينات الرسم البياني + `BulkClient.export_graph_embeddings(flow)` - تصدير مجمع تضمينات الرسم البياني + `BulkClient.import_document_embeddings(flow, embeddings)` - استيراد مجمع تضمينات المستندات + `BulkClient.export_document_embeddings(flow)` - تصدير مجمع تضمينات المستندات + `BulkClient.import_entity_contexts(flow, contexts)` - استيراد مجمع سياقات الكيانات + `BulkClient.export_entity_contexts(flow)` - تصدير مجمع سياقات الكيانات + `BulkClient.import_objects(flow, objects)` - استيراد مجمع الكائنات + +5. **عميل العمليات المجمعة غير المتزامن**: + `AsyncBulkClient.import_triples(flow, triples)` - استيراد مجمع ثلاثيات غير متزامن + `AsyncBulkClient.export_triples(flow)` - تصدير مجمع ثلاثيات غير متزامن + `AsyncBulkClient.import_graph_embeddings(flow, embeddings)` - استيراد مجمع تضمينات الرسم البياني غير المتزامن + `AsyncBulkClient.export_graph_embeddings(flow)` - تصدير مجمع تضمينات الرسم البياني غير المتزامن + `AsyncBulkClient.import_document_embeddings(flow, embeddings)` - استيراد مجمع تضمينات المستندات غير المتزامن + `AsyncBulkClient.export_document_embeddings(flow)` - تصدير مجمع تضمينات المستندات غير المتزامن + `AsyncBulkClient.import_entity_contexts(flow, contexts)` - استيراد مجمع سياقات الكيانات غير المتزامن + `AsyncBulkClient.export_entity_contexts(flow)` - تصدير مجمع سياقات الكيانات غير المتزامن + `AsyncBulkClient.import_objects(flow, objects)` - استيراد مجمع الكائنات غير المتزامن + +6. **عميل تدفق REST غير المتزامن**: + `AsyncFlow.list()` - سرد جميع التدفقات (غير متزامن) + `AsyncFlow.get(id)` - الحصول على تعريف التدفق (غير متزامن) + `AsyncFlow.start(...)` - بدء التدفق (غير متزامن) + `AsyncFlow.stop(id)` - إيقاف التدفق (غير متزامن) + `AsyncFlow.id(flow_id)` - الحصول على مثيل تدفق (غير متزامن) + `AsyncFlowInstance.agent(...)` - تنفيذ الوكيل (غير متزامن) + `AsyncFlowInstance.text_completion(...)` - إكمال النص (غير متزامن) + `AsyncFlowInstance.graph_rag(...)` - Graph RAG (غير متزامن) + جميع طرق FlowInstance الأخرى كإصدارات غير متزامنة + +7. **عملاء المقاييس**: + `Metrics.get()` - مقاييس Prometheus متزامنة + `AsyncMetrics.get()` - مقاييس Prometheus غير متزامنة + +8. **تحسين واجهة برمجة تطبيقات REST للتدفق**: + `FlowInstance.graph_embeddings_query()` - استعلام تضمينات الرسم البياني (للتوافق مع الميزات المتزامنة) + `AsyncFlowInstance.graph_embeddings_query()` - استعلام تضمينات الرسم البياني (للتوافق مع الميزات غير المتزامنة) + +#### واجهات برمجة تطبيقات معدلة + +1. **المنشئ (Constructor)** (تحسين طفيف): + ```python + Api(url: str, timeout: int = 60, token: Optional[str] = None) + ``` + تمت إضافة المعامل `token` (اختياري، للمصادقة). + إذا لم يتم تحديد `None` (افتراضيًا): لم يتم استخدام أي مصادقة. + إذا تم تحديده: يتم استخدامه كرمز مميز (bearer token) لواجهة برمجة التطبيقات REST (`Authorization: Bearer `)، ومعامل استعلام لـ WebSocket (`?token=`). + لا توجد تغييرات أخرى - متوافق تمامًا مع الإصدارات السابقة. + +2. **لا توجد تغييرات جذرية**: + جميع طرق واجهة برمجة التطبيقات REST الحالية لم تتغير. + تمت الحفاظ على جميع التوقيعات الحالية. + تمت الحفاظ على جميع أنواع الإرجاع الحالية. + +### تفاصيل التنفيذ + +#### معالجة الأخطاء + +**أخطاء اتصال WebSocket**: +```python +try: + api = Api(url="http://localhost:8088/") + socket = api.socket() + socket_flow = socket.flow("default") + response = socket_flow.agent(question="...", user="user123") +except ConnectionError as e: + print(f"WebSocket connection failed: {e}") + print("Hint: Ensure Gateway is running and WebSocket endpoint is accessible") +``` + +**العودة السلسة:** +```python +api = Api(url="http://localhost:8088/") + +try: + # Try WebSocket streaming first + socket_flow = api.socket().flow("default") + for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk.content) +except ConnectionError: + # Fall back to REST non-streaming + print("WebSocket unavailable, falling back to REST") + rest_flow = api.flow().id("default") + response = rest_flow.agent(question="...", user="...") + print(response["response"]) +``` + +**أخطاء البث الجزئي:** +```python +api = Api(url="http://localhost:8088/") +socket_flow = api.socket().flow("default") + +accumulated = [] +try: + for chunk in socket_flow.graph_rag(question="...", streaming=True): + accumulated.append(chunk.content) + if chunk.error: + print(f"Error occurred: {chunk.error}") + print(f"Partial response: {''.join(accumulated)}") + break +except Exception as e: + print(f"Streaming error: {e}") + print(f"Partial response: {''.join(accumulated)}") +``` + +#### إدارة الموارد + +**دعم مدير السياق:** +```python +# Automatic cleanup +with Api(url="http://localhost:8088/") as api: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +# All connections automatically closed + +# Manual cleanup +api = Api(url="http://localhost:8088/") +try: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +finally: + api.close() # Explicitly close all connections (WebSocket, bulk, etc.) +``` + +#### الترابط والتزامن + +**أمان الترابط**: +تحتفظ كل نسخة من `Api` باتصالها الخاص. +يستخدم نقل WebSocket الأقفال لعملية تعدد المهام الآمنة للطلبات. +يمكن للعديد من سلاسل العمل (threads) مشاركة نسخة واحدة من `Api` بأمان. +مُكررات التدفق (streaming iterators) ليست آمنة للترابط (يجب استهلاكها من سلسلة عمل واحدة). + +**دعم غير متزامن** (للمستقبل): +```python +# Phase 2 enhancement (not in initial scope) +import asyncio + +async def main(): + api = await AsyncApi(url="ws://localhost:8088/") + flow = api.flow().id("default") + + async for chunk in flow.agent(question="...", streaming=True): + print(chunk.content) + + await api.close() + +asyncio.run(main()) +``` + +## اعتبارات الأمان + +### المصادقة + +**المعلمة الرمز:** +```python +# No authentication (default) +api = Api(url="http://localhost:8088/") + +# With authentication +api = Api(url="http://localhost:8088/", token="mytoken") +``` + +**نقل REST:** +رمز مميز عبر رأس `Authorization` +يتم تطبيقه تلقائيًا على جميع طلبات REST +التنسيق: `Authorization: Bearer ` + +**نقل WebSocket:** +رمز مميز عبر معلمة الاستعلام المضافة إلى عنوان URL الخاص بـ WebSocket +يتم تطبيقه تلقائيًا أثناء إنشاء الاتصال +التنسيق: `ws://localhost:8088/api/v1/socket?token=` + +**التنفيذ:** +```python +class SocketClient: + def _connect(self) -> WebSocket: + # Construct WebSocket URL with optional token + ws_url = f"{self.url}/api/v1/socket" + if self.token: + ws_url = f"{ws_url}?token={self.token}" + # Connect to WebSocket + return websocket.connect(ws_url) +``` + +**مثال:** +```python +# REST with auth +api = Api(url="http://localhost:8088/", token="mytoken") +flow = api.flow().id("default") +# All REST calls include: Authorization: Bearer mytoken + +# WebSocket with auth +socket = api.socket() +# Connects to: ws://localhost:8088/api/v1/socket?token=mytoken +``` + +### الاتصالات الآمنة + +يدعم كل من البروتوكولين WS (WebSocket) و WSS (WebSocket Secure). +التحقق من صحة شهادة TLS لاتصالات WSS. +تعطيل اختياري للتحقق من الشهادة لأغراض التطوير (مع تحذير). + +### التحقق من صحة البيانات المدخلة + +التحقق من صحة مخططات عناوين URL (http، https، ws، wss). +التحقق من صحة قيم معلمات النقل. +التحقق من صحة مجموعات معلمات التدفق. +التحقق من صحة أنواع بيانات الاستيراد المجمعة. + +## اعتبارات الأداء + +### تحسينات في زمن الاستجابة + +**عمليات LLM المتدفقة**: +**الوقت اللازم للحصول على أول رمز**: ~500 مللي ثانية (مقارنة بـ ~30 ثانية بدون تدفق). +**التحسين**: أداء أسرع بمقدار 60 مرة. +**ينطبق على**: الوكيل، و Graph RAG، و Document RAG، وإكمال النص، والموجه. + +**الاتصالات المستمرة**: +**تكلفة الاتصال**: يتم إلغاؤها للطلبات اللاحقة. +**مصافحة WebSocket**: تكلفة لمرة واحدة (~100 مللي ثانية). +**ينطبق على**: جميع العمليات عند استخدام نقل WebSocket. + +### تحسينات في الإنتاجية + +**العمليات المجمعة**: +**استيراد الثلاثيات**: ~10,000 ثلاثية/ثانية (مقارنة بـ ~100/ثانية باستخدام REST لكل عنصر). +**استيراد التضمينات**: ~5,000 تضمين/ثانية (مقارنة بـ ~50/ثانية باستخدام REST لكل عنصر). +**التحسين**: زيادة في الإنتاجية بمقدار 100 مرة للعمليات المجمعة. + +**تعدد الطلبات**: +**الطلبات المتزامنة**: تصل إلى 15 طلبًا متزامنًا عبر اتصال واحد. +**إعادة استخدام الاتصال**: لا توجد تكلفة إضافية للاتصال للعمليات المتزامنة. + +### اعتبارات الذاكرة + +**الاستجابات المتدفقة**: +استخدام ثابت للذاكرة (معالجة أجزاء البيانات عند وصولها). +لا يتم تخزين الاستجابة بأكملها في الذاكرة. +مناسب للإخراجات الطويلة جدًا (>1 ميجابايت). + +**العمليات المجمعة**: +معالجة قائمة (استخدام ثابت للذاكرة). +لا يتم تحميل مجموعة البيانات بأكملها في الذاكرة. +مناسب لمجموعات البيانات التي تحتوي على ملايين العناصر. + +### المقاييس (المتوقعة) + +| العملية | REST (الحالي) | WebSocket (تدفق) | التحسين | +|-----------|----------------|----------------------|-------------| +| الوكيل (الوقت اللازم للحصول على أول رمز) | 30 ثانية | 0.5 ثانية | 60x | +| Graph RAG (الوقت اللازم للحصول على أول رمز) | 25 ثانية | 0.5 ثانية | 50x | +| استيراد 10 آلاف ثلاثية | 100 ثانية | 1 ثانية | 100x | +| استيراد 1 مليون ثلاثية | 10,000 ثانية (2.7 ساعة) | 100 ثانية (1.6 دقيقة) | 100x | +| 10 طلبات صغيرة متزامنة | 5 ثوانٍ (تسلسلي) | 0.5 ثانية (متوازي) | 10x | + +## استراتيجية الاختبار + +### اختبارات الوحدة + +**طبقة النقل** (`test_transport.py`): +اختبار طلب/استجابة النقل REST +اختبار اتصال نقل WebSocket +اختبار إعادة اتصال نقل WebSocket +اختبار تعدد الطلبات +اختبار تحليل الاستجابة المتدفقة +محاكاة خادم WebSocket للاختبارات الحتمية + +**طرق واجهة برمجة التطبيقات (API)** (`test_flow.py`، `test_library.py`، إلخ): +اختبار الطرق الجديدة باستخدام النقل المُحاكى +اختبار معالجة المعلمات المتدفقة +اختبار مُكررات العمليات المجمعة +اختبار معالجة الأخطاء + +**الأنواع** (`test_types.py`): +اختبار أنواع الشرائح المتدفقة الجديدة +اختبار تسلسل/إلغاء تسلسل الأنواع + +### اختبارات التكامل + +**REST من طرف إلى طرف** (`test_integration_rest.py`): +اختبار جميع العمليات مقابل البوابة الحقيقية (وضع REST) +التحقق من التوافق مع الإصدارات السابقة +اختبار حالات الخطأ + +**WebSocket من طرف إلى طرف** (`test_integration_websocket.py`): +اختبار جميع العمليات مقابل البوابة الحقيقية (وضع WebSocket) +اختبار العمليات المتدفقة +اختبار العمليات المجمعة +اختبار الطلبات المتزامنة +اختبار استعادة الاتصال + +**خدمات التدفق** (`test_streaming_integration.py`): +اختبار تدفق الوكيل (الأفكار، والملاحظات، والإجابات) +اختبار تدفق RAG (أجزاء متزايدة) +اختبار تدفق إكمال النص (رمز تلو رمز) +اختبار تدفق المطالبات +اختبار معالجة الأخطاء أثناء التدفق + +**العمليات المجمعة** (`test_bulk_integration.py`): +اختبار استيراد/تصدير مجمّع للثلاثيات (1K، 10K، 100K عناصر) +اختبار استيراد/تصدير مجمّع للتضمينات +اختبار استخدام الذاكرة أثناء العمليات المجمعة +اختبار تتبع التقدم + +### اختبارات الأداء + +**معايير زمن الوصول** (`test_performance_latency.py`): +قياس الوقت اللازم للرمز الأول (تدفق مقابل عدم تدفق) +قياس النفقات العامة للاتصال (REST مقابل WebSocket) +مقارنة بالمعايير المتوقعة + +**معايير الإنتاجية** (`test_performance_throughput.py`): +قياس إنتاجية الاستيراد المجمّع +قياس كفاءة تعدد الطلبات +مقارنة بالمعايير المتوقعة + +### اختبارات التوافق + +**التوافق مع الإصدارات السابقة** (`test_backward_compatibility.py`): +تشغيل مجموعة الاختبار الحالية مقابل واجهة برمجة التطبيقات المعاد هيكلتها +التحقق من عدم وجود تغييرات فاصلة +اختبار مسار الترحيل للأنماط الشائعة + +## خطة الترحيل + +### المرحلة 1: الترحيل الشفاف (افتراضي) + +**لا يلزم إجراء أي تغييرات في التعليمات البرمجية**. يستمر التعليم البرمجي الحالي في العمل: + +```python +# Existing code works unchanged +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") +response = flow.agent(question="What is ML?", user="user123") +``` + +### المرحلة الثانية: البث الاختياري (بسيط) + +**استخدم واجهة `api.socket()` لتمكين البث:** + +```python +# Before: Non-streaming REST +api = Api(url="http://localhost:8088/") +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# After: Streaming WebSocket (same parameters!) +api = Api(url="http://localhost:8088/") # Same URL +socket_flow = api.socket().flow("default") + +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) +``` + +**النقاط الرئيسية:** +نفس عنوان URL لكل من REST و WebSocket. +نفس توقيعات الطرق (سهولة الترحيل). +فقط أضف `.socket()` و `streaming=True`. + +### المرحلة الثالثة: العمليات المجمعة (قدرة جديدة). + +**استخدم واجهة `api.bulk()`** لمجموعات البيانات الكبيرة: + +```python +# Before: Inefficient per-item operations +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") + +for triple in my_large_triple_list: + # Slow per-item operations + # (no direct bulk insert in REST API) + pass + +# After: Efficient bulk loading +api = Api(url="http://localhost:8088/") # Same URL +bulk = api.bulk() + +# This is fast (10,000 triples/second) +bulk.import_triples(flow="default", triples=iter(my_large_triple_list)) +``` + +### تحديثات الوثائق + +1. **README.md**: إضافة أمثلة للبث و WebSocket +2. **مرجع واجهة برمجة التطبيقات (API Reference)**: توثيق جميع الطرق والمعلمات الجديدة +3. **دليل الترحيل (Migration Guide)**: دليل خطوة بخطوة لتمكين البث +4. **أمثلة (Examples)**: إضافة نصوص برمجية لأمثلة شائعة +5. **دليل الأداء (Performance Guide)**: توثيق التحسينات المتوقعة في الأداء + +### سياسة الإيقاف + +**لا يوجد إيقاف (No deprecations)**. تظل جميع واجهات برمجة التطبيقات الحالية مدعومة. هذا تحسين خالص. + +## الجدول الزمني + +### الأسبوع الأول: الأساس +طبقة تجريد النقل +إعادة هيكلة التعليمات البرمجية REST الحالية +اختبارات الوحدة لطبقة النقل +التحقق من التوافق مع الإصدارات السابقة + +### الأسبوع الثاني: نقل بيانات WebSocket +تنفيذ نقل بيانات WebSocket +إدارة الاتصال وإعادة الاتصال +تعدد الطلبات +اختبارات الوحدة والتكامل + +### الأسبوع الثالث: دعم البث +إضافة معلمة البث إلى طرق LLM +تنفيذ تحليل استجابة البث +إضافة أنواع أجزاء البث +اختبارات تكامل البث + +### الأسبوع الرابع: العمليات المجمعة +إضافة طرق الاستيراد/التصدير المجمعة +تنفيذ عمليات قائمة على المكرر +اختبار الأداء +اختبارات تكامل العمليات المجمعة + +### الأسبوع الخامس: تكافؤ الميزات والوثائق +إضافة استعلام تضمين الرسم البياني +إضافة واجهة برمجة تطبيقات المقاييس +وثائق شاملة +دليل الترحيل +إصدار مرشح + +### الأسبوع السادس: الإصدار +اختبار تكامل نهائي +قياس الأداء +وثائق الإصدار +إعلان للمجتمع + +**المدة الإجمالية**: 6 أسابيع + +## أسئلة مفتوحة + +### أسئلة تصميم واجهة برمجة التطبيقات + +1. **دعم غير متزامن (Async Support)**: ✅ **تم الحل (RESOLVED)** - تم تضمين الدعم الكامل غير المتزامن في الإصدار الأولي + تمت إضافة إصدارات غير متزامنة لجميع الواجهات: `async_flow()`، `async_socket()`، `async_bulk()`، `async_metrics()` + يوفر تناسقًا كاملاً بين واجهات برمجة التطبيقات المتزامنة وغير المتزامنة + ضروري لأطر العمل غير المتزامنة الحديثة (FastAPI, aiohttp) + +2. **تتبع التقدم (Progress Tracking)**: هل يجب أن تدعم العمليات المجمعة استدعيات رد اتصال للتقدم؟ + ```python + def progress_callback(processed: int, total: Optional[int]): + print(f"Processed {processed} items") + + bulk.import_triples(flow="default", triples=triples, on_progress=progress_callback) + ``` + **التوصية**: أضف في المرحلة الثانية. ليس ضروريًا للإصدار الأولي. + +3. **مهلة البث (Streaming Timeout)**: كيف يجب أن نتعامل مع المهلات لعمليات البث؟ + **التوصية**: استخدم نفس المهلة المستخدمة في العمليات غير المباشرة، ولكن أعد ضبطها عند استلام كل جزء. + +4. **تخزين الأجزاء مؤقتًا (Chunk Buffering)**: هل يجب علينا تخزين الأجزاء مؤقتًا أم إرجاعها على الفور؟ + **التوصية**: أرجعها على الفور لتقليل زمن الوصول. + +5. **الخدمات العامة عبر WebSocket**: هل يجب أن يدعم `api.socket()` الخدمات العامة (المكتبة، المعرفة، المجموعة، التكوين) أم فقط الخدمات الخاصة بالنطاق (flow-scoped)؟ + **التوصية**: ابدأ بالخدمات الخاصة بالنطاق فقط (حيث يكون البث مهمًا). أضف الخدمات العامة إذا لزم الأمر في المرحلة الثانية. + +### أسئلة التنفيذ + +1. **مكتبة WebSocket**: هل يجب أن نستخدم `websockets`، `websocket-client`، أو `aiohttp`؟ + **التوصية**: `websockets` (غير متزامن، ناضج، مدعوم جيدًا). قم بتغليفه في واجهة متزامنة باستخدام `asyncio.run()`. + +2. **تجميع الاتصالات (Connection Pooling)**: هل يجب أن ندعم مثيلات متعددة متزامنة من `Api` تشارك مجموعة اتصالات؟ + **التوصية**: تؤجل إلى المرحلة الثانية. كل مثيل من `Api` لديه اتصالات خاصة به في البداية. + +3. **إعادة استخدام الاتصال (Connection Reuse)**: هل يجب أن تشارك `SocketClient` و `BulkClient` نفس اتصال WebSocket، أم تستخدم اتصالات منفصلة؟ + **التوصية**: اتصالات منفصلة. تطبيق أبسط، وفصل واضح للمسؤوليات. + +4. **الاتصال الكسول مقابل الاتصال الحماسي (Lazy vs Eager Connection)**: هل يجب إنشاء اتصال WebSocket في `api.socket()` أم عند الطلب الأول؟ + **التوصية**: كسول (عند الطلب الأول). يتجنب تكلفة الاتصال إذا كان المستخدم يستخدم فقط طرق REST. + +### أسئلة الاختبار + +1. **بوابة وهمية (Mock Gateway)**: هل يجب علينا إنشاء بوابة وهمية خفيفة الوزن للاختبار، أم الاختبار مقابل البوابة الحقيقية؟ + **التوصية**: كلاهما. استخدم الوهميات للاختبارات الوحدوية، والبوابة الحقيقية للاختبارات التكاملية. + +2. **اختبارات الانحدار في الأداء (Performance Regression Tests)**: هل يجب علينا إضافة اختبارات أداء انحدار آلية إلى CI؟ + **التوصية**: نعم، ولكن مع حدود سماح كبيرة لمراعاة تباين بيئة CI. + +## المراجع + +### المواصفات التقنية ذات الصلة +`docs/tech-specs/streaming-llm-responses.md` - تطبيق البث في البوابة +`docs/tech-specs/rag-streaming-support.md` - دعم البث لـ RAG + +### ملفات التنفيذ +`trustgraph-base/trustgraph/api/` - مصدر واجهة برمجة التطبيقات (API) بلغة Python +`trustgraph-flow/trustgraph/gateway/` - مصدر البوابة +`trustgraph-flow/trustgraph/gateway/dispatch/mux.py` - تطبيق مرجعي لتقسيم WebSocket + +### التوثيق +`docs/apiSpecification.md` - مرجع API كامل +`docs/api-status-summary.md` - ملخص حالة API +`README.websocket` - توثيق بروتوكول WebSocket +`STREAMING-IMPLEMENTATION-NOTES.txt` - ملاحظات حول تطبيق البث + +### المكتبات الخارجية +`websockets` - مكتبة WebSocket بلغة Python (https://websockets.readthedocs.io/) +`requests` - مكتبة HTTP بلغة Python (موجودة) diff --git a/docs/tech-specs/python-api-refactor.es.md b/docs/tech-specs/python-api-refactor.es.md new file mode 100644 index 00000000..15a7e13f --- /dev/null +++ b/docs/tech-specs/python-api-refactor.es.md @@ -0,0 +1,1508 @@ +# Especificación Técnica de Refactorización de la API de Python + +## Resumen + +Esta especificación describe una refactorización integral de la biblioteca de cliente de la API de Python de TrustGraph para lograr la paridad de funciones con la API Gateway y agregar soporte para patrones de comunicación en tiempo real modernos. + +La refactorización aborda cuatro casos de uso principales: + +1. **Interacciones de LLM en Streaming**: Habilitar el streaming en tiempo real de las respuestas de LLM (agente, RAG de grafos, RAG de documentos, finalización de texto, prompts) con una latencia significativamente menor (~60 veces menor, 500 ms frente a 30 s para el primer token). +2. **Operaciones de Datos Masivos**: Soporte para la importación/exportación eficiente de triples, incrustaciones de grafos e incrustaciones de documentos para la gestión de grafos de conocimiento a gran escala. +3. **Paridad de Funciones**: Asegurar que cada punto final de la API Gateway tenga un método de API de Python correspondiente, incluidas las consultas de incrustaciones de grafos. +4. **Conexiones Persistentes**: Habilitar la comunicación basada en WebSocket para solicitudes multiplexadas y una menor sobrecarga de conexión. + +## Objetivos + +**Paridad de Funciones**: Cada servicio de la API Gateway tiene un método de API de Python correspondiente. +**Soporte de Streaming**: Todos los servicios capaces de streaming (agente, RAG, finalización de texto, prompt) admiten el streaming en la API de Python. +**Transporte WebSocket**: Agregar una capa de transporte WebSocket opcional para conexiones persistentes y multiplexación. +**Operaciones Masivas**: Agregar importación/exportación masiva eficiente para triples, incrustaciones de grafos e incrustaciones de documentos. +**Soporte Completo Async**: Implementación completa de async/await para todas las interfaces (REST, WebSocket, operaciones masivas, métricas). +**Compatibilidad con Versiones Anteriores**: El código existente continúa funcionando sin modificaciones. +**Seguridad de Tipos**: Mantener interfaces con seguridad de tipos utilizando dataclasses y sugerencias de tipo. +**Mejora Progresiva**: El streaming y el async son opcionales a través de la selección explícita de la interfaz. +**Rendimiento**: Lograr una mejora de latencia de 60 veces para las operaciones de streaming. +**Python Moderno**: Soporte para paradigmas tanto síncronos como asíncronos para una máxima flexibilidad. + +## Antecedentes + +### Estado Actual + +La API de Python (`trustgraph-base/trustgraph/api/`) es una biblioteca de cliente REST con los siguientes módulos: + +`flow.py`: Gestión de flujos y servicios con ámbito de flujo (50 métodos). +`library.py`: Operaciones de la biblioteca de documentos (9 métodos). +`knowledge.py`: Gestión central de grafos (4 métodos). +`collection.py`: Metadatos de colecciones (3 métodos). +`config.py`: Gestión de configuración (6 métodos). +`types.py`: Definiciones de tipos de datos (5 dataclasses). + +**Operaciones Totales**: 50/59 (cobertura del 85%). + +### Limitaciones Actuales + +**Operaciones Faltantes**: +Consulta de incrustaciones de grafos (búsqueda semántica sobre entidades de grafos). +Importación/exportación masiva para triples, incrustaciones de grafos, incrustaciones de documentos, contextos de entidades, objetos. +Punto final de métricas. + +**Capacidades Faltantes**: +Soporte de streaming para servicios de LLM. +Transporte WebSocket. +Solicitudes concurrentes multiplexadas. +Conexiones persistentes. + +**Problemas de Rendimiento**: +Alta latencia para las interacciones de LLM (~30 s para el primer token). +Transferencia de datos masiva ineficiente (solicitud REST por elemento). +Sobrecarga de conexión para múltiples operaciones secuenciales. + +**Problemas de Experiencia de Usuario**: +Sin retroalimentación en tiempo real durante la generación de LLM. +No se pueden cancelar las operaciones de LLM de larga duración. +Mala escalabilidad para las operaciones masivas. + +### Impacto + +La mejora de streaming de noviembre de 2024 en la API Gateway proporcionó una mejora de latencia de 60 veces (500 ms frente a 30 s para el primer token) para las interacciones de LLM, pero los usuarios de la API de Python no pueden aprovechar esta capacidad. Esto crea una brecha significativa de experiencia entre los usuarios de Python y los que no lo utilizan. + +## Diseño Técnico + +### Arquitectura + +La API de Python refactorizada utiliza un **enfoque de interfaz modular** con objetos separados para diferentes patrones de comunicación. Todas las interfaces están disponibles tanto en variantes **síncronas como asíncronas**: + +1. **Interfaz REST** (existente, mejorada). + **Sync**: `api.flow()`, `api.library()`, `api.knowledge()`, `api.collection()`, `api.config()`. + **Async**: `api.async_flow()`. + Solicitud/respuesta síncrona/asíncrona. + Modelo de conexión simple. + Predeterminado para la compatibilidad con versiones anteriores. + +2. **Interfaz WebSocket** (nueva). + **Sync**: `api.socket()`. + **Async**: `api.async_socket()`. + Conexión persistente. + Solicitudes multiplexadas. + Soporte de streaming. + Mismas firmas de método que REST donde la funcionalidad se superpone. + +3. **Interfaz de Operaciones Masivas** (nueva). + **Sync**: `api.bulk()`. + **Async**: `api.async_bulk()`. + Basado en WebSocket para la eficiencia. + Importación/exportación basada en iterador/AsyncIterator. + Maneja conjuntos de datos grandes. + +4. **Interfaz de Métricas** (nueva). + **Sync**: `api.metrics()`. + **Async**: `api.async_metrics()`. + Acceso a métricas de Prometheus. + +```python +import asyncio + +# Synchronous interfaces +api = Api(url="http://localhost:8088/") + +# REST (existing, unchanged) +flow = api.flow().id("default") +response = flow.agent(question="...", user="...") + +# WebSocket (new) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="...", user="...") +for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk) + +# Bulk operations (new) +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Asynchronous interfaces +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST (new) + flow = api.async_flow().id("default") + response = await flow.agent(question="...", user="...") + + # Async WebSocket (new) + socket_flow = api.async_socket().flow("default") + async for chunk in socket_flow.agent(question="...", streaming=True): + print(chunk) + + # Async bulk operations (new) + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + +asyncio.run(main()) +``` + +**Principios clave de diseño:** +**Misma URL para todas las interfaces:** `Api(url="http://localhost:8088/")` funciona para todas. +**Simetría sincrónica/asincrónica:** Cada interfaz tiene variantes tanto sincrónicas como asincrónicas con firmas de método idénticas. +**Firmas idénticas:** Donde la funcionalidad se superpone, las firmas de los métodos son idénticas entre REST y WebSocket, sincrónicas y asincrónicas. +**Mejora progresiva:** Elija la interfaz según las necesidades (REST para tareas simples, WebSocket para transmisión, Bulk para conjuntos de datos grandes, asíncrono para marcos modernos). +**Intención explícita:** `api.socket()` indica WebSocket, `api.async_socket()` indica WebSocket asíncrono. +**Compatible con versiones anteriores:** El código existente no se modifica. + +### Componentes + +#### 1. Clase API principal (modificada) + +Módulo: `trustgraph-base/trustgraph/api/api.py` + +**Clase API mejorada:** + +```python +class Api: + def __init__(self, url: str, timeout: int = 60, token: Optional[str] = None): + self.url = url + self.timeout = timeout + self.token = token # Optional bearer token for REST, query param for WebSocket + self._socket_client = None + self._bulk_client = None + self._async_flow = None + self._async_socket_client = None + self._async_bulk_client = None + + # Existing synchronous methods (unchanged) + def flow(self) -> Flow: + """Synchronous REST-based flow interface""" + pass + + def library(self) -> Library: + """Synchronous REST-based library interface""" + pass + + def knowledge(self) -> Knowledge: + """Synchronous REST-based knowledge interface""" + pass + + def collection(self) -> Collection: + """Synchronous REST-based collection interface""" + pass + + def config(self) -> Config: + """Synchronous REST-based config interface""" + pass + + # New synchronous methods + def socket(self) -> SocketClient: + """Synchronous WebSocket-based interface for streaming operations""" + if self._socket_client is None: + self._socket_client = SocketClient(self.url, self.timeout, self.token) + return self._socket_client + + def bulk(self) -> BulkClient: + """Synchronous bulk operations interface for import/export""" + if self._bulk_client is None: + self._bulk_client = BulkClient(self.url, self.timeout, self.token) + return self._bulk_client + + def metrics(self) -> Metrics: + """Synchronous metrics interface""" + return Metrics(self.url, self.timeout, self.token) + + # New asynchronous methods + def async_flow(self) -> AsyncFlow: + """Asynchronous REST-based flow interface""" + if self._async_flow is None: + self._async_flow = AsyncFlow(self.url, self.timeout, self.token) + return self._async_flow + + def async_socket(self) -> AsyncSocketClient: + """Asynchronous WebSocket-based interface for streaming operations""" + if self._async_socket_client is None: + self._async_socket_client = AsyncSocketClient(self.url, self.timeout, self.token) + return self._async_socket_client + + def async_bulk(self) -> AsyncBulkClient: + """Asynchronous bulk operations interface for import/export""" + if self._async_bulk_client is None: + self._async_bulk_client = AsyncBulkClient(self.url, self.timeout, self.token) + return self._async_bulk_client + + def async_metrics(self) -> AsyncMetrics: + """Asynchronous metrics interface""" + return AsyncMetrics(self.url, self.timeout, self.token) + + # Resource management + def close(self) -> None: + """Close all synchronous connections""" + if self._socket_client: + self._socket_client.close() + if self._bulk_client: + self._bulk_client.close() + + async def aclose(self) -> None: + """Close all asynchronous connections""" + if self._async_socket_client: + await self._async_socket_client.aclose() + if self._async_bulk_client: + await self._async_bulk_client.aclose() + if self._async_flow: + await self._async_flow.aclose() + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + async def __aenter__(self): + return self + + async def __aexit__(self, *args): + await self.aclose() +``` + +#### 2. Cliente WebSocket Síncrono + +Módulo: `trustgraph-base/trustgraph/api/socket_client.py` (nuevo) + +**Clase SocketClient**: + +```python +class SocketClient: + """Synchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> SocketFlowInstance: + """Get flow instance for WebSocket operations""" + return SocketFlowInstance(self, flow_id) + + def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Uses asyncio.run() internally to wrap async websockets library + pass + + def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + # Synchronous wrapper around async WebSocket calls + pass + + def close(self) -> None: + """Close WebSocket connection""" + pass + +class SocketFlowInstance: + """Synchronous WebSocket flow instance with same interface as REST FlowInstance""" + def __init__(self, client: SocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance + def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, Iterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**Características principales:** +Conexión perezosa (solo se conecta cuando se envía la primera solicitud) +Multiplexación de solicitudes (hasta 15 concurrentes) +Reconexión automática en caso de desconexión +Análisis de respuesta en streaming +Operación segura para subprocesos +Envoltorio sincrónico alrededor de la biblioteca de websockets asíncrona + +#### 3. Cliente WebSocket asíncrono + +Módulo: `trustgraph-base/trustgraph/api/async_socket_client.py` (nuevo) + +**Clase AsyncSocketClient:** + +```python +class AsyncSocketClient: + """Asynchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> AsyncSocketFlowInstance: + """Get async flow instance for WebSocket operations""" + return AsyncSocketFlowInstance(self, flow_id) + + async def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Native async websockets library + pass + + async def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + pass + + async def aclose(self) -> None: + """Close WebSocket connection""" + pass + +class AsyncSocketFlowInstance: + """Asynchronous WebSocket flow instance""" + def __init__(self, client: AsyncSocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance (but async) + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, AsyncIterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**Características principales**: +Soporte nativo para async/await +Eficiente para aplicaciones asíncronas (FastAPI, aiohttp) +Sin bloqueo de hilos +Misma interfaz que la versión síncrona +AsyncIterator para streaming + +#### 4. Cliente de Operaciones Masivas Síncronas + +Módulo: `trustgraph-base/trustgraph/api/bulk_client.py` (nuevo) + +**Clase BulkClient**: + +```python +class BulkClient: + """Synchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + def import_triples( + self, + flow: str, + triples: Iterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + def export_triples( + self, + flow: str, + **kwargs + ) -> Iterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + def import_graph_embeddings( + self, + flow: str, + embeddings: Iterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> Iterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + def close(self) -> None: + """Close connections""" + pass +``` + +**Características principales:** +Basado en iteradores para un uso constante de memoria. +Conexiones WebSocket dedicadas por operación. +Seguimiento del progreso (callback opcional). +Manejo de errores con informes de éxito parcial. + +#### 5. Cliente de operaciones masivas asíncronas + +Módulo: `trustgraph-base/trustgraph/api/async_bulk_client.py` (nuevo) + +**Clase AsyncBulkClient:** + +```python +class AsyncBulkClient: + """Asynchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + async def import_triples( + self, + flow: str, + triples: AsyncIterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + async def export_triples( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + async def import_graph_embeddings( + self, + flow: str, + embeddings: AsyncIterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + async def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + async def aclose(self) -> None: + """Close connections""" + pass +``` + +**Características principales:** +Basado en AsyncIterator para un uso constante de memoria. +Eficiente para aplicaciones asíncronas. +Soporte nativo para async/await. +Misma interfaz que la versión síncrona. + +#### 6. API de flujo REST (Síncrono - Sin cambios) + +Módulo: `trustgraph-base/trustgraph/api/flow.py` + +La API de flujo REST permanece **completamente sin cambios** para la compatibilidad con versiones anteriores. Todos los métodos existentes siguen funcionando: + +`Flow.list()`, `Flow.start()`, `Flow.stop()`, etc. +`FlowInstance.agent()`, `FlowInstance.text_completion()`, `FlowInstance.graph_rag()`, etc. +Todas las firmas y tipos de retorno existentes se conservan. + +**Nuevo:** Agregar `graph_embeddings_query()` a REST FlowInstance para la paridad de funciones: + +```python +class FlowInstance: + # All existing methods unchanged... + + # New: Graph embeddings query (REST) + def graph_embeddings_query( + self, + text: str, + user: str, + collection: str, + limit: int = 10, + **kwargs + ) -> List[Dict[str, Any]]: + """Query graph embeddings for semantic search""" + # Calls POST /api/v1/flow/{flow}/service/graph-embeddings + pass +``` + +#### 7. API de flujo REST asíncrono + +Módulo: `trustgraph-base/trustgraph/api/async_flow.py` (nuevo) + +**Clases AsyncFlow y AsyncFlowInstance:** + +```python +class AsyncFlow: + """Asynchronous REST-based flow interface""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def list(self) -> List[Dict[str, Any]]: + """List all flows""" + pass + + async def get(self, id: str) -> Dict[str, Any]: + """Get flow definition""" + pass + + async def start(self, class_name: str, id: str, description: str, parameters: Dict) -> None: + """Start a flow""" + pass + + async def stop(self, id: str) -> None: + """Stop a flow""" + pass + + def id(self, flow_id: str) -> AsyncFlowInstance: + """Get async flow instance""" + return AsyncFlowInstance(self.url, self.timeout, self.token, flow_id) + + async def aclose(self) -> None: + """Close connection""" + pass + +class AsyncFlowInstance: + """Asynchronous REST flow instance""" + + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + **kwargs + ) -> Dict[str, Any]: + """Async agent execution""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + **kwargs + ) -> str: + """Async text completion""" + pass + + async def graph_rag( + self, + question: str, + user: str, + collection: str, + **kwargs + ) -> str: + """Async graph RAG""" + pass + + # ... all other FlowInstance methods as async versions +``` + +**Características principales:** +HTTP asíncrono nativo utilizando `aiohttp` o `httpx` +Mismas firmas de método que la API REST sincrónica +Sin transmisión (utilice `async_socket()` para la transmisión) +Eficiente para aplicaciones asíncronas + +#### 8. API de métricas + +Módulo: `trustgraph-base/trustgraph/api/metrics.py` (nuevo) + +**Métricas sincrónicas:** + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +**Métricas Asíncronas**: + +```python +class AsyncMetrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +#### 9. Tipos Mejorados + +Módulo: `trustgraph-base/trustgraph/api/types.py` (modificado) + +**Nuevos Tipos**: + +```python +from typing import Iterator, Union, Dict, Any +import dataclasses + +@dataclasses.dataclass +class StreamingChunk: + """Base class for streaming chunks""" + content: str + end_of_message: bool = False + +@dataclasses.dataclass +class AgentThought(StreamingChunk): + """Agent reasoning chunk""" + chunk_type: str = "thought" + +@dataclasses.dataclass +class AgentObservation(StreamingChunk): + """Agent tool observation chunk""" + chunk_type: str = "observation" + +@dataclasses.dataclass +class AgentAnswer(StreamingChunk): + """Agent final answer chunk""" + chunk_type: str = "final-answer" + end_of_dialog: bool = False + +@dataclasses.dataclass +class RAGChunk(StreamingChunk): + """RAG streaming chunk""" + end_of_stream: bool = False + error: Optional[Dict[str, str]] = None + +# Type aliases for clarity +AgentStream = Iterator[Union[AgentThought, AgentObservation, AgentAnswer]] +RAGStream = Iterator[RAGChunk] +CompletionStream = Iterator[str] +``` + +#### 6. API de métricas + +Módulo: `trustgraph-base/trustgraph/api/metrics.py` (nuevo) + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +### Enfoque de Implementación + +#### Fase 1: Mejora del API Central (Semana 1) + +1. Agregar métodos `socket()`, `bulk()` y `metrics()` a la clase `Api` +2. Implementar inicialización perezosa para WebSocket y clientes masivos +3. Agregar soporte para administrador de contexto (`__enter__`, `__exit__`) +4. Agregar método `close()` para limpieza +5. Agregar pruebas unitarias para las mejoras del API +6. Verificar compatibilidad con versiones anteriores + +**Compatibilidad con versiones anteriores**: No hay cambios que rompan la compatibilidad. Solo se agregan nuevos métodos. + +#### Fase 2: Cliente WebSocket (Semanas 2-3) + +1. Implementar clase `SocketClient` con gestión de conexión +2. Implementar `SocketFlowInstance` con las mismas firmas de método que `FlowInstance` +3. Agregar soporte para multiplexación de solicitudes (hasta 15 concurrentes) +4. Agregar análisis de respuesta en streaming para diferentes tipos de fragmentos +5. Agregar lógica de reconexión automática +6. Agregar pruebas unitarias e integrales +7. Documentar patrones de uso de WebSocket + +**Compatibilidad con versiones anteriores**: Nueva interfaz solamente. No tiene impacto en el código existente. + +#### Fase 3: Soporte de Streaming (Semanas 3-4) + +1. Agregar clases de tipo de fragmento de streaming (`AgentThought`, `AgentObservation`, `AgentAnswer`, `RAGChunk`) +2. Implementar análisis de respuesta en streaming en `SocketClient` +3. Agregar parámetro de streaming a todos los métodos LLM en `SocketFlowInstance` +4. Manejar casos de error durante el streaming +5. Agregar pruebas unitarias e integrales para el streaming +6. Agregar ejemplos de streaming a la documentación + +**Compatibilidad con versiones anteriores**: Nueva interfaz solamente. El API REST existente no se modifica. + +#### Fase 4: Operaciones Masivas (Semanas 4-5) + +1. Implementar clase `BulkClient` +2. Agregar métodos de importación/exportación masiva para triples, incrustaciones, contextos, objetos +3. Implementar procesamiento basado en iterador para un uso constante de memoria +4. Agregar seguimiento de progreso (callback opcional) +5. Agregar manejo de errores con informes de éxito parcial +6. Agregar pruebas unitarias e integrales +7. Agregar ejemplos de operaciones masivas + +**Compatibilidad con versiones anteriores**: Nueva interfaz solamente. No tiene impacto en el código existente. + +#### Fase 5: Paridad de Funciones y Pulido (Semana 5) + +1. Agregar `graph_embeddings_query()` a REST `FlowInstance` +2. Implementar clase `Metrics` +3. Agregar pruebas de integración exhaustivas +4. Pruebas de rendimiento +5. Actualizar toda la documentación +6. Crear una guía de migración + +**Compatibilidad con versiones anteriores**: Nuevos métodos solamente. No tiene impacto en el código existente. + +### Modelos de Datos + +#### Selección de Interfaz + +```python +# Single API instance, same URL for all interfaces +api = Api(url="http://localhost:8088/") + +# Synchronous interfaces +rest_flow = api.flow().id("default") # Sync REST +socket_flow = api.socket().flow("default") # Sync WebSocket +bulk = api.bulk() # Sync bulk operations +metrics = api.metrics() # Sync metrics + +# Asynchronous interfaces +async_rest_flow = api.async_flow().id("default") # Async REST +async_socket_flow = api.async_socket().flow("default") # Async WebSocket +async_bulk = api.async_bulk() # Async bulk operations +async_metrics = api.async_metrics() # Async metrics +``` + +#### Tipos de respuesta de transmisión + +**Transmisión del agente**: + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - non-streaming (same signature) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - streaming (new) +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentThought): + print(f"Thinking: {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"Observed: {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"Answer: {chunk.content}") + if chunk.end_of_dialog: + break +``` + +**Transmisión RAG**: + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.graph_rag(question="What is Python?", user="user123", collection="default") +print(response) + +# WebSocket interface - streaming (new) +socket_flow = api.socket().flow("default") +for chunk in socket_flow.graph_rag( + question="What is Python?", + user="user123", + collection="default", + streaming=True +): + print(chunk.content, end="", flush=True) + if chunk.end_of_stream: + break +``` + +**Operaciones masivas (síncronas):** + +```python +api = Api(url="http://localhost:8088/") + +# Bulk import triples +def triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Bulk export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +**Operaciones masivas (asíncronas):** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async bulk import triples + async def async_triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + + # Async bulk export triples + async for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") + +asyncio.run(main()) +``` + +**Ejemplo de REST asíncrono**: + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST flow operations + flow = api.async_flow().id("default") + response = await flow.agent(question="What is ML?", user="user123") + print(response["response"]) + +asyncio.run(main()) +``` + +**Ejemplo de transmisión WebSocket asíncrona:** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async WebSocket streaming + socket = api.async_socket() + flow = socket.flow("default") + + async for chunk in flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) + if chunk.end_of_dialog: + break + +asyncio.run(main()) +``` + +### APIs + +#### New APIs + +1. **Clase API Core**: + **Síncrono**: + `Api.socket()` - Obtener cliente WebSocket síncrono + `Api.bulk()` - Obtener cliente de operaciones masivas síncrono + `Api.metrics()` - Obtener cliente de métricas síncrono + `Api.close()` - Cerrar todas las conexiones síncronas + Soporte de administrador de contexto (`__enter__`, `__exit__`) + **Asíncrono**: + `Api.async_flow()` - Obtener cliente de flujo REST asíncrono + `Api.async_socket()` - Obtener cliente WebSocket asíncrono + `Api.async_bulk()` - Obtener cliente de operaciones masivas asíncrono + `Api.async_metrics()` - Obtener cliente de métricas asíncrono + `Api.aclose()` - Cerrar todas las conexiones asíncronas + Soporte de administrador de contexto asíncrono (`__aenter__`, `__aexit__`) + +2. **Cliente WebSocket Síncrono**: + `SocketClient.flow(flow_id)` - Obtener instancia de flujo WebSocket + `SocketFlowInstance.agent(..., streaming: bool = False)` - Agente con transmisión opcional + `SocketFlowInstance.text_completion(..., streaming: bool = False)` - Completar texto con transmisión opcional + `SocketFlowInstance.graph_rag(..., streaming: bool = False)` - RAG de gráfico con transmisión opcional + `SocketFlowInstance.document_rag(..., streaming: bool = False)` - RAG de documento con transmisión opcional + `SocketFlowInstance.prompt(..., streaming: bool = False)` - Prompt con transmisión opcional + `SocketFlowInstance.graph_embeddings_query()` - Consulta de incrustaciones de gráfico + Todos los demás métodos de FlowInstance con firmas idénticas + +3. **Cliente WebSocket Asíncrono**: + `AsyncSocketClient.flow(flow_id)` - Obtener instancia de flujo WebSocket asíncrono + `AsyncSocketFlowInstance.agent(..., streaming: bool = False)` - Agente asíncrono con transmisión opcional + `AsyncSocketFlowInstance.text_completion(..., streaming: bool = False)` - Completar texto asíncrono con transmisión opcional + `AsyncSocketFlowInstance.graph_rag(..., streaming: bool = False)` - RAG de gráfico asíncrono con transmisión opcional + `AsyncSocketFlowInstance.document_rag(..., streaming: bool = False)` - RAG de documento asíncrono con transmisión opcional + `AsyncSocketFlowInstance.prompt(..., streaming: bool = False)` - Prompt asíncrono con transmisión opcional + `AsyncSocketFlowInstance.graph_embeddings_query()` - Consulta de incrustaciones de gráfico asíncrona + Todos los demás métodos de FlowInstance como versiones asíncronas + +4. **Cliente de Operaciones Masivas Síncrono**: + `BulkClient.import_triples(flow, triples)` - Importación masiva de triples + `BulkClient.export_triples(flow)` - Exportación masiva de triples + `BulkClient.import_graph_embeddings(flow, embeddings)` - Importación masiva de incrustaciones de gráfico + `BulkClient.export_graph_embeddings(flow)` - Exportación masiva de incrustaciones de gráfico + `BulkClient.import_document_embeddings(flow, embeddings)` - Importación masiva de incrustaciones de documento + `BulkClient.export_document_embeddings(flow)` - Exportación masiva de incrustaciones de documento + `BulkClient.import_entity_contexts(flow, contexts)` - Importación masiva de contextos de entidades + `BulkClient.export_entity_contexts(flow)` - Exportación masiva de contextos de entidades + `BulkClient.import_objects(flow, objects)` - Importación masiva de objetos + +5. **Cliente de Operaciones Masivas Asíncrono**: + `AsyncBulkClient.import_triples(flow, triples)` - Importación asíncrona masiva de triples + `AsyncBulkClient.export_triples(flow)` - Exportación asíncrona masiva de triples + `AsyncBulkClient.import_graph_embeddings(flow, embeddings)` - Importación asíncrona masiva de incrustaciones de gráfico + `AsyncBulkClient.export_graph_embeddings(flow)` - Exportación asíncrona masiva de incrustaciones de gráfico + `AsyncBulkClient.import_document_embeddings(flow, embeddings)` - Importación asíncrona masiva de incrustaciones de documento + `AsyncBulkClient.export_document_embeddings(flow)` - Exportación asíncrona masiva de incrustaciones de documento + `AsyncBulkClient.import_entity_contexts(flow, contexts)` - Importación asíncrona masiva de contextos de entidades + `AsyncBulkClient.export_entity_contexts(flow)` - Exportación asíncrona masiva de contextos de entidades + `AsyncBulkClient.import_objects(flow, objects)` - Importación asíncrona masiva de objetos + +6. **Cliente de Flujo REST Asíncrono**: + `AsyncFlow.list()` - Listar todos los flujos de forma asíncrona + `AsyncFlow.get(id)` - Obtener definición de flujo de forma asíncrona + `AsyncFlow.start(...)` - Iniciar flujo de forma asíncrona + `AsyncFlow.stop(id)` - Detener flujo de forma asíncrona + `AsyncFlow.id(flow_id)` - Obtener instancia de flujo de forma asíncrona + `AsyncFlowInstance.agent(...)` - Ejecución de agente asíncrona + `AsyncFlowInstance.text_completion(...)` - Completar texto de forma asíncrona + `AsyncFlowInstance.graph_rag(...)` - RAG de gráfico asíncrono + Todos los demás métodos de FlowInstance como versiones asíncronas + +7. **Clientes de Métricas**: + `Metrics.get()` - Métricas de Prometheus síncronas + `AsyncMetrics.get()` - Métricas de Prometheus asíncronas + +8. **Mejora de la API REST de Flujo**: + `FlowInstance.graph_embeddings_query()` - Consulta de incrustaciones de gráfico (paridad de funciones síncronas) + `AsyncFlowInstance.graph_embeddings_query()` - Consulta de incrustaciones de gráfico (paridad de funciones asíncronas) + +#### APIs Modificadas + +1. **Constructor** (pequeña mejora): + ```python + Api(url: str, timeout: int = 60, token: Optional[str] = None) + ``` + Se agregó el parámetro `token` (opcional, para autenticación). + Si `None` no se especifica (por defecto): No se utiliza autenticación. + Si se especifica: Se utiliza como token de tipo "bearer" para REST (`Authorization: Bearer `), parámetro de consulta para WebSocket (`?token=`). + No se realizaron otros cambios; es totalmente compatible con versiones anteriores. + +2. **Sin cambios que rompan la compatibilidad**: + Todos los métodos de la API REST existentes no se han modificado. + Todas las firmas existentes se han conservado. + Todos los tipos de retorno existentes se han conservado. + +### Detalles de implementación + +#### Manejo de errores + +**Errores de conexión WebSocket**: +```python +try: + api = Api(url="http://localhost:8088/") + socket = api.socket() + socket_flow = socket.flow("default") + response = socket_flow.agent(question="...", user="user123") +except ConnectionError as e: + print(f"WebSocket connection failed: {e}") + print("Hint: Ensure Gateway is running and WebSocket endpoint is accessible") +``` + +**Respaldo Elegante**: +```python +api = Api(url="http://localhost:8088/") + +try: + # Try WebSocket streaming first + socket_flow = api.socket().flow("default") + for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk.content) +except ConnectionError: + # Fall back to REST non-streaming + print("WebSocket unavailable, falling back to REST") + rest_flow = api.flow().id("default") + response = rest_flow.agent(question="...", user="...") + print(response["response"]) +``` + +**Errores de transmisión parcial**: +```python +api = Api(url="http://localhost:8088/") +socket_flow = api.socket().flow("default") + +accumulated = [] +try: + for chunk in socket_flow.graph_rag(question="...", streaming=True): + accumulated.append(chunk.content) + if chunk.error: + print(f"Error occurred: {chunk.error}") + print(f"Partial response: {''.join(accumulated)}") + break +except Exception as e: + print(f"Streaming error: {e}") + print(f"Partial response: {''.join(accumulated)}") +``` + +#### Gestión de Recursos + +**Soporte para Administradores de Contexto**: +```python +# Automatic cleanup +with Api(url="http://localhost:8088/") as api: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +# All connections automatically closed + +# Manual cleanup +api = Api(url="http://localhost:8088/") +try: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +finally: + api.close() # Explicitly close all connections (WebSocket, bulk, etc.) +``` + +#### Concurrencia y Subprocesamiento + +**Seguridad de Subprocesos**: +Cada instancia de `Api` mantiene su propia conexión. +El transporte WebSocket utiliza bloqueos para el multiplexado de solicitudes, que es seguro para subprocesos. +Múltiples subprocesos pueden compartir una instancia de `Api` de forma segura. +Los iteradores de transmisión no son seguros para subprocesos (se deben consumir desde un solo subproceso). + +**Soporte Asíncrono** (consideración futura): +```python +# Phase 2 enhancement (not in initial scope) +import asyncio + +async def main(): + api = await AsyncApi(url="ws://localhost:8088/") + flow = api.flow().id("default") + + async for chunk in flow.agent(question="...", streaming=True): + print(chunk.content) + + await api.close() + +asyncio.run(main()) +``` + +## Consideraciones de seguridad + +### Autenticación + +**Parámetro de token**: +```python +# No authentication (default) +api = Api(url="http://localhost:8088/") + +# With authentication +api = Api(url="http://localhost:8088/", token="mytoken") +``` + +**Transporte REST**: +Token del portador a través del encabezado `Authorization` +Se aplica automáticamente a todas las solicitudes REST +Formato: `Authorization: Bearer ` + +**Transporte WebSocket**: +Token a través de un parámetro de consulta adjunto a la URL de WebSocket +Se aplica automáticamente durante el establecimiento de la conexión +Formato: `ws://localhost:8088/api/v1/socket?token=` + +**Implementación**: +```python +class SocketClient: + def _connect(self) -> WebSocket: + # Construct WebSocket URL with optional token + ws_url = f"{self.url}/api/v1/socket" + if self.token: + ws_url = f"{ws_url}?token={self.token}" + # Connect to WebSocket + return websocket.connect(ws_url) +``` + +**Ejemplo:** +```python +# REST with auth +api = Api(url="http://localhost:8088/", token="mytoken") +flow = api.flow().id("default") +# All REST calls include: Authorization: Bearer mytoken + +# WebSocket with auth +socket = api.socket() +# Connects to: ws://localhost:8088/api/v1/socket?token=mytoken +``` + +### Comunicación Segura + +Soporta tanto los esquemas WS (WebSocket) como los de WSS (WebSocket Secure). +Validación de certificados TLS para conexiones WSS. +Verificación de certificados opcional para desarrollo (con advertencia). + +### Validación de Datos de Entrada + +Validar esquemas de URL (http, https, ws, wss). +Validar valores de parámetros de transporte. +Validar combinaciones de parámetros de transmisión. +Validar tipos de datos para la importación masiva. + +## Consideraciones de Rendimiento + +### Mejoras en la Latencia + +**Operaciones de LLM en Transmisión**: +**Tiempo hasta el primer token**: ~500ms (vs ~30s sin transmisión) +**Mejora**: 60 veces más rápido en términos de rendimiento percibido. +**Aplicable a**: Agente, Graph RAG, Document RAG, Completar Texto, Prompt. + +**Conexiones Persistentes**: +**Sobrecarga de la conexión**: Eliminada para solicitudes posteriores. +**Handshake de WebSocket**: Costo único (~100ms). +**Aplicable a**: Todas las operaciones al usar el transporte WebSocket. + +### Mejoras en el Rendimiento (Throughput) + +**Operaciones Masivas**: +**Importación de triples**: ~10,000 triples/segundo (vs ~100/segundo con REST por elemento). +**Importación de embeddings**: ~5,000 embeddings/segundo (vs ~50/segundo con REST por elemento). +**Mejora**: 100 veces más de rendimiento para operaciones masivas. + +**Multiplexación de Solicitudes**: +**Solicitudes concurrentes**: Hasta 15 solicitudes simultáneas sobre una sola conexión. +**Reutilización de la conexión**: Sin sobrecarga de conexión para operaciones concurrentes. + +### Consideraciones de Memoria + +**Respuestas en Transmisión**: +Uso constante de memoria (procesa los fragmentos a medida que llegan). +No se almacena en búfer la respuesta completa. +Adecuado para salidas muy largas (>1MB). + +**Operaciones Masivas**: +Procesamiento basado en iteradores (uso constante de memoria). +No se carga todo el conjunto de datos en la memoria. +Adecuado para conjuntos de datos con millones de elementos. + +### Pruebas de Rendimiento (Esperadas) + +| Operación | REST (existente) | WebSocket (en transmisión) | Mejora | +|-----------|----------------|----------------------|-------------| +| Agente (tiempo hasta el primer token) | 30s | 0.5s | 60x | +| Graph RAG (tiempo hasta el primer token) | 25s | 0.5s | 50x | +| Importar 10K triples | 100s | 1s | 100x | +| Importar 1M triples | 10,000s (2.7h) | 100s (1.6m) | 100x | +| 10 solicitudes pequeñas concurrentes | 5s (secuencial) | 0.5s (paralelo) | 10x | + +## Estrategia de Pruebas + +### Pruebas Unitarias + +**Capa de Transporte** (`test_transport.py`): +Probar la solicitud/respuesta de transporte REST +Probar la conexión de transporte WebSocket +Probar la reconexión de transporte WebSocket +Probar el multiplexado de solicitudes +Probar el análisis de la respuesta de transmisión +Simular un servidor WebSocket para pruebas deterministas + +**Métodos de la API** (`test_flow.py`, `test_library.py`, etc.): +Probar nuevos métodos con transporte simulado +Probar el manejo de parámetros de transmisión +Probar iteradores de operaciones masivas +Probar el manejo de errores + +**Tipos** (`test_types.py`): +Probar nuevos tipos de fragmentos de transmisión +Probar la serialización/deserialización de tipos + +### Pruebas de Integración + +**REST de Extremo a Extremo** (`test_integration_rest.py`): +Probar todas las operaciones contra la puerta de enlace real (modo REST) +Verificar la compatibilidad con versiones anteriores +Probar condiciones de error + +**WebSocket de Extremo a Extremo** (`test_integration_websocket.py`): +Probar todas las operaciones contra la puerta de enlace real (modo WebSocket) +Probar operaciones de transmisión +Probar operaciones masivas +Probar solicitudes concurrentes +Probar la recuperación de la conexión + +**Servicios de Transmisión** (`test_streaming_integration.py`): +Probar la transmisión de agentes (pensamientos, observaciones, respuestas) +Probar la transmisión de RAG (fragmentos incrementales) +Probar la transmisión de finalización de texto (token por token) +Probar la transmisión de indicaciones +Probar el manejo de errores durante la transmisión + +**Operaciones Masivas** (`test_bulk_integration.py`): +Probar la importación/exportación masiva de triples (1K, 10K, 100K elementos) +Probar la importación/exportación masiva de incrustaciones +Probar el uso de memoria durante las operaciones masivas +Probar el seguimiento del progreso + +### Pruebas de Rendimiento + +**Mediciones de Latencia** (`test_performance_latency.py`): +Medir el tiempo hasta el primer token (transmisión vs. no transmisión) +Medir la sobrecarga de la conexión (REST vs WebSocket) +Comparar con puntos de referencia esperados + +**Mediciones de Rendimiento** (`test_performance_throughput.py`): +Medir el rendimiento de la importación masiva +Medir la eficiencia del multiplexado de solicitudes +Comparar con puntos de referencia esperados + +### Pruebas de Compatibilidad + +**Compatibilidad con Versiones Anteriores** (`test_backward_compatibility.py`): +Ejecutar el conjunto de pruebas existente contra la API refactorizada +Verificar la ausencia de cambios que rompan la compatibilidad +Probar la ruta de migración para patrones comunes + +## Plan de Migración + +### Fase 1: Migración Transparente (Predeterminada) + +**No se requieren cambios en el código**. El código existente continúa funcionando: + +```python +# Existing code works unchanged +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") +response = flow.agent(question="What is ML?", user="user123") +``` + +### Fase 2: Transmisión por demanda (Simple) + +**Utilice la interfaz `api.socket()`** para habilitar la transmisión: + +```python +# Before: Non-streaming REST +api = Api(url="http://localhost:8088/") +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# After: Streaming WebSocket (same parameters!) +api = Api(url="http://localhost:8088/") # Same URL +socket_flow = api.socket().flow("default") + +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) +``` + +**Puntos clave:** +La misma URL para REST y WebSocket. +Las mismas firmas de métodos (migración sencilla). +Simplemente agregue `.socket()` y `streaming=True`. + +### Fase 3: Operaciones masivas (Nueva funcionalidad) + +**Utilice la interfaz `api.bulk()`** para conjuntos de datos grandes: + +```python +# Before: Inefficient per-item operations +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") + +for triple in my_large_triple_list: + # Slow per-item operations + # (no direct bulk insert in REST API) + pass + +# After: Efficient bulk loading +api = Api(url="http://localhost:8088/") # Same URL +bulk = api.bulk() + +# This is fast (10,000 triples/second) +bulk.import_triples(flow="default", triples=iter(my_large_triple_list)) +``` + +### Actualizaciones de la documentación + +1. **README.md**: Agregar ejemplos de transmisión y WebSocket +2. **Referencia de la API**: Documentar todos los nuevos métodos y parámetros +3. **Guía de migración**: Guía paso a paso para habilitar la transmisión +4. **Ejemplos**: Agregar scripts de ejemplo para patrones comunes +5. **Guía de rendimiento**: Documentar las mejoras de rendimiento esperadas + +### Política de obsolescencia + +**No hay obsolescencias**. Todas las API existentes siguen siendo compatibles. Esto es una mejora pura. + +## Cronograma + +### Semana 1: Base +Capa de abstracción de transporte +Refactorizar código REST existente +Pruebas unitarias para la capa de transporte +Verificación de compatibilidad con versiones anteriores + +### Semana 2: Transporte WebSocket +Implementación del transporte WebSocket +Gestión de conexiones y reconexión +Multiplexación de solicitudes +Pruebas unitarias e de integración + +### Semana 3: Soporte de transmisión +Agregar parámetro de transmisión a los métodos de LLM +Implementar el análisis de respuestas de transmisión +Agregar tipos de fragmentos de transmisión +Pruebas de integración de transmisión + +### Semana 4: Operaciones masivas +Agregar métodos de importación/exportación masivos +Implementar operaciones basadas en iteradores +Pruebas de rendimiento +Pruebas de integración de operaciones masivas + +### Semana 5: Paridad de funciones y documentación +Agregar consulta de incrustaciones de grafos +Agregar API de métricas +Documentación completa +Guía de migración +Versión candidata + +### Semana 6: Lanzamiento +Pruebas de integración finales +Pruebas de referencia de rendimiento +Documentación de lanzamiento +Anuncio a la comunidad + +**Duración total**: 6 semanas + +## Preguntas abiertas + +### Preguntas de diseño de la API + +1. **Soporte asíncrono**: ✅ **RESUELTO** - Soporte asíncrono completo incluido en el lanzamiento inicial + Todas las interfaces tienen variantes asíncronas: `async_flow()`, `async_socket()`, `async_bulk()`, `async_metrics()` + Proporciona una simetría completa entre las API sincrónicas y asíncronas + Esencial para marcos de trabajo asíncronos modernos (FastAPI, aiohttp) + +2. **Seguimiento del progreso**: ¿Deben las operaciones masivas admitir devoluciones de llamada de progreso? + ```python + def progress_callback(processed: int, total: Optional[int]): + print(f"Processed {processed} items") + + bulk.import_triples(flow="default", triples=triples, on_progress=progress_callback) + ``` + **Recomendación**: Agregar en la Fase 2. No es crítico para la versión inicial. + +3. **Tiempo de espera de la transmisión**: ¿Cómo debemos manejar los tiempos de espera para las operaciones de transmisión? + **Recomendación**: Utilizar el mismo tiempo de espera que para las operaciones no de transmisión, pero restablecerlo cada vez que se recibe un fragmento. + +4. **Almacenamiento en búfer de fragmentos**: ¿Debemos almacenar los fragmentos en búfer o devolverlos inmediatamente? + **Recomendación**: Devolverlos inmediatamente para lograr la menor latencia. + +5. **Servicios globales a través de WebSocket**: ¿Debería `api.socket()` admitir servicios globales (biblioteca, conocimiento, colección, configuración) o solo servicios específicos del flujo? + **Recomendación**: Comenzar solo con servicios específicos del flujo (donde la transmisión es importante). Agregar servicios globales si es necesario en la Fase 2. + +### Preguntas de implementación + +1. **Biblioteca de WebSocket**: ¿Debemos usar `websockets`, `websocket-client` o `aiohttp`? + **Recomendación**: `websockets` (asíncrono, maduro, bien mantenido). Envolverlo en una interfaz síncrona utilizando `asyncio.run()`. + +2. **Grupo de conexiones**: ¿Debemos admitir múltiples instancias concurrentes de `Api` que compartan un grupo de conexiones? + **Recomendación**: Dejar para la Fase 2. Cada instancia de `Api` tendrá sus propias conexiones inicialmente. + +3. **Reutilización de conexiones**: ¿Deben `SocketClient` y `BulkClient` compartir la misma conexión de WebSocket, o usar conexiones separadas? + **Recomendación**: Conexiones separadas. Implementación más sencilla, separación de responsabilidades más clara. + +4. **Conexión perezosa vs. activa**: ¿Se debe establecer la conexión de WebSocket en `api.socket()` o en la primera solicitud? + **Recomendación**: Perezosa (en la primera solicitud). Evita la sobrecarga de la conexión si el usuario solo utiliza métodos REST. + +### Preguntas de prueba + +1. **Pasarela de simulación**: ¿Debemos crear una pasarela de simulación ligera para las pruebas, o probar contra la pasarela real? + **Recomendación**: Ambos. Utilizar simulaciones para pruebas unitarias, y la pasarela real para pruebas de integración. + +2. **Pruebas de regresión de rendimiento**: ¿Debemos agregar pruebas de regresión de rendimiento automatizadas a CI? + **Recomendación**: Sí, pero con umbrales amplios para tener en cuenta la variabilidad del entorno de CI. + +## Referencias + +### Especificaciones técnicas relacionadas +`docs/tech-specs/streaming-llm-responses.md` - Implementación de transmisión en la pasarela +`docs/tech-specs/rag-streaming-support.md` - Soporte de transmisión RAG + +### Archivos de implementación +`trustgraph-base/trustgraph/api/` - Código fuente de la API de Python +`trustgraph-flow/trustgraph/gateway/` - Código fuente de la pasarela +`trustgraph-flow/trustgraph/gateway/dispatch/mux.py` - Implementación de referencia de multiplexor de WebSocket + +### Documentación +`docs/apiSpecification.md` - Referencia completa de la API +`docs/api-status-summary.md` - Resumen del estado de la API +`README.websocket` - Documentación del protocolo WebSocket +`STREAMING-IMPLEMENTATION-NOTES.txt` - Notas de implementación de transmisión + +### Bibliotecas externas +`websockets` - Biblioteca de WebSocket de Python (https://websockets.readthedocs.io/) +`requests` - Biblioteca HTTP de Python (existente) diff --git a/docs/tech-specs/python-api-refactor.he.md b/docs/tech-specs/python-api-refactor.he.md new file mode 100644 index 00000000..b9279844 --- /dev/null +++ b/docs/tech-specs/python-api-refactor.he.md @@ -0,0 +1,1508 @@ +# Python API Refactor Technical Specification + +## Overview + +This specification describes a comprehensive refactor of the TrustGraph Python API client library to achieve feature parity with the API Gateway and add support for modern real-time communication patterns. + +The refactor addresses four primary use cases: + +1. **Streaming LLM Interactions**: Enable real-time streaming of LLM responses (agent, graph RAG, document RAG, text completion, prompts) with ~60x lower latency (500ms vs 30s for first token) +2. **Bulk Data Operations**: Support efficient bulk import/export of triples, graph embeddings, and document embeddings for large-scale knowledge graph management +3. **Feature Parity**: Ensure every API Gateway endpoint has a corresponding Python API method, including graph embeddings query +4. **Persistent Connections**: Enable WebSocket-based communication for multiplexed requests and reduced connection overhead + +## Goals + +**Feature Parity**: Every Gateway API service has a corresponding Python API method +**Streaming Support**: All streaming-capable services (agent, RAG, text completion, prompt) support streaming in Python API +**WebSocket Transport**: Add optional WebSocket transport layer for persistent connections and multiplexing +**Bulk Operations**: Add efficient bulk import/export for triples, graph embeddings, and document embeddings +**Full Async Support**: Complete async/await implementation for all interfaces (REST, WebSocket, bulk operations, metrics) +**Backward Compatibility**: Existing code continues to work without modification +**Type Safety**: Maintain type-safe interfaces with dataclasses and type hints +**Progressive Enhancement**: Streaming and async are opt-in via explicit interface selection +**Performance**: Achieve 60x latency improvement for streaming operations +**Modern Python**: Support for both sync and async paradigms for maximum flexibility + +## Background + +### Current State + +The Python API (`trustgraph-base/trustgraph/api/`) is a REST-only client library with the following modules: + +`flow.py`: Flow management and flow-scoped services (50 methods) +`library.py`: Document library operations (9 methods) +`knowledge.py`: KG core management (4 methods) +`collection.py`: Collection metadata (3 methods) +`config.py`: Configuration management (6 methods) +`types.py`: Data type definitions (5 dataclasses) + +**Total Operations**: 50/59 (85% coverage) + +### Current Limitations + +**Missing Operations**: +Graph embeddings query (semantic search over graph entities) +Bulk import/export for triples, graph embeddings, document embeddings, entity contexts, objects +Metrics endpoint + +**Missing Capabilities**: +Streaming support for LLM services +WebSocket transport +Multiplexed concurrent requests +Persistent connections + +**Performance Issues**: +High latency for LLM interactions (~30s time-to-first-token) +Inefficient bulk data transfer (REST request per item) +Connection overhead for multiple sequential operations + +**User Experience Issues**: +No real-time feedback during LLM generation +Cannot cancel long-running LLM operations +Poor scalability for bulk operations + +### Impact + +The November 2024 streaming enhancement to the Gateway API provided 60x latency improvement (500ms vs 30s first token) for LLM interactions, but Python API users cannot leverage this capability. This creates a significant experience gap between Python and non-Python users. + +## Technical Design + +### Architecture + +The refactored Python API uses a **modular interface approach** with separate objects for different communication patterns. All interfaces are available in both **synchronous and asynchronous** variants: + +1. **REST Interface** (existing, enhanced) + **Sync**: `api.flow()`, `api.library()`, `api.knowledge()`, `api.collection()`, `api.config()` + **Async**: `api.async_flow()` + Synchronous/asynchronous request/response + Simple connection model + Default for backward compatibility + +2. **WebSocket Interface** (new) + **Sync**: `api.socket()` + **Async**: `api.async_socket()` + Persistent connection + Multiplexed requests + Streaming support + Same method signatures as REST where functionality overlaps + +3. **Bulk Operations Interface** (new) + **Sync**: `api.bulk()` + **Async**: `api.async_bulk()` + WebSocket-based for efficiency + Iterator/AsyncIterator-based import/export + Handles large datasets + +4. **Metrics Interface** (new) + **Sync**: `api.metrics()` + **Async**: `api.async_metrics()` + Prometheus metrics access + +```python +import asyncio + +# Synchronous interfaces +api = Api(url="http://localhost:8088/") + +# REST (existing, unchanged) +flow = api.flow().id("default") +response = flow.agent(question="...", user="...") + +# WebSocket (new) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="...", user="...") +for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk) + +# Bulk operations (new) +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Asynchronous interfaces +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST (new) + flow = api.async_flow().id("default") + response = await flow.agent(question="...", user="...") + + # Async WebSocket (new) + socket_flow = api.async_socket().flow("default") + async for chunk in socket_flow.agent(question="...", streaming=True): + print(chunk) + + # Async bulk operations (new) + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + +asyncio.run(main()) +``` + +**עקרונות עיצוב מרכזיים:** +**כתובת URL זהה לכל הממשקים:** `Api(url="http://localhost:8088/")` עובד עבור כל +**סימטריה בין סינכרוני/אסינכרוני:** לכל ממשק יש גרסאות סינכרוניות ואסינכרוניות עם חתימות מתודות זהות. +**חתימות זהות:** כאשר יש חפיפה בפונקציונליות, חתימות המתודות זהות בין REST ו-WebSocket, סינכרוני ואסינכרוני. +**שיפור הדרגתי:** בחרו ממשק בהתאם לצרכים (REST לפשוט, WebSocket לסטרימינג, Bulk עבור מערכי נתונים גדולים, אסינכרוני עבור מסגרות עבודה מודרניות). +**כוונת שימוש מפורשת:** `api.socket()` מציין WebSocket, `api.async_socket()` מציין WebSocket אסינכרוני. +**תואם לאחור:** קוד קיים אינו משתנה. + +### רכיבים + +#### 1. מחלקת API מרכזית (משופרת) + +מודול: `trustgraph-base/trustgraph/api/api.py` + +**מחלקת API משופרת:** + +```python +class Api: + def __init__(self, url: str, timeout: int = 60, token: Optional[str] = None): + self.url = url + self.timeout = timeout + self.token = token # Optional bearer token for REST, query param for WebSocket + self._socket_client = None + self._bulk_client = None + self._async_flow = None + self._async_socket_client = None + self._async_bulk_client = None + + # Existing synchronous methods (unchanged) + def flow(self) -> Flow: + """Synchronous REST-based flow interface""" + pass + + def library(self) -> Library: + """Synchronous REST-based library interface""" + pass + + def knowledge(self) -> Knowledge: + """Synchronous REST-based knowledge interface""" + pass + + def collection(self) -> Collection: + """Synchronous REST-based collection interface""" + pass + + def config(self) -> Config: + """Synchronous REST-based config interface""" + pass + + # New synchronous methods + def socket(self) -> SocketClient: + """Synchronous WebSocket-based interface for streaming operations""" + if self._socket_client is None: + self._socket_client = SocketClient(self.url, self.timeout, self.token) + return self._socket_client + + def bulk(self) -> BulkClient: + """Synchronous bulk operations interface for import/export""" + if self._bulk_client is None: + self._bulk_client = BulkClient(self.url, self.timeout, self.token) + return self._bulk_client + + def metrics(self) -> Metrics: + """Synchronous metrics interface""" + return Metrics(self.url, self.timeout, self.token) + + # New asynchronous methods + def async_flow(self) -> AsyncFlow: + """Asynchronous REST-based flow interface""" + if self._async_flow is None: + self._async_flow = AsyncFlow(self.url, self.timeout, self.token) + return self._async_flow + + def async_socket(self) -> AsyncSocketClient: + """Asynchronous WebSocket-based interface for streaming operations""" + if self._async_socket_client is None: + self._async_socket_client = AsyncSocketClient(self.url, self.timeout, self.token) + return self._async_socket_client + + def async_bulk(self) -> AsyncBulkClient: + """Asynchronous bulk operations interface for import/export""" + if self._async_bulk_client is None: + self._async_bulk_client = AsyncBulkClient(self.url, self.timeout, self.token) + return self._async_bulk_client + + def async_metrics(self) -> AsyncMetrics: + """Asynchronous metrics interface""" + return AsyncMetrics(self.url, self.timeout, self.token) + + # Resource management + def close(self) -> None: + """Close all synchronous connections""" + if self._socket_client: + self._socket_client.close() + if self._bulk_client: + self._bulk_client.close() + + async def aclose(self) -> None: + """Close all asynchronous connections""" + if self._async_socket_client: + await self._async_socket_client.aclose() + if self._async_bulk_client: + await self._async_bulk_client.aclose() + if self._async_flow: + await self._async_flow.aclose() + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + async def __aenter__(self): + return self + + async def __aexit__(self, *args): + await self.aclose() +``` + +#### 2. לקוח WebSocket סינכרוני + +מודול: `trustgraph-base/trustgraph/api/socket_client.py` (חדש) + +**מחלקה SocketClient**: + +```python +class SocketClient: + """Synchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> SocketFlowInstance: + """Get flow instance for WebSocket operations""" + return SocketFlowInstance(self, flow_id) + + def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Uses asyncio.run() internally to wrap async websockets library + pass + + def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + # Synchronous wrapper around async WebSocket calls + pass + + def close(self) -> None: + """Close WebSocket connection""" + pass + +class SocketFlowInstance: + """Synchronous WebSocket flow instance with same interface as REST FlowInstance""" + def __init__(self, client: SocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance + def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, Iterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**תכונות עיקריות:** +חיבור עצלני (מתחבר רק כאשר מתקבלת בקשה ראשונה) +ריבוב בקשות (עד 15 בקשות בו-זמנית) +חיבור מחדש אוטומטי במקרה של ניתוק +ניתוח תגובה בשיטת סטרימינג +פעולה בטוחה לשימוש ב-threads +עטיפה סינכרונית עבור ספריית websockets אסינכרונית + +#### 3. לקוח WebSocket אסינכרוני + +מודול: `trustgraph-base/trustgraph/api/async_socket_client.py` (חדש) + +**מחלקה AsyncSocketClient:** + +```python +class AsyncSocketClient: + """Asynchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> AsyncSocketFlowInstance: + """Get async flow instance for WebSocket operations""" + return AsyncSocketFlowInstance(self, flow_id) + + async def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Native async websockets library + pass + + async def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + pass + + async def aclose(self) -> None: + """Close WebSocket connection""" + pass + +class AsyncSocketFlowInstance: + """Asynchronous WebSocket flow instance""" + def __init__(self, client: AsyncSocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance (but async) + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, AsyncIterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**תכונות עיקריות:** +תמיכה מובנית ב-async/await +יעיל עבור יישומים אסינכרוניים (FastAPI, aiohttp) +ללא חסימת תהליכים +ממשק זהה לגרסה הסינכרונית +AsyncIterator עבור סטרימינג + +#### 4. לקוח לפעולות סינכרוניות מרובות + +מודול: `trustgraph-base/trustgraph/api/bulk_client.py` (חדש) + +**מחלקה BulkClient:** + +```python +class BulkClient: + """Synchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + def import_triples( + self, + flow: str, + triples: Iterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + def export_triples( + self, + flow: str, + **kwargs + ) -> Iterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + def import_graph_embeddings( + self, + flow: str, + embeddings: Iterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> Iterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + def close(self) -> None: + """Close connections""" + pass +``` + +**תכונות עיקריות:** +מבוסס על איטרטור לשימוש קבוע בזיכרון +חיבורי WebSocket ייעודיים לכל פעולה +מעקב אחר התקדמות (אופציונלי, באמצעות פונקציית החזרה) +טיפול בשגיאות עם דיווח על הצלחה חלקית + +#### 5. לקוח לפעולות אסינכרוניות מרובות + +מודול: `trustgraph-base/trustgraph/api/async_bulk_client.py` (חדש) + +**מחלקה: AsyncBulkClient**: + +```python +class AsyncBulkClient: + """Asynchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + async def import_triples( + self, + flow: str, + triples: AsyncIterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + async def export_triples( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + async def import_graph_embeddings( + self, + flow: str, + embeddings: AsyncIterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + async def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + async def aclose(self) -> None: + """Close connections""" + pass +``` + +**תכונות עיקריות:** +מבוסס על AsyncIterator לשימוש קבוע בזיכרון +יעיל עבור יישומים אסינכרוניים +תמיכה מובנית ב-async/await +אותו ממשק כמו הגרסה הסינכרונית + +#### 6. ממשק REST Flow (סינכרוני - ללא שינוי) + +מודול: `trustgraph-base/trustgraph/api/flow.py` + +ממשק REST Flow נשאר **ללא שינוי מוחלט** לצורך תאימות לאחור. כל השיטות הקיימות ממשיכות לעבוד: + +`Flow.list()`, `Flow.start()`, `Flow.stop()`, וכו'. +`FlowInstance.agent()`, `FlowInstance.text_completion()`, `FlowInstance.graph_rag()`, וכו'. +כל החתימות וטיפוסי ההחזרה הקיימים נשמרו + +**חדש:** הוספת `graph_embeddings_query()` ל-REST FlowInstance לצורך התאמה: + +```python +class FlowInstance: + # All existing methods unchanged... + + # New: Graph embeddings query (REST) + def graph_embeddings_query( + self, + text: str, + user: str, + collection: str, + limit: int = 10, + **kwargs + ) -> List[Dict[str, Any]]: + """Query graph embeddings for semantic search""" + # Calls POST /api/v1/flow/{flow}/service/graph-embeddings + pass +``` + +#### 7. ממשק REST אסינכרוני + +מודול: `trustgraph-base/trustgraph/api/async_flow.py` (חדש) + +**מחלקות AsyncFlow ו-AsyncFlowInstance**: + +```python +class AsyncFlow: + """Asynchronous REST-based flow interface""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def list(self) -> List[Dict[str, Any]]: + """List all flows""" + pass + + async def get(self, id: str) -> Dict[str, Any]: + """Get flow definition""" + pass + + async def start(self, class_name: str, id: str, description: str, parameters: Dict) -> None: + """Start a flow""" + pass + + async def stop(self, id: str) -> None: + """Stop a flow""" + pass + + def id(self, flow_id: str) -> AsyncFlowInstance: + """Get async flow instance""" + return AsyncFlowInstance(self.url, self.timeout, self.token, flow_id) + + async def aclose(self) -> None: + """Close connection""" + pass + +class AsyncFlowInstance: + """Asynchronous REST flow instance""" + + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + **kwargs + ) -> Dict[str, Any]: + """Async agent execution""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + **kwargs + ) -> str: + """Async text completion""" + pass + + async def graph_rag( + self, + question: str, + user: str, + collection: str, + **kwargs + ) -> str: + """Async graph RAG""" + pass + + # ... all other FlowInstance methods as async versions +``` + +**תכונות עיקריות:** +שימוש ב-HTTP אסינכרוני באמצעות `aiohttp` או `httpx` +אותם חתימות מתודות כמו ב-API REST סינכרוני +ללא סטרימינג (יש להשתמש ב-`async_socket()` עבור סטרימינג) +יעיל עבור יישומים אסינכרוניים + +#### 8. ממשק API למדדים + +מודול: `trustgraph-base/trustgraph/api/metrics.py` (חדש) + +**מדדים סינכרוניים:** + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +**מדדי אסינכרוניים:** + +```python +class AsyncMetrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +#### 9. סוגים משופרים + +מודול: `trustgraph-base/trustgraph/api/types.py` (ערוך) + +**סוגים חדשים**: + +```python +from typing import Iterator, Union, Dict, Any +import dataclasses + +@dataclasses.dataclass +class StreamingChunk: + """Base class for streaming chunks""" + content: str + end_of_message: bool = False + +@dataclasses.dataclass +class AgentThought(StreamingChunk): + """Agent reasoning chunk""" + chunk_type: str = "thought" + +@dataclasses.dataclass +class AgentObservation(StreamingChunk): + """Agent tool observation chunk""" + chunk_type: str = "observation" + +@dataclasses.dataclass +class AgentAnswer(StreamingChunk): + """Agent final answer chunk""" + chunk_type: str = "final-answer" + end_of_dialog: bool = False + +@dataclasses.dataclass +class RAGChunk(StreamingChunk): + """RAG streaming chunk""" + end_of_stream: bool = False + error: Optional[Dict[str, str]] = None + +# Type aliases for clarity +AgentStream = Iterator[Union[AgentThought, AgentObservation, AgentAnswer]] +RAGStream = Iterator[RAGChunk] +CompletionStream = Iterator[str] +``` + +#### 6. ממשק API למדדים + +מודול: `trustgraph-base/trustgraph/api/metrics.py` (חדש) + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +### גישת יישום + +#### שלב 1: שיפורי API מרכזיים (שבוע 1) + +1. הוספת שיטות `socket()`, `bulk()` ו-`metrics()` למחלקה `Api` +2. יישום אתחול עצלני עבור לקוחות WebSocket ו-bulk +3. הוספת תמיכה במנהל הקשר (`__enter__`, `__exit__`) +4. הוספת שיטה `close()` לניקוי +5. הוספת בדיקות יחידה לשיפורי מחלקת API +6. אימות תאימות לאחור + +**תאימות לאחור**: אין שינויים משמעותיים. רק שיטות חדשות. + +#### שלב 2: לקוח WebSocket (שבועות 2-3) + +1. יישום מחלקה `SocketClient` עם ניהול חיבור +2. יישום `SocketFlowInstance` עם אותם חתימות שיטה כמו `FlowInstance` +3. הוספת תמיכה בריבוי בקשות (עד 15 מקבילים) +4. הוספת ניתוח תגובה בסטרימינג עבור סוגי חלקים שונים +5. הוספת לוגיקת חיבור מחדש אוטומטית +6. הוספת בדיקות יחידה ושילוב +7. תיעוד דפוסי שימוש ב-WebSocket + +**תאימות לאחור**: ממשק חדש בלבד. ללא השפעה על קוד קיים. + +#### שלב 3: תמיכה בסטרימינג (שבועות 3-4) + +1. הוספת מחלקות סוגי חלקים בסטרימינג (`AgentThought`, `AgentObservation`, `AgentAnswer`, `RAGChunk`) +2. יישום ניתוח תגובה בסטרימינג ב-`SocketClient` +3. הוספת פרמטר סטרימינג לכל שיטות LLM ב-`SocketFlowInstance` +4. טיפול במקרים שגויים במהלך סטרימינג +5. הוספת בדיקות יחידה ושילוב עבור סטרימינג +6. הוספת דוגמאות סטרימינג לתיעוד + +**תאימות לאחור**: ממשק חדש בלבד. API REST קיים ללא שינוי. + +#### שלב 4: פעולות Bulk (שבועות 4-5) + +1. יישום מחלקה `BulkClient` +2. הוספת שיטות ייבוא/ייצוא bulk עבור משולשות, הטבעות, הקשרים, אובייקטים +3. יישום עיבוד מבוסס איטרטור עבור זיכרון קבוע +4. הוספת מעקב התקדמות (callback אופציונלי) +5. הוספת טיפול בשגיאות עם דיווח על הצלחה חלקית +6. הוספת בדיקות יחידה ושילוב +7. הוספת דוגמאות לפעולות bulk + +**תאימות לאחור**: ממשק חדש בלבד. ללא השפעה על קוד קיים. + +#### שלב 5: התאמה וליטוש (שבוע 5) + +1. הוספת `graph_embeddings_query()` ל-REST `FlowInstance` +2. יישום מחלקה `Metrics` +3. הוספת בדיקות שילוב מקיפות +4. ביצועי benchmark +5. עדכון כל התיעוד +6. יצירת מדריך מעבר + +**תאימות לאחור**: שיטות חדשות בלבד. ללא השפעה על קוד קיים. + +### מודלים של נתונים + +#### בחירת ממשק + +```python +# Single API instance, same URL for all interfaces +api = Api(url="http://localhost:8088/") + +# Synchronous interfaces +rest_flow = api.flow().id("default") # Sync REST +socket_flow = api.socket().flow("default") # Sync WebSocket +bulk = api.bulk() # Sync bulk operations +metrics = api.metrics() # Sync metrics + +# Asynchronous interfaces +async_rest_flow = api.async_flow().id("default") # Async REST +async_socket_flow = api.async_socket().flow("default") # Async WebSocket +async_bulk = api.async_bulk() # Async bulk operations +async_metrics = api.async_metrics() # Async metrics +``` + +#### סוגי תגובות סטרימינג + +**סטרימינג של סוכן:** + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - non-streaming (same signature) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - streaming (new) +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentThought): + print(f"Thinking: {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"Observed: {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"Answer: {chunk.content}") + if chunk.end_of_dialog: + break +``` + +**סטרימינג RAG**: + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.graph_rag(question="What is Python?", user="user123", collection="default") +print(response) + +# WebSocket interface - streaming (new) +socket_flow = api.socket().flow("default") +for chunk in socket_flow.graph_rag( + question="What is Python?", + user="user123", + collection="default", + streaming=True +): + print(chunk.content, end="", flush=True) + if chunk.end_of_stream: + break +``` + +**פעולות מרובות (סינכרוניות):** + +```python +api = Api(url="http://localhost:8088/") + +# Bulk import triples +def triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Bulk export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +**פעולות מרובות (אסינכרוניות):** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async bulk import triples + async def async_triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + + # Async bulk export triples + async for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") + +asyncio.run(main()) +``` + +**דוגמה ל-REST אסינכרוני:** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST flow operations + flow = api.async_flow().id("default") + response = await flow.agent(question="What is ML?", user="user123") + print(response["response"]) + +asyncio.run(main()) +``` + +**דוגמה לסטרימינג WebSocket אסינכרוני:** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async WebSocket streaming + socket = api.async_socket() + flow = socket.flow("default") + + async for chunk in flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) + if chunk.end_of_dialog: + break + +asyncio.run(main()) +``` + +### ממשקי API + +#### ממשקי API חדשים + +1. **מחלקה ראשית של ממשק API**: + **סינכרוני**: + `Api.socket()` - קבלת לקוח WebSocket סינכרוני + `Api.bulk()` - קבלת לקוח פעולות אצווה סינכרוני + `Api.metrics()` - קבלת לקוח מדדים סינכרוני + `Api.close()` - סגירת כל החיבורים הסינכרוניים + תמיכה במנהל הקשר (context manager) (`__enter__`, `__exit__`) + **אסינכרוני**: + `Api.async_flow()` - קבלת לקוח REST flow אסינכרוני + `Api.async_socket()` - קבלת לקוח WebSocket אסינכרוני + `Api.async_bulk()` - קבלת לקוח פעולות אצווה אסינכרוני + `Api.async_metrics()` - קבלת לקוח מדדים אסינכרוני + `Api.aclose()` - סגירת כל החיבורים האסינכרוניים + תמיכה במנהל הקשר אסינכרוני (`__aenter__`, `__aexit__`) + +2. **לקוח WebSocket סינכרוני**: + `SocketClient.flow(flow_id)` - קבלת מופע WebSocket + `SocketFlowInstance.agent(..., streaming: bool = False)` - סוכן עם סטרימינג אופציונלי + `SocketFlowInstance.text_completion(..., streaming: bool = False)` - השלמת טקסט עם סטרימינג אופציונלי + `SocketFlowInstance.graph_rag(..., streaming: bool = False)` - Graph RAG עם סטרימינג אופציונלי + `SocketFlowInstance.document_rag(..., streaming: bool = False)` - Document RAG עם סטרימינג אופציונלי + `SocketFlowInstance.prompt(..., streaming: bool = False)` - הנחיה (prompt) עם סטרימינג אופציונלי + `SocketFlowInstance.graph_embeddings_query()` - שאילתת הטמעות גרף + כל שיטות FlowInstance אחרות עם חתימות זהות + +3. **לקוח WebSocket אסינכרוני**: + `AsyncSocketClient.flow(flow_id)` - קבלת מופע WebSocket אסינכרוני + `AsyncSocketFlowInstance.agent(..., streaming: bool = False)` - סוכן אסינכרוני עם סטרימינג אופציונלי + `AsyncSocketFlowInstance.text_completion(..., streaming: bool = False)` - השלמת טקסט אסינכרונית עם סטרימינג אופציונלי + `AsyncSocketFlowInstance.graph_rag(..., streaming: bool = False)` - Graph RAG אסינכרוני עם סטרימינג אופציונלי + `AsyncSocketFlowInstance.document_rag(..., streaming: bool = False)` - Document RAG אסינכרוני עם סטרימינג אופציונלי + `AsyncSocketFlowInstance.prompt(..., streaming: bool = False)` - הנחיה (prompt) אסינכרונית עם סטרימינג אופציונלי + `AsyncSocketFlowInstance.graph_embeddings_query()` - שאילתת הטמעות גרף אסינכרונית + כל שיטות FlowInstance אחרות כגרסאות אסינכרוניות + +4. **לקוח פעולות אצווה סינכרוני**: + `BulkClient.import_triples(flow, triples)` - ייבוא אצווה של משולשות + `BulkClient.export_triples(flow)` - ייצוא אצווה של משולשות + `BulkClient.import_graph_embeddings(flow, embeddings)` - ייבוא אצווה של הטמעות גרף + `BulkClient.export_graph_embeddings(flow)` - ייצוא אצווה של הטמעות גרף + `BulkClient.import_document_embeddings(flow, embeddings)` - ייבוא אצווה של הטמעות מסמכים + `BulkClient.export_document_embeddings(flow)` - ייצוא אצווה של הטמעות מסמכים + `BulkClient.import_entity_contexts(flow, contexts)` - ייבוא אצווה של הקשרים של ישויות + `BulkClient.export_entity_contexts(flow)` - ייצוא אצווה של הקשרים של ישויות + `BulkClient.import_objects(flow, objects)` - ייבוא אצווה של אובייקטים + +5. **לקוח פעולות אצווה אסינכרוני**: + `AsyncBulkClient.import_triples(flow, triples)` - ייבוא אצווה אסינכרוני של משולשות + `AsyncBulkClient.export_triples(flow)` - ייצוא אצווה אסינכרוני של משולשות + `AsyncBulkClient.import_graph_embeddings(flow, embeddings)` - ייבוא אצווה אסינכרוני של הטמעות גרף + `AsyncBulkClient.export_graph_embeddings(flow)` - ייצוא אצווה אסינכרוני של הטמעות גרף + `AsyncBulkClient.import_document_embeddings(flow, embeddings)` - ייבוא אצווה אסינכרוני של הטמעות מסמכים + `AsyncBulkClient.export_document_embeddings(flow)` - ייצוא אצווה אסינכרוני של הטמעות מסמכים + `AsyncBulkClient.import_entity_contexts(flow, contexts)` - ייבוא אצווה אסינכרוני של הקשרים של ישויות + `AsyncBulkClient.export_entity_contexts(flow)` - ייצוא אצווה אסינכרוני של הקשרים של ישויות + `AsyncBulkClient.import_objects(flow, objects)` - ייבוא אצווה אסינכרוני של אובייקטים + +6. **לקוח REST Flow אסינכרוני**: + `AsyncFlow.list()` - רשימת כל ה-flows (אסינכרוני) + `AsyncFlow.get(id)` - קבלת הגדרת flow (אסינכרוני) + `AsyncFlow.start(...)` - התחלת flow (אסינכרוני) + `AsyncFlow.stop(id)` - עצירת flow (אסינכרוני) + `AsyncFlow.id(flow_id)` - קבלת מופע flow (אסינכרוני) + `AsyncFlowInstance.agent(...)` - הרצת סוכן (אסינכרוני) + `AsyncFlowInstance.text_completion(...)` - השלמת טקסט (אסינכרונית) + `AsyncFlowInstance.graph_rag(...)` - Graph RAG (אסינכרוני) + כל שיטות FlowInstance אחרות כגרסאות אסינכרוניות + +7. **לקוחות מדדים**: + `Metrics.get()` - מדדי Prometheus סינכרוניים + `AsyncMetrics.get()` - מדדי Prometheus אסינכרוניים + +8. **שיפור ממשק API של REST Flow**: + `FlowInstance.graph_embeddings_query()` - שאילתת הטמעות גרף (תאימות תכונות סינכרונית) + `AsyncFlowInstance.graph_embeddings_query()` - שאילתת הטמעות גרף (תאימות תכונות אסינכרונית) + +#### ממשקי API שעברו שינוי + +1. **מבנה (Constructor)** (שיפור קל): + ```python + Api(url: str, timeout: int = 60, token: Optional[str] = None) + ``` + הוסף פרמטר `token` (אופציונלי, לצורך אימות) + אם `None` (ברירת מחדל): לא נעשה שימוש באימות + אם צוין: משמש כטוקן bearer עבור REST (`Authorization: Bearer `), כפרמטר שאילתה עבור WebSocket (`?token=`) + לא בוצעו שינויים אחרים - תואם לאחור לחלוטין + +2. **ללא שינויים שמשנים את הפעולה**: + כל שיטות ה-API של REST הקיימות לא שונו + כל החתימות הקיימות נשמרו + כל סוגי ההחזרה הקיימים נשמרו + +### פרטי יישום + +#### טיפול בשגיאות + +**שגיאות חיבור WebSocket**: +```python +try: + api = Api(url="http://localhost:8088/") + socket = api.socket() + socket_flow = socket.flow("default") + response = socket_flow.agent(question="...", user="user123") +except ConnectionError as e: + print(f"WebSocket connection failed: {e}") + print("Hint: Ensure Gateway is running and WebSocket endpoint is accessible") +``` + +**מעבר חלק:** +```python +api = Api(url="http://localhost:8088/") + +try: + # Try WebSocket streaming first + socket_flow = api.socket().flow("default") + for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk.content) +except ConnectionError: + # Fall back to REST non-streaming + print("WebSocket unavailable, falling back to REST") + rest_flow = api.flow().id("default") + response = rest_flow.agent(question="...", user="...") + print(response["response"]) +``` + +**שגיאות סטרימינג חלקיות**: +```python +api = Api(url="http://localhost:8088/") +socket_flow = api.socket().flow("default") + +accumulated = [] +try: + for chunk in socket_flow.graph_rag(question="...", streaming=True): + accumulated.append(chunk.content) + if chunk.error: + print(f"Error occurred: {chunk.error}") + print(f"Partial response: {''.join(accumulated)}") + break +except Exception as e: + print(f"Streaming error: {e}") + print(f"Partial response: {''.join(accumulated)}") +``` + +#### ניהול משאבים + +**תמיכה במנהל הקשר (Context Manager):** +```python +# Automatic cleanup +with Api(url="http://localhost:8088/") as api: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +# All connections automatically closed + +# Manual cleanup +api = Api(url="http://localhost:8088/") +try: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +finally: + api.close() # Explicitly close all connections (WebSocket, bulk, etc.) +``` + +#### תִּקְשׁוּר וּמְקַרְבֵּי מִקְבֵּל + +**בְּטִיחוּת מִתְקַרְבֵּי מִקְבֵּל**: +כל מופע של `Api` שומר על חיבור משלו. +תעבורת WebSocket משתמשת במנעולים עבור ריבוב בקשות בטוח לחוטים. +מספר חוטים יכולים לשתף מופע של `Api` בצורה בטוחה. +איטרטורים של סטרימינג אינם בטוחים לחוטים (יש לצרוך מהחוט היחיד). + +**תמיכה אסינכרונית** (שיקול עתידי): +```python +# Phase 2 enhancement (not in initial scope) +import asyncio + +async def main(): + api = await AsyncApi(url="ws://localhost:8088/") + flow = api.flow().id("default") + + async for chunk in flow.agent(question="...", streaming=True): + print(chunk.content) + + await api.close() + +asyncio.run(main()) +``` + +## שיקולי אבטחה + +### אימות + +**פרמטר טוקן**: +```python +# No authentication (default) +api = Api(url="http://localhost:8088/") + +# With authentication +api = Api(url="http://localhost:8088/", token="mytoken") +``` + +**שינוע REST**: +טוקן נושא דרך כותרת `Authorization` +מיושם אוטומטית על כל בקשות REST +פורמט: `Authorization: Bearer ` + +**שינוע WebSocket**: +טוקן דרך פרמטר שאילתה המצורף לכתובת ה-WebSocket +מיושם אוטומטית במהלך יצירת החיבור +פורמט: `ws://localhost:8088/api/v1/socket?token=` + +**יישום**: +```python +class SocketClient: + def _connect(self) -> WebSocket: + # Construct WebSocket URL with optional token + ws_url = f"{self.url}/api/v1/socket" + if self.token: + ws_url = f"{ws_url}?token={self.token}" + # Connect to WebSocket + return websocket.connect(ws_url) +``` + +**דוגמה:** +```python +# REST with auth +api = Api(url="http://localhost:8088/", token="mytoken") +flow = api.flow().id("default") +# All REST calls include: Authorization: Bearer mytoken + +# WebSocket with auth +socket = api.socket() +# Connects to: ws://localhost:8088/api/v1/socket?token=mytoken +``` + +### תקשורת מאובטחת + +תמיכה הן בפרוטוקול WS (WebSocket) והן בפרוטוקול WSS (WebSocket Secure). +אימות תעודות TLS עבור חיבורי WSS. +אפשרות לביטול אימות תעודות לצורך פיתוח (עם אזהרה). + +### אימות קלט + +אימות סכימות כתובות URL (http, https, ws, wss). +אימות ערכי פרמטרים של העברת נתונים. +אימות שילובים של פרמטרים של העברה רציפה. +אימות סוגי נתונים לייבוא בכמות גדולה. + +## שיקולי ביצועים + +### שיפורי השהייה + +**פעולות LLM רציפות (Streaming)**: +**זמן עד לקבלת הטוקן הראשון**: ~500ms (לעומת ~30 שניות ללא העברה רציפה). +**שיפור**: ביצועים תפיסיים מהירים פי 60. +**מתאים ל**: סוכן, Graph RAG, Document RAG, השלמת טקסט, הנחיה. + +**חיבורים קבועים**: +**תקורה של חיבור**: מבוטלת עבור בקשות עוקבות. +**הדחיסה הראשונית של WebSocket**: עלות חד-פעמית (~100ms). +**מתאים ל**: כל הפעולות בעת שימוש בפרוטוקול WebSocket. + +### שיפורי תפוקה + +**פעולות בכמות גדולה**: +**ייבוא משולשות**: ~10,000 משולשות/שנייה (לעומת ~100/שנייה עם REST עבור כל פריט). +**ייבוא הטמעות (Embeddings)**: ~5,000 הטמעות/שנייה (לעומת ~50/שנייה עם REST עבור כל פריט). +**שיפור**: תפוקה גבוהה פי 100 עבור פעולות בכמות גדולה. + +**ריבוב בקשות (Request Multiplexing)**: +**בקשות מקבילות**: עד 15 בקשות בו-זמנית על גבי חיבור יחיד. +**שימוש חוזר בחיבור**: אין תקורה של חיבור עבור פעולות מקבילות. + +### שיקולי זיכרון + +**תגובות רציפות (Streaming)**: +שימוש קבוע בזיכרון (עיבוד מקטעים כשהם מגיעים). +אין אחסון זמני של תגובה שלמה. +מתאים לפלטים ארוכים מאוד (>1MB). + +**פעולות בכמות גדולה**: +עיבוד מבוסס איטרטור (שימוש קבוע בזיכרון). +אין טעינה של קבוצת נתונים שלמה לתוך הזיכרון. +מתאים לקבוצות נתונים עם מיליוני פריטים. + +### מדדי ביצוע (צפויים) + +| פעולה | REST (קיים) | WebSocket (העברה רציפה) | שיפור | +|-----------|----------------|----------------------|-------------| +| סוכן (זמן עד לקבלת הטוקן הראשון) | 30 שניות | 0.5 שניות | 60x | +| Graph RAG (זמן עד לקבלת הטוקן הראשון) | 25 שניות | 0.5 שניות | 50x | +| ייבוא 10K משולשות | 100 שניות | 1 שניה | 100x | +| ייבוא 1M משולשות | 10,000 שניות (2.7 שעות) | 100 שניות (1.6 דקות) | 100x | +| 10 בקשות קטנות במקביל | 5 שניות (רציף) | 0.5 שניות (מקביל) | 10x | + +## אסטרטגיית בדיקות + +### בדיקות יחידה + +**שכבת התעבורה** (`test_transport.py`): +בדיקת בקשה/תגובה של פרוטוקול REST +בדיקת חיבור פרוטוקול WebSocket +בדיקת חיבור מחדש של פרוטוקול WebSocket +בדיקת ריבוי בקשות +בדיקת ניתוח תגובה בסטרימינג +שרת WebSocket מדמה לבדיקות דטרמיניסטיות + +**שיטות API** (`test_flow.py`, `test_library.py`, וכו'): +בדיקת שיטות חדשות עם שכבת תעבורה מדמה +בדיקת טיפול בפרמטרים בסטרימינג +בדיקת איטרטורים לפעולות אצווה +בדיקת טיפול בשגיאות + +**טיפוסים** (`test_types.py`): +בדיקת טיפוסי סטרימינג חדשים +בדיקת סריאליזציה/דה-סריאליזציה של טיפוסים + +### בדיקות אינטגרציה + +**REST מקצה לקצה** (`test_integration_rest.py`): +בדיקת כל הפעולות מול שער אמיתי (מצב REST) +אימות תאימות לאחור +בדיקת תנאי שגיאה + +**WebSocket מקצה לקצה** (`test_integration_websocket.py`): +בדיקת כל הפעולות מול שער אמיתי (מצב WebSocket) +בדיקת פעולות סטרימינג +בדיקת פעולות אצווה +בדיקת בקשות מקבילות +בדיקת התאוששות חיבור + +**שירותי סטרימינג** (`test_streaming_integration.py`): +בדיקת סטרימינג של סוכן (מחשבות, תצפיות, תשובות) +בדיקת סטרימינג של RAG (חלקים מצטברים) +בדיקת סטרימינג של השלמת טקסט (טוקן אחר טוקן) +בדיקת סטרימינג של הנחיה +בדיקת טיפול בשגיאות במהלך סטרימינג + +**פעולות אצווה** (`test_bulk_integration.py`): +בדיקת ייבוא/ייצוא אצווה של טריפלטים (1K, 10K, 100K פריטים) +בדיקת ייבוא/ייצוא אצווה של הטמעות +בדיקת שימוש בזיכרון במהלך פעולות אצווה +בדיקת מעקב אחר התקדמות + +### בדיקות ביצועים + +**מדדי השהייה** (`test_performance_latency.py`): +מדידת זמן עד לטוקן הראשון (סטרימינג לעומת לא סטרימינג) +מדידת תקורה של חיבור (REST לעומת WebSocket) +השוואה למדדים צפויים + +**מדדי תפוקה** (`test_performance_throughput.py`): +מדידת תפוקת ייבוא אצווה +מדידת יעילות ריבוי בקשות +השוואה למדדים צפויים + +### בדיקות תאימות + +**תאימות לאחור** (`test_backward_compatibility.py`): +הרצת סט בדיקות קיים מול API שעבר שינוי מבני +אימות היעדר שינויים שוברים +בדיקת נתיב מעבר עבור תבניות נפוצות + +## תוכנית מעבר + +### שלב 1: מעבר שקוף (ברירת מחדל) + +**לא נדרשים שינויי קוד**. קוד קיים ממשיך לעבוד: + +```python +# Existing code works unchanged +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") +response = flow.agent(question="What is ML?", user="user123") +``` + +### שלב 2: הפעלת סטרימינג (פשוט) + +**השתמשו בממשק `api.socket()`** כדי להפעיל סטרימינג: + +```python +# Before: Non-streaming REST +api = Api(url="http://localhost:8088/") +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# After: Streaming WebSocket (same parameters!) +api = Api(url="http://localhost:8088/") # Same URL +socket_flow = api.socket().flow("default") + +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) +``` + +**נקודות עיקריות:** +אותה כתובת URL עבור REST ו-WebSocket +אותם חתימות מתודות (מעבר קל) +פשוט הוסיפו את `.socket()` ו-`streaming=True` + +### שלב 3: פעולות בכמות גדולה (יכולת חדשה) + +**השתמשו בממשק `api.bulk()`** עבור מערכי נתונים גדולים: + +```python +# Before: Inefficient per-item operations +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") + +for triple in my_large_triple_list: + # Slow per-item operations + # (no direct bulk insert in REST API) + pass + +# After: Efficient bulk loading +api = Api(url="http://localhost:8088/") # Same URL +bulk = api.bulk() + +# This is fast (10,000 triples/second) +bulk.import_triples(flow="default", triples=iter(my_large_triple_list)) +``` + +### עדכוני תיעוד + +1. **README.md**: הוספת דוגמאות סטרימינג ו-WebSocket +2. **הפניה ל-API**: תיעוד של כל השיטות והפרמטרים החדשים +3. **מדריך מעבר**: מדריך שלב אחר שלב להפעלת סטרימינג +4. **דוגמאות**: הוספת סקריפטים לדוגמה לתבניות נפוצות +5. **מדריך ביצועים**: תיעוד של שיפורי ביצועים צפויים + +### מדיניות הפסקה + +**ללא הפסקות**. כל ה-APIs הקיימים נתמכים. זוהי שיפור משמעותי בלבד. + +## ציר זמן + +### שבוע 1: יסודות +שכבת הפשטה של העברת נתונים +שיפור קוד REST קיים +בדיקות יחידה לשכבת העברת הנתונים +אימות תאימות לאחור + +### שבוע 2: העברת WebSocket +יישום העברת WebSocket +ניהול חיבורים וחיבור מחדש +ריבוב בקשות +בדיקות יחידה ושילוב + +### שבוע 3: תמיכה בסטרימינג +הוספת פרמטר סטרימינג לשיטות LLM +יישום ניתוח תגובות סטרימינג +הוספת סוגי חלקי סטרימינג +בדיקות שילוב סטרימינג + +### שבוע 4: פעולות מרובות +הוספת שיטות ייבוא/ייצוא מרובות +יישום פעולות מבוססות איטרטור +בדיקות ביצועים +בדיקות שילוב לפעולות מרובות + +### שבוע 5: התאמה ותיעוד +הוספת שאילתת הטמעות גרף +הוספת API למדדים +תיעוד מקיף +מדריך מעבר +גרסה מועמדת + +### שבוע 6: שחרור +בדיקות שילוב סופיות +מדידת ביצועים +תיעוד לשחרור +הודעה לקהילה + +**משך כולל**: 6 שבועות + +## שאלות פתוחות + +### שאלות עיצוב API + +1. **תמיכה אסינכרונית**: ✅ **נפתר** - תמיכה אסינכרונית מלאה כלולה בשחרור הראשוני + לכל הממשקים יש גרסאות אסינכרוניות: `async_flow()`, `async_socket()`, `async_bulk()`, `async_metrics()` + מספק סימטריה מלאה בין ממשקי סנכרון ואסינכרון + חיוני למסגרות אסינכרוניות מודרניות (FastAPI, aiohttp) + +2. **מעקב אחר התקדמות**: האם פעולות מרובות צריכות לתמוך בפונקציות החזרה של התקדמות? + ```python + def progress_callback(processed: int, total: Optional[int]): + print(f"Processed {processed} items") + + bulk.import_triples(flow="default", triples=triples, on_progress=progress_callback) + ``` + **המלצה**: להוסיף בשלב 2. לא קריטי לשחרור הראשוני. + +3. **זמן המתנה (Timeout) לסטרימינג**: איך עלינו לטפל בזמני המתנה עבור פעולות סטרימינג? + **המלצה**: להשתמש באותו זמן המתנה כמו בפעולות שאינן סטרימינג, אך לאפס אותו בכל פעם שמתקבל חלק. + +4. **ביצוע אחסון של חלקים (Chunk Buffering)**: האם עלינו לאחסן חלקים או להחזיר מידע מיד? + **המלצה**: להחזיר מיד כדי להשיג השהייה נמוכה ביותר. + +5. **שירותים גלובליים דרך WebSocket**: האם `api.socket()` צריך לתמוך בשירותים גלובליים (ספרייה, ידע, אוסף, תצורה) או רק בשירותים המוגבלים ל-flow? + **המלצה**: להתחיל רק עם שירותים המוגבלים ל-flow (שם הסטרימינג חשוב). להוסיף שירותים גלובליים במידת הצורך בשלב 2. + +### שאלות יישום + +1. **ספריית WebSocket**: האם עלינו להשתמש ב-`websockets`, `websocket-client`, או `aiohttp`? + **המלצה**: `websockets` (אסינכרוני, בשל, מתוחזק היטב). לעטוף בממשק סינכרוני באמצעות `asyncio.run()`. + +2. **ניהול חיבורים (Connection Pooling)**: האם עלינו לתמוך במספר מופעים מקבילים של `Api` המשתפים בריכת חיבורים? + **המלצה**: לדחות לשלב 2. לכל מופע של `Api` יהיו חיבורים משלו בתחילה. + +3. **שימוש חוזר בחיבורים**: האם `SocketClient` ו-`BulkClient` צריכים לשתף את אותו חיבור WebSocket, או להשתמש בחיבורים נפרדים? + **המלצה**: חיבורים נפרדים. יישום פשוט יותר, הפרדה ברורה יותר של נושאים. + +4. **חיבור עצלני לעומת חיבור מוקדם**: האם החיבור WebSocket צריך להיות מוקם ב-`api.socket()` או בבקשה הראשונה? + **המלצה**: עצלני (בבקשה הראשונה). נמנע מעלות נוספת של חיבור אם המשתמש משתמש רק בשיטות REST. + +### שאלות בדיקה + +1. **שער מדמה (Mock Gateway)**: האם עלינו ליצור שער מדמה קל משקל לבדיקות, או לבדוק מול שער אמיתי? + **המלצה**: שניהם. להשתמש במדמים לבדיקות יחידה, ושער אמיתי לבדיקות אינטגרציה. + +2. **בדיקות רגרסיה לביצועים**: האם עלינו להוסיף בדיקות רגרסיה אוטומטיות לביצועים ל-CI? + **המלצה**: כן, אך עם ספים נדיבים כדי להתחשב בשונות בסביבת ה-CI. + +## הפניות + +### מפרטי טכנולוגיה קשורים +`docs/tech-specs/streaming-llm-responses.md` - יישום סטרימינג בשער +`docs/tech-specs/rag-streaming-support.md` - תמיכה בסטרימינג של RAG + +### קבצי יישום +`trustgraph-base/trustgraph/api/` - קוד מקור של API בפייתון +`trustgraph-flow/trustgraph/gateway/` - קוד מקור של השער +`trustgraph-flow/trustgraph/gateway/dispatch/mux.py` - יישום התייחסות של מולטיפלקסר WebSocket + +### תיעוד +`docs/apiSpecification.md` - הפניה מלאה ל-API +`docs/api-status-summary.md` - סיכום סטטוס API +`README.websocket` - תיעוד פרוטוקול WebSocket +`STREAMING-IMPLEMENTATION-NOTES.txt` - הערות על יישום סטרימינג + +### ספריות חיצוניות +`websockets` - ספריית WebSocket בפייתון (https://websockets.readthedocs.io/) +`requests` - ספריית HTTP בפייתון (קיימת) diff --git a/docs/tech-specs/python-api-refactor.hi.md b/docs/tech-specs/python-api-refactor.hi.md new file mode 100644 index 00000000..1c44f1c0 --- /dev/null +++ b/docs/tech-specs/python-api-refactor.hi.md @@ -0,0 +1,1508 @@ +# पायथन एपीआई रिफैक्टर तकनीकी विनिर्देश + +## अवलोकन + +यह विनिर्देश ट्रस्टग्राफ पायथन एपीआई क्लाइंट लाइब्रेरी का एक व्यापक रिफैक्टर है, जिसका उद्देश्य एपीआई गेटवे के साथ सुविधा समानता प्राप्त करना और आधुनिक रीयल-टाइम संचार पैटर्न के लिए समर्थन जोड़ना है। + +यह रिफैक्टर चार प्राथमिक उपयोग मामलों को संबोधित करता है: + +1. **स्ट्रीमिंग एलएलएम इंटरैक्शन**: एलएलएम प्रतिक्रियाओं (एजेंट, ग्राफ आरएजी, दस्तावेज़ आरएजी, टेक्स्ट कंप्लीशन, प्रॉम्प्ट) का रीयल-टाइम स्ट्रीमिंग सक्षम करें, जिसमें ~60 गुना कम विलंबता हो (पहले टोकन के लिए 500ms बनाम 30s)। +2. **बल्क डेटा ऑपरेशन**: बड़े पैमाने पर नॉलेज ग्राफ प्रबंधन के लिए ट्रिपल, ग्राफ एम्बेडिंग और दस्तावेज़ एम्बेडिंग के कुशल बल्क आयात/निर्यात का समर्थन करें। +3. **सुविधा समानता**: सुनिश्चित करें कि प्रत्येक एपीआई गेटवे एंडपॉइंट के लिए एक संबंधित पायथन एपीआई विधि है, जिसमें ग्राफ एम्बेडिंग क्वेरी शामिल है। +4. **लगातार कनेक्शन**: मल्टीप्लेक्स अनुरोधों और कम कनेक्शन ओवरहेड के लिए वेबसॉकेट-आधारित संचार को सक्षम करें। + +## लक्ष्य + +**सुविधा समानता**: प्रत्येक गेटवे एपीआई सेवा के लिए एक संबंधित पायथन एपीआई विधि है। +**स्ट्रीमिंग समर्थन**: सभी स्ट्रीमिंग-सक्षम सेवाओं (एजेंट, आरएजी, टेक्स्ट कंप्लीशन, प्रॉम्प्ट) पायथन एपीआई में स्ट्रीमिंग का समर्थन करते हैं। +**वेबसॉकेट ट्रांसपोर्ट**: लगातार कनेक्शन और मल्टीप्लेक्सिंग के लिए वैकल्पिक वेबसॉकेट ट्रांसपोर्ट लेयर जोड़ें। +**बल्क ऑपरेशन**: ट्रिपल, ग्राफ एम्बेडिंग और दस्तावेज़ एम्बेडिंग के लिए कुशल बल्क आयात/निर्यात जोड़ें। +**पूर्ण एसिंक समर्थन**: सभी इंटरफेस (REST, वेबसॉकेट, बल्क ऑपरेशन, मेट्रिक्स) के लिए पूर्ण एसिंक/अवेट कार्यान्वयन। +**पिछला संगतता**: मौजूदा कोड बिना किसी संशोधन के काम करना जारी रखता है। +**टाइप सुरक्षा**: डेटाक्लासेस और टाइप हिंट के साथ टाइप-सुरक्षित इंटरफेस बनाए रखें। +**प्रगतिशील संवर्द्धन**: स्ट्रीमिंग और एसिंक स्पष्ट इंटरफेस चयन के माध्यम से वैकल्पिक हैं। +**प्रदर्शन**: स्ट्रीमिंग ऑपरेशनों के लिए 60 गुना विलंबता में सुधार प्राप्त करें। +**आधुनिक पायथन**: अधिकतम लचीलेपन के लिए सिंक और एसिंक दोनों प्रतिमानों के लिए समर्थन। + +## पृष्ठभूमि + +### वर्तमान स्थिति + +पायथन एपीआई (`trustgraph-base/trustgraph/api/`) एक REST-ओनली क्लाइंट लाइब्रेरी है जिसमें निम्नलिखित मॉड्यूल हैं: + +`flow.py`: फ्लो प्रबंधन और फ्लो-स्कोप सेवाओं (50 विधियाँ) +`library.py`: दस्तावेज़ लाइब्रेरी ऑपरेशन (9 विधियाँ) +`knowledge.py`: केजी कोर प्रबंधन (4 विधियाँ) +`collection.py`: संग्रह मेटाडेटा (3 विधियाँ) +`config.py`: कॉन्फ़िगरेशन प्रबंधन (6 विधियाँ) +`types.py`: डेटा टाइप परिभाषाएँ (5 डेटाक्लास) + +**कुल ऑपरेशन**: 50/59 (85% कवरेज) + +### वर्तमान सीमाएँ + +**गायब ऑपरेशन**: +ग्राफ एम्बेडिंग क्वेरी (ग्राफ संस्थाओं पर सिमेंटिक खोज) +ट्रिपल, ग्राफ एम्बेडिंग, दस्तावेज़ एम्बेडिंग, एंटिटी कॉन्टेक्स्ट, ऑब्जेक्ट के लिए बल्क आयात/निर्यात +मेट्रिक्स एंडपॉइंट + +**गायब क्षमताएँ**: +एलएलएम सेवाओं के लिए स्ट्रीमिंग समर्थन +वेबसॉकेट ट्रांसपोर्ट +मल्टीप्लेक्स समवर्ती अनुरोध +लगातार कनेक्शन + +**प्रदर्शन संबंधी समस्याएँ**: +एलएलएम इंटरैक्शन के लिए उच्च विलंबता (~30s समय-से-पहला-टोकन) +अक्षम बल्क डेटा ट्रांसफर (प्रति आइटम REST अनुरोध) +कई क्रमिक ऑपरेशनों के लिए कनेक्शन ओवरहेड + +**उपयोगकर्ता अनुभव संबंधी समस्याएँ**: +एलएलएम पीढ़ी के दौरान कोई रीयल-टाइम प्रतिक्रिया नहीं +लंबे समय तक चलने वाले एलएलएम ऑपरेशनों को रद्द नहीं किया जा सकता है +बल्क ऑपरेशनों के लिए खराब स्केलेबिलिटी + +### प्रभाव + +नवंबर 2024 में गेटवे एपीआई में स्ट्रीमिंग संवर्द्धन ने एलएलएम इंटरैक्शन के लिए 60 गुना विलंबता में सुधार (पहले टोकन के लिए 500ms बनाम 30s) प्रदान किया, लेकिन पायथन एपीआई उपयोगकर्ता इस क्षमता का लाभ नहीं उठा सकते हैं। इससे पायथन और गैर-पायथन उपयोगकर्ताओं के बीच एक महत्वपूर्ण अनुभव अंतर पैदा होता है। + +## तकनीकी डिजाइन + +### वास्तुकला + +रिफैक्टर किए गए पायथन एपीआई विभिन्न संचार पैटर्न के लिए अलग-अलग ऑब्जेक्ट के साथ एक **मॉड्यूलर इंटरफेस दृष्टिकोण** का उपयोग करता है। सभी इंटरफेस सिंक्रोनस और एसिंक्रोनस दोनों रूपों में उपलब्ध हैं: + +1. **REST इंटरफेस** (मौजूदा, संवर्धित) + **सिंक**: `api.flow()`, `api.library()`, `api.knowledge()`, `api.collection()`, `api.config()` + **एसिंक**: `api.async_flow()` + सिंक्रोनस/एसिंक्रोनस अनुरोध/प्रतिक्रिया + सरल कनेक्शन मॉडल + पिछड़े संगतता के लिए डिफ़ॉल्ट + +2. **वेबसॉकेट इंटरफेस** (नया) + **सिंक**: `api.socket()` + **एसिंक**: `api.async_socket()` + लगातार कनेक्शन + मल्टीप्लेक्स अनुरोध + स्ट्रीमिंग समर्थन + जहां कार्यक्षमता ओवरलैप होती है, वहां REST के समान विधि हस्ताक्षर + +3. **बल्क ऑपरेशन इंटरफेस** (नया) + **सिंक**: `api.bulk()` + **एसिंक**: `api.async_bulk()` + दक्षता के लिए वेबसॉकेट-आधारित + आयात/निर्यात के लिए Iterator/AsyncIterator-आधारित + बड़े डेटासेट को संभालता है + +4. **मेट्रिक्स इंटरफेस** (नया) + **सिंक**: `api.metrics()` + **एसिंक**: `api.async_metrics()` + प्रोमेथियस मेट्रिक्स एक्सेस + +```python +import asyncio + +# Synchronous interfaces +api = Api(url="http://localhost:8088/") + +# REST (existing, unchanged) +flow = api.flow().id("default") +response = flow.agent(question="...", user="...") + +# WebSocket (new) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="...", user="...") +for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk) + +# Bulk operations (new) +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Asynchronous interfaces +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST (new) + flow = api.async_flow().id("default") + response = await flow.agent(question="...", user="...") + + # Async WebSocket (new) + socket_flow = api.async_socket().flow("default") + async for chunk in socket_flow.agent(question="...", streaming=True): + print(chunk) + + # Async bulk operations (new) + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + +asyncio.run(main()) +``` + +**मुख्य डिज़ाइन सिद्धांत:** +**सभी इंटरफेस के लिए समान URL:** `Api(url="http://localhost:8088/")` सभी के लिए काम करता है। +**सिंक/एसिंक्रोनस समरूपता:** प्रत्येक इंटरफेस में सिंक और एसिंक्रोनस दोनों संस्करण होते हैं, जिनमें समान मेथड सिग्नेचर होते हैं। +**समान सिग्नेचर:** जहां कार्यक्षमता ओवरलैप होती है, REST और WebSocket, सिंक और एसिंक्रोनस के बीच मेथड सिग्नेचर समान होते हैं। +**प्रगतिशील संवर्द्धन:** आवश्यकताओं के आधार पर इंटरफेस चुनें (सरल कार्यों के लिए REST, स्ट्रीमिंग के लिए WebSocket, बड़े डेटासेट के लिए बल्क, आधुनिक फ्रेमवर्क के लिए एसिंक्रोनस)। +**स्पष्ट इरादा:** `api.socket()` WebSocket को दर्शाता है, `api.async_socket()` एसिंक्रोनस WebSocket को दर्शाता है। +**पिछड़े संगत:** मौजूदा कोड अपरिवर्तित रहता है। + +### घटक + +#### 1. कोर एपीआई क्लास (संशोधित) + +मॉड्यूल: `trustgraph-base/trustgraph/api/api.py` + +**संवर्धित एपीआई क्लास:** + +```python +class Api: + def __init__(self, url: str, timeout: int = 60, token: Optional[str] = None): + self.url = url + self.timeout = timeout + self.token = token # Optional bearer token for REST, query param for WebSocket + self._socket_client = None + self._bulk_client = None + self._async_flow = None + self._async_socket_client = None + self._async_bulk_client = None + + # Existing synchronous methods (unchanged) + def flow(self) -> Flow: + """Synchronous REST-based flow interface""" + pass + + def library(self) -> Library: + """Synchronous REST-based library interface""" + pass + + def knowledge(self) -> Knowledge: + """Synchronous REST-based knowledge interface""" + pass + + def collection(self) -> Collection: + """Synchronous REST-based collection interface""" + pass + + def config(self) -> Config: + """Synchronous REST-based config interface""" + pass + + # New synchronous methods + def socket(self) -> SocketClient: + """Synchronous WebSocket-based interface for streaming operations""" + if self._socket_client is None: + self._socket_client = SocketClient(self.url, self.timeout, self.token) + return self._socket_client + + def bulk(self) -> BulkClient: + """Synchronous bulk operations interface for import/export""" + if self._bulk_client is None: + self._bulk_client = BulkClient(self.url, self.timeout, self.token) + return self._bulk_client + + def metrics(self) -> Metrics: + """Synchronous metrics interface""" + return Metrics(self.url, self.timeout, self.token) + + # New asynchronous methods + def async_flow(self) -> AsyncFlow: + """Asynchronous REST-based flow interface""" + if self._async_flow is None: + self._async_flow = AsyncFlow(self.url, self.timeout, self.token) + return self._async_flow + + def async_socket(self) -> AsyncSocketClient: + """Asynchronous WebSocket-based interface for streaming operations""" + if self._async_socket_client is None: + self._async_socket_client = AsyncSocketClient(self.url, self.timeout, self.token) + return self._async_socket_client + + def async_bulk(self) -> AsyncBulkClient: + """Asynchronous bulk operations interface for import/export""" + if self._async_bulk_client is None: + self._async_bulk_client = AsyncBulkClient(self.url, self.timeout, self.token) + return self._async_bulk_client + + def async_metrics(self) -> AsyncMetrics: + """Asynchronous metrics interface""" + return AsyncMetrics(self.url, self.timeout, self.token) + + # Resource management + def close(self) -> None: + """Close all synchronous connections""" + if self._socket_client: + self._socket_client.close() + if self._bulk_client: + self._bulk_client.close() + + async def aclose(self) -> None: + """Close all asynchronous connections""" + if self._async_socket_client: + await self._async_socket_client.aclose() + if self._async_bulk_client: + await self._async_bulk_client.aclose() + if self._async_flow: + await self._async_flow.aclose() + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + async def __aenter__(self): + return self + + async def __aexit__(self, *args): + await self.aclose() +``` + +#### 2. सिंक्रोनस वेबसॉकेट क्लाइंट + +मॉड्यूल: `trustgraph-base/trustgraph/api/socket_client.py` (नया) + +**SocketClient क्लास:** + +```python +class SocketClient: + """Synchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> SocketFlowInstance: + """Get flow instance for WebSocket operations""" + return SocketFlowInstance(self, flow_id) + + def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Uses asyncio.run() internally to wrap async websockets library + pass + + def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + # Synchronous wrapper around async WebSocket calls + pass + + def close(self) -> None: + """Close WebSocket connection""" + pass + +class SocketFlowInstance: + """Synchronous WebSocket flow instance with same interface as REST FlowInstance""" + def __init__(self, client: SocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance + def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, Iterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**मुख्य विशेषताएं:** +आलसी कनेक्शन (केवल पहले अनुरोध भेजे जाने पर कनेक्ट होता है) +अनुरोध मल्टीप्लेक्सिंग (एक साथ 15 तक) +डिस्कनेक्ट होने पर स्वचालित पुनः कनेक्शन +स्ट्रीमिंग प्रतिक्रिया पार्सिंग +थ्रेड-सुरक्षित संचालन +एसिंक्रोनस वेबसॉकेट लाइब्रेरी के चारों ओर सिंक्रोनस रैपर + +#### 3. एसिंक्रोनस वेबसॉकेट क्लाइंट + +मॉड्यूल: `trustgraph-base/trustgraph/api/async_socket_client.py` (नया) + +**AsyncSocketClient क्लास:** + +```python +class AsyncSocketClient: + """Asynchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> AsyncSocketFlowInstance: + """Get async flow instance for WebSocket operations""" + return AsyncSocketFlowInstance(self, flow_id) + + async def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Native async websockets library + pass + + async def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + pass + + async def aclose(self) -> None: + """Close WebSocket connection""" + pass + +class AsyncSocketFlowInstance: + """Asynchronous WebSocket flow instance""" + def __init__(self, client: AsyncSocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance (but async) + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, AsyncIterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**मुख्य विशेषताएं:** +मूल एसिंक्रोनस/अवेट समर्थन +एसिंक्रोनस अनुप्रयोगों के लिए कुशल (फास्टएपीआई, एआईओएचटीटीपी) +कोई थ्रेड अवरोधन नहीं +सिंक्रोनस संस्करण के समान इंटरफ़ेस +स्ट्रीमिंग के लिए AsyncIterator + +#### 4. सिंक्रोनस बल्क ऑपरेशंस क्लाइंट + +मॉड्यूल: `trustgraph-base/trustgraph/api/bulk_client.py` (नया) + +**BulkClient क्लास:** + +```python +class BulkClient: + """Synchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + def import_triples( + self, + flow: str, + triples: Iterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + def export_triples( + self, + flow: str, + **kwargs + ) -> Iterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + def import_graph_embeddings( + self, + flow: str, + embeddings: Iterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> Iterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + def close(self) -> None: + """Close connections""" + pass +``` + +**मुख्य विशेषताएं:** +निरंतर मेमोरी उपयोग के लिए इटरेटर-आधारित। +प्रत्येक ऑपरेशन के लिए समर्पित वेबसॉकेट कनेक्शन। +प्रगति ट्रैकिंग (वैकल्पिक कॉलबैक)। +आंशिक सफलता रिपोर्टिंग के साथ त्रुटि प्रबंधन। + +#### 5. एसिंक्रोनस बल्क ऑपरेशंस क्लाइंट + +मॉड्यूल: `trustgraph-base/trustgraph/api/async_bulk_client.py` (नया) + +**AsyncBulkClient क्लास:** + +```python +class AsyncBulkClient: + """Asynchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + async def import_triples( + self, + flow: str, + triples: AsyncIterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + async def export_triples( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + async def import_graph_embeddings( + self, + flow: str, + embeddings: AsyncIterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + async def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + async def aclose(self) -> None: + """Close connections""" + pass +``` + +**मुख्य विशेषताएं:** +निरंतर मेमोरी उपयोग के लिए AsyncIterator-आधारित। +एसिंक्रोनस अनुप्रयोगों के लिए कुशल। +मूल एसिंक्रोनस/अवेट समर्थन। +सिंक्रोनस संस्करण के समान इंटरफ़ेस। + +#### 6. REST फ्लो एपीआई (सिंक्रोनस - अपरिवर्तित) + +मॉड्यूल: `trustgraph-base/trustgraph/api/flow.py` + +REST फ्लो एपीआई पिछली अनुकूलता के लिए **पूरी तरह से अपरिवर्तित** रहता है। सभी मौजूदा विधियां काम करना जारी रखती हैं: + +`Flow.list()`, `Flow.start()`, `Flow.stop()`, आदि। +`FlowInstance.agent()`, `FlowInstance.text_completion()`, `FlowInstance.graph_rag()`, आदि। +सभी मौजूदा हस्ताक्षर और रिटर्न प्रकार संरक्षित। + +**नया:** सुविधा समानता के लिए REST फ्लोइंस्टेंस में `graph_embeddings_query()` जोड़ें: + +```python +class FlowInstance: + # All existing methods unchanged... + + # New: Graph embeddings query (REST) + def graph_embeddings_query( + self, + text: str, + user: str, + collection: str, + limit: int = 10, + **kwargs + ) -> List[Dict[str, Any]]: + """Query graph embeddings for semantic search""" + # Calls POST /api/v1/flow/{flow}/service/graph-embeddings + pass +``` + +#### 7. एसिंक्रोनस रेस्ट फ्लो एपीआई + +मॉड्यूल: `trustgraph-base/trustgraph/api/async_flow.py` (नया) + +**AsyncFlow और AsyncFlowInstance क्लास:** + +```python +class AsyncFlow: + """Asynchronous REST-based flow interface""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def list(self) -> List[Dict[str, Any]]: + """List all flows""" + pass + + async def get(self, id: str) -> Dict[str, Any]: + """Get flow definition""" + pass + + async def start(self, class_name: str, id: str, description: str, parameters: Dict) -> None: + """Start a flow""" + pass + + async def stop(self, id: str) -> None: + """Stop a flow""" + pass + + def id(self, flow_id: str) -> AsyncFlowInstance: + """Get async flow instance""" + return AsyncFlowInstance(self.url, self.timeout, self.token, flow_id) + + async def aclose(self) -> None: + """Close connection""" + pass + +class AsyncFlowInstance: + """Asynchronous REST flow instance""" + + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + **kwargs + ) -> Dict[str, Any]: + """Async agent execution""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + **kwargs + ) -> str: + """Async text completion""" + pass + + async def graph_rag( + self, + question: str, + user: str, + collection: str, + **kwargs + ) -> str: + """Async graph RAG""" + pass + + # ... all other FlowInstance methods as async versions +``` + +**मुख्य विशेषताएं:** +देशी एसिंक्रोनस HTTP, `aiohttp` या `httpx` का उपयोग करके। +सिंक्रोनस REST API के समान मेथड सिग्नेचर। +कोई स्ट्रीमिंग नहीं (स्ट्रीमिंग के लिए `async_socket()` का उपयोग करें)। +एसिंक्रोनस अनुप्रयोगों के लिए कुशल। + +#### 8. मेट्रिक्स एपीआई + +मॉड्यूल: `trustgraph-base/trustgraph/api/metrics.py` (नया) + +**सिंक्रोनस मेट्रिक्स:** + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +**अतुल्यकालिक मेट्रिक्स:** + +```python +class AsyncMetrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +#### 9. उन्नत प्रकार (Enhanced Types) + +मॉड्यूल: `trustgraph-base/trustgraph/api/types.py` (संशोधित) + +**नए प्रकार (New Types):** + +```python +from typing import Iterator, Union, Dict, Any +import dataclasses + +@dataclasses.dataclass +class StreamingChunk: + """Base class for streaming chunks""" + content: str + end_of_message: bool = False + +@dataclasses.dataclass +class AgentThought(StreamingChunk): + """Agent reasoning chunk""" + chunk_type: str = "thought" + +@dataclasses.dataclass +class AgentObservation(StreamingChunk): + """Agent tool observation chunk""" + chunk_type: str = "observation" + +@dataclasses.dataclass +class AgentAnswer(StreamingChunk): + """Agent final answer chunk""" + chunk_type: str = "final-answer" + end_of_dialog: bool = False + +@dataclasses.dataclass +class RAGChunk(StreamingChunk): + """RAG streaming chunk""" + end_of_stream: bool = False + error: Optional[Dict[str, str]] = None + +# Type aliases for clarity +AgentStream = Iterator[Union[AgentThought, AgentObservation, AgentAnswer]] +RAGStream = Iterator[RAGChunk] +CompletionStream = Iterator[str] +``` + +#### 6. मेट्रिक्स एपीआई + +मॉड्यूल: `trustgraph-base/trustgraph/api/metrics.py` (नया) + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +### कार्यान्वयन दृष्टिकोण + +#### चरण 1: मुख्य एपीआई संवर्धन (सप्ताह 1) + +1. `socket()`, `bulk()`, और `metrics()` विधियों को `Api` वर्ग में जोड़ें +2. वेबसॉकेट और बल्क क्लाइंट के लिए लेज़ी इनिशियलाइज़ेशन लागू करें +3. संदर्भ प्रबंधक समर्थन जोड़ें (`__enter__`, `__exit__`) +4. सफाई के लिए `close()` विधि जोड़ें +5. एपीआई वर्ग संवर्धनों के लिए यूनिट परीक्षण जोड़ें +6. पिछड़े अनुकूलता की जांच करें + +**पिछड़ी अनुकूलता**: कोई ब्रेकिंग परिवर्तन नहीं। केवल नई विधियाँ। + +#### चरण 2: वेबसॉकेट क्लाइंट (सप्ताह 2-3) + +1. कनेक्शन प्रबंधन के साथ `SocketClient` वर्ग लागू करें +2. `SocketFlowInstance` को `FlowInstance` के समान विधि हस्ताक्षर के साथ लागू करें +3. अनुरोध मल्टीप्लेक्सिंग समर्थन जोड़ें (अधिकतम 15 समवर्ती) +4. विभिन्न चंक प्रकारों के लिए स्ट्रीमिंग प्रतिक्रिया पार्सिंग जोड़ें +5. स्वचालित पुन: कनेक्शन तर्क जोड़ें +6. यूनिट और एकीकरण परीक्षण जोड़ें +7. वेबसॉकेट उपयोग पैटर्न का दस्तावेजीकरण करें + +**पिछड़ी अनुकूलता**: केवल नया इंटरफ़ेस। मौजूदा कोड पर कोई प्रभाव नहीं। + +#### चरण 3: स्ट्रीमिंग समर्थन (सप्ताह 3-4) + +1. स्ट्रीमिंग चंक प्रकार कक्षाएं जोड़ें (`AgentThought`, `AgentObservation`, `AgentAnswer`, `RAGChunk`) +2. `SocketClient` में स्ट्रीमिंग प्रतिक्रिया पार्सिंग लागू करें +3. `SocketFlowInstance` में सभी एलएलएम विधियों में स्ट्रीमिंग पैरामीटर जोड़ें +4. स्ट्रीमिंग के दौरान त्रुटि मामलों को संभालें +5. स्ट्रीमिंग के लिए यूनिट और एकीकरण परीक्षण जोड़ें +6. दस्तावेज़ में स्ट्रीमिंग उदाहरण जोड़ें + +**पिछड़ी अनुकूलता**: केवल नया इंटरफ़ेस। मौजूदा रेस्ट एपीआई अपरिवर्तित। + +#### चरण 4: बल्क ऑपरेशन (सप्ताह 4-5) + +1. `BulkClient` वर्ग लागू करें +2. ट्रिपल, एम्बेडिंग, संदर्भ, ऑब्जेक्ट के लिए बल्क आयात/निर्यात विधियाँ जोड़ें +3. निरंतर मेमोरी के लिए इटरेटर-आधारित प्रसंस्करण लागू करें +4. प्रगति ट्रैकिंग जोड़ें (वैकल्पिक कॉलबैक) +5. आंशिक सफलता रिपोर्टिंग के साथ त्रुटि हैंडलिंग जोड़ें +6. यूनिट और एकीकरण परीक्षण जोड़ें +7. बल्क ऑपरेशन उदाहरण जोड़ें + +**पिछड़ी अनुकूलता**: केवल नया इंटरफ़ेस। मौजूदा कोड पर कोई प्रभाव नहीं। + +#### चरण 5: सुविधा समानता और पॉलिश (सप्ताह 5) + +1. रेस्ट `FlowInstance` में `graph_embeddings_query()` जोड़ें +2. `Metrics` वर्ग लागू करें +3. व्यापक एकीकरण परीक्षण जोड़ें +4. प्रदर्शन बेंचमार्किंग +5. सभी दस्तावेज़ों को अपडेट करें +6. माइग्रेशन गाइड बनाएं + +**पिछड़ी अनुकूलता**: केवल नई विधियाँ। मौजूदा कोड पर कोई प्रभाव नहीं। + +### डेटा मॉडल + +#### इंटरफ़ेस चयन + +```python +# Single API instance, same URL for all interfaces +api = Api(url="http://localhost:8088/") + +# Synchronous interfaces +rest_flow = api.flow().id("default") # Sync REST +socket_flow = api.socket().flow("default") # Sync WebSocket +bulk = api.bulk() # Sync bulk operations +metrics = api.metrics() # Sync metrics + +# Asynchronous interfaces +async_rest_flow = api.async_flow().id("default") # Async REST +async_socket_flow = api.async_socket().flow("default") # Async WebSocket +async_bulk = api.async_bulk() # Async bulk operations +async_metrics = api.async_metrics() # Async metrics +``` + +#### स्ट्रीमिंग प्रतिक्रिया प्रकार + +**एजेंट स्ट्रीमिंग**: + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - non-streaming (same signature) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - streaming (new) +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentThought): + print(f"Thinking: {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"Observed: {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"Answer: {chunk.content}") + if chunk.end_of_dialog: + break +``` + +**RAG स्ट्रीमिंग**: + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.graph_rag(question="What is Python?", user="user123", collection="default") +print(response) + +# WebSocket interface - streaming (new) +socket_flow = api.socket().flow("default") +for chunk in socket_flow.graph_rag( + question="What is Python?", + user="user123", + collection="default", + streaming=True +): + print(chunk.content, end="", flush=True) + if chunk.end_of_stream: + break +``` + +**बल्क ऑपरेशन (सिंक्रोनस):** + +```python +api = Api(url="http://localhost:8088/") + +# Bulk import triples +def triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Bulk export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +**बल्क ऑपरेशन (असिंक्रोनस):** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async bulk import triples + async def async_triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + + # Async bulk export triples + async for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") + +asyncio.run(main()) +``` + +**एसिंक्रोनस रेस्ट उदाहरण:** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST flow operations + flow = api.async_flow().id("default") + response = await flow.agent(question="What is ML?", user="user123") + print(response["response"]) + +asyncio.run(main()) +``` + +**एसिंक्रोनस वेबसॉकेट स्ट्रीमिंग का उदाहरण**: + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async WebSocket streaming + socket = api.async_socket() + flow = socket.flow("default") + + async for chunk in flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) + if chunk.end_of_dialog: + break + +asyncio.run(main()) +``` + +### एपीआई (APIs) + +#### नए एपीआई (New APIs) + +1. **कोर एपीआई क्लास (Core API Class):** + **सिंक्रोनस (Synchronous):** + `Api.socket()` - सिंक्रोनस वेबसॉकेट क्लाइंट प्राप्त करें (Get synchronous WebSocket client) + `Api.bulk()` - सिंक्रोनस बल्क ऑपरेशंस क्लाइंट प्राप्त करें (Get synchronous bulk operations client) + `Api.metrics()` - सिंक्रोनस मेट्रिक्स क्लाइंट प्राप्त करें (Get synchronous metrics client) + `Api.close()` - सभी सिंक्रोनस कनेक्शन बंद करें (Close all synchronous connections) + संदर्भ प्रबंधक समर्थन (Context manager support (`__enter__`, `__exit__`)) + **एसिंक्रोनस (Asynchronous):** + `Api.async_flow()` - एसिंक्रोनस रेस्ट फ्लो क्लाइंट प्राप्त करें (Get asynchronous REST flow client) + `Api.async_socket()` - एसिंक्रोनस वेबसॉकेट क्लाइंट प्राप्त करें (Get asynchronous WebSocket client) + `Api.async_bulk()` - एसिंक्रोनस बल्क ऑपरेशंस क्लाइंट प्राप्त करें (Get asynchronous bulk operations client) + `Api.async_metrics()` - एसिंक्रोनस मेट्रिक्स क्लाइंट प्राप्त करें (Get asynchronous metrics client) + `Api.aclose()` - सभी एसिंक्रोनस कनेक्शन बंद करें (Close all asynchronous connections) + एसिंक्रोनस संदर्भ प्रबंधक समर्थन (Async context manager support (`__aenter__`, `__aexit__`)) + +2. **सिंक्रोनस वेबसॉकेट क्लाइंट (Synchronous WebSocket Client):** + `SocketClient.flow(flow_id)` - वेबसॉकेट फ्लो इंस्टेंस प्राप्त करें (Get WebSocket flow instance) + `SocketFlowInstance.agent(..., streaming: bool = False)` - एजेंट, वैकल्पिक स्ट्रीमिंग के साथ (Agent with optional streaming) + `SocketFlowInstance.text_completion(..., streaming: bool = False)` - टेक्स्ट कंप्लीशन, वैकल्पिक स्ट्रीमिंग के साथ (Text completion with optional streaming) + `SocketFlowInstance.graph_rag(..., streaming: bool = False)` - ग्राफ आरएजी, वैकल्पिक स्ट्रीमिंग के साथ (Graph RAG with optional streaming) + `SocketFlowInstance.document_rag(..., streaming: bool = False)` - डॉक्यूमेंट आरएजी, वैकल्पिक स्ट्रीमिंग के साथ (Document RAG with optional streaming) + `SocketFlowInstance.prompt(..., streaming: bool = False)` - प्रॉम्प्ट, वैकल्पिक स्ट्रीमिंग के साथ (Prompt with optional streaming) + `SocketFlowInstance.graph_embeddings_query()` - ग्राफ एम्बेडिंग क्वेरी (Graph embeddings query) + सभी अन्य FlowInstance विधियाँ, समान हस्ताक्षर के साथ (All other FlowInstance methods with identical signatures) + +3. **एसिंक्रोनस वेबसॉकेट क्लाइंट (Asynchronous WebSocket Client):** + `AsyncSocketClient.flow(flow_id)` - एसिंक्रोनस वेबसॉकेट फ्लो इंस्टेंस प्राप्त करें (Get async WebSocket flow instance) + `AsyncSocketFlowInstance.agent(..., streaming: bool = False)` - एसिंक्रोनस एजेंट, वैकल्पिक स्ट्रीमिंग के साथ (Async agent with optional streaming) + `AsyncSocketFlowInstance.text_completion(..., streaming: bool = False)` - एसिंक्रोनस टेक्स्ट कंप्लीशन, वैकल्पिक स्ट्रीमिंग के साथ (Async text completion with optional streaming) + `AsyncSocketFlowInstance.graph_rag(..., streaming: bool = False)` - एसिंक्रोनस ग्राफ आरएजी, वैकल्पिक स्ट्रीमिंग के साथ (Async graph RAG with optional streaming) + `AsyncSocketFlowInstance.document_rag(..., streaming: bool = False)` - एसिंक्रोनस डॉक्यूमेंट आरएजी, वैकल्पिक स्ट्रीमिंग के साथ (Async document RAG with optional streaming) + `AsyncSocketFlowInstance.prompt(..., streaming: bool = False)` - एसिंक्रोनस प्रॉम्प्ट, वैकल्पिक स्ट्रीमिंग के साथ (Async prompt with optional streaming) + `AsyncSocketFlowInstance.graph_embeddings_query()` - एसिंक्रोनस ग्राफ एम्बेडिंग क्वेरी (Async graph embeddings query) + सभी अन्य FlowInstance विधियाँ, एसिंक्रोनस संस्करण के रूप में (All other FlowInstance methods as async versions) + +4. **सिंक्रोनस बल्क ऑपरेशंस क्लाइंट (Synchronous Bulk Operations Client):** + `BulkClient.import_triples(flow, triples)` - बल्क ट्रिपल इम्पोर्ट (Bulk triple import) + `BulkClient.export_triples(flow)` - बल्क ट्रिपल एक्सपोर्ट (Bulk triple export) + `BulkClient.import_graph_embeddings(flow, embeddings)` - बल्क ग्राफ एम्बेडिंग इम्पोर्ट (Bulk graph embeddings import) + `BulkClient.export_graph_embeddings(flow)` - बल्क ग्राफ एम्बेडिंग एक्सपोर्ट (Bulk graph embeddings export) + `BulkClient.import_document_embeddings(flow, embeddings)` - बल्क डॉक्यूमेंट एम्बेडिंग इम्पोर्ट (Bulk document embeddings import) + `BulkClient.export_document_embeddings(flow)` - बल्क डॉक्यूमेंट एम्बेडिंग एक्सपोर्ट (Bulk document embeddings export) + `BulkClient.import_entity_contexts(flow, contexts)` - बल्क एंटिटी कॉन्टेक्स्ट इम्पोर्ट (Bulk entity contexts import) + `BulkClient.export_entity_contexts(flow)` - बल्क एंटिटी कॉन्टेक्स्ट एक्सपोर्ट (Bulk entity contexts export) + `BulkClient.import_objects(flow, objects)` - बल्क ऑब्जेक्ट्स इम्पोर्ट (Bulk objects import) + +5. **एसिंक्रोनस बल्क ऑपरेशंस क्लाइंट (Asynchronous Bulk Operations Client):** + `AsyncBulkClient.import_triples(flow, triples)` - एसिंक्रोनस बल्क ट्रिपल इम्पोर्ट (Async bulk triple import) + `AsyncBulkClient.export_triples(flow)` - एसिंक्रोनस बल्क ट्रिपल एक्सपोर्ट (Async bulk triple export) + `AsyncBulkClient.import_graph_embeddings(flow, embeddings)` - एसिंक्रोनस बल्क ग्राफ एम्बेडिंग इम्पोर्ट (Async bulk graph embeddings import) + `AsyncBulkClient.export_graph_embeddings(flow)` - एसिंक्रोनस बल्क ग्राफ एम्बेडिंग एक्सपोर्ट (Async bulk graph embeddings export) + `AsyncBulkClient.import_document_embeddings(flow, embeddings)` - एसिंक्रोनस बल्क डॉक्यूमेंट एम्बेडिंग इम्पोर्ट (Async bulk document embeddings import) + `AsyncBulkClient.export_document_embeddings(flow)` - एसिंक्रोनस बल्क डॉक्यूमेंट एम्बेडिंग एक्सपोर्ट (Async bulk document embeddings export) + `AsyncBulkClient.import_entity_contexts(flow, contexts)` - एसिंक्रोनस बल्क एंटिटी कॉन्टेक्स्ट इम्पोर्ट (Async bulk entity contexts import) + `AsyncBulkClient.export_entity_contexts(flow)` - एसिंक्रोनस बल्क एंटिटी कॉन्टेक्स्ट एक्सपोर्ट (Async bulk entity contexts export) + `AsyncBulkClient.import_objects(flow, objects)` - एसिंक्रोनस बल्क ऑब्जेक्ट्स इम्पोर्ट (Async bulk objects import) + +6. **एसिंक्रोनस रेस्ट फ्लो क्लाइंट (Asynchronous REST Flow Client):** + `AsyncFlow.list()` - सभी फ्लो की सूची (list all flows) + `AsyncFlow.get(id)` - फ्लो परिभाषा प्राप्त करें (get flow definition) + `AsyncFlow.start(...)` - फ्लो शुरू करें (start flow) + `AsyncFlow.stop(id)` - फ्लो रोकें (stop flow) + `AsyncFlow.id(flow_id)` - एसिंक्रोनस फ्लो इंस्टेंस प्राप्त करें (get async flow instance) + `AsyncFlowInstance.agent(...)` - एजेंट निष्पादन (agent execution) + `AsyncFlowInstance.text_completion(...)` - टेक्स्ट कंप्लीशन (text completion) + `AsyncFlowInstance.graph_rag(...)` - ग्राफ आरएजी (graph RAG) + सभी अन्य FlowInstance विधियाँ, एसिंक्रोनस संस्करण के रूप में (All other FlowInstance methods as async versions) + +7. **मेट्रिक्स क्लाइंट (Metrics Clients):** + `Metrics.get()` - सिंक्रोनस प्रोमीथियस मेट्रिक्स (Synchronous Prometheus metrics) + `AsyncMetrics.get()` - एसिंक्रोनस प्रोमीथियस मेट्रिक्स (Asynchronous Prometheus metrics) + +8. **रेस्ट फ्लो एपीआई एन्हांसमेंट (REST Flow API Enhancement):** + `FlowInstance.graph_embeddings_query()` - ग्राफ एम्बेडिंग क्वेरी (सिंक्रोनस फीचर समानता) (Graph embeddings query (sync feature parity)) + `AsyncFlowInstance.graph_embeddings_query()` - ग्राफ एम्बेडिंग क्वेरी (एसिंक्रोनस फीचर समानता) (Graph embeddings query (async feature parity)) + +#### संशोधित एपीआई (Modified APIs) + +1. **कंस्ट्रक्टर (Constructor)** (मामूली एन्हांसमेंट): + ```python + Api(url: str, timeout: int = 60, token: Optional[str] = None) + ``` + `token` पैरामीटर जोड़ा गया (वैकल्पिक, प्रमाणीकरण के लिए) + यदि `None` (डिफ़ॉल्ट): कोई प्रमाणीकरण उपयोग नहीं किया गया + यदि निर्दिष्ट: REST के लिए इसे बेयरर टोकन के रूप में उपयोग किया जाता है (`Authorization: Bearer `), और WebSocket के लिए क्वेरी पैरामीटर के रूप में (`?token=`) + कोई अन्य परिवर्तन नहीं - पूरी तरह से पिछली संगतता + +2. **कोई महत्वपूर्ण परिवर्तन नहीं**: + सभी मौजूदा REST API विधियाँ अपरिवर्तित हैं + सभी मौजूदा हस्ताक्षर संरक्षित हैं + सभी मौजूदा रिटर्न प्रकार संरक्षित हैं + +### कार्यान्वयन विवरण + +#### त्रुटि प्रबंधन + +**WebSocket कनेक्शन त्रुटियाँ**: +```python +try: + api = Api(url="http://localhost:8088/") + socket = api.socket() + socket_flow = socket.flow("default") + response = socket_flow.agent(question="...", user="user123") +except ConnectionError as e: + print(f"WebSocket connection failed: {e}") + print("Hint: Ensure Gateway is running and WebSocket endpoint is accessible") +``` + +**सुगम प्रतिस्थापन**: +```python +api = Api(url="http://localhost:8088/") + +try: + # Try WebSocket streaming first + socket_flow = api.socket().flow("default") + for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk.content) +except ConnectionError: + # Fall back to REST non-streaming + print("WebSocket unavailable, falling back to REST") + rest_flow = api.flow().id("default") + response = rest_flow.agent(question="...", user="...") + print(response["response"]) +``` + +**आंशिक स्ट्रीमिंग त्रुटियाँ**: +```python +api = Api(url="http://localhost:8088/") +socket_flow = api.socket().flow("default") + +accumulated = [] +try: + for chunk in socket_flow.graph_rag(question="...", streaming=True): + accumulated.append(chunk.content) + if chunk.error: + print(f"Error occurred: {chunk.error}") + print(f"Partial response: {''.join(accumulated)}") + break +except Exception as e: + print(f"Streaming error: {e}") + print(f"Partial response: {''.join(accumulated)}") +``` + +#### संसाधन प्रबंधन + +**संदर्भ प्रबंधक समर्थन**: +```python +# Automatic cleanup +with Api(url="http://localhost:8088/") as api: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +# All connections automatically closed + +# Manual cleanup +api = Api(url="http://localhost:8088/") +try: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +finally: + api.close() # Explicitly close all connections (WebSocket, bulk, etc.) +``` + +#### थ्रेडिंग और समवर्ती (Threading and Concurrency) + +**थ्रेड सुरक्षा (Thread Safety):** +प्रत्येक `Api` उदाहरण अपने स्वयं के कनेक्शन को बनाए रखता है। +WebSocket ट्रांसपोर्ट थ्रेड-सुरक्षित अनुरोध मल्टीप्लेक्सिंग के लिए लॉक्स का उपयोग करता है। +कई थ्रेड सुरक्षित रूप से एक `Api` उदाहरण को साझा कर सकते हैं। +स्ट्रीमिंग इटरेटर थ्रेड-सुरक्षित नहीं हैं (केवल एक थ्रेड से उपयोग करें)। + +**एसिंक्रोनस समर्थन (Async Support)** (भविष्य में विचार): +```python +# Phase 2 enhancement (not in initial scope) +import asyncio + +async def main(): + api = await AsyncApi(url="ws://localhost:8088/") + flow = api.flow().id("default") + + async for chunk in flow.agent(question="...", streaming=True): + print(chunk.content) + + await api.close() + +asyncio.run(main()) +``` + +## सुरक्षा संबंधी विचार + +### प्रमाणीकरण + +**टोकन पैरामीटर**: +```python +# No authentication (default) +api = Api(url="http://localhost:8088/") + +# With authentication +api = Api(url="http://localhost:8088/", token="mytoken") +``` + +**REST ट्रांसपोर्ट:** +बेयरर टोकन `Authorization` हेडर के माध्यम से +सभी REST अनुरोधों पर स्वचालित रूप से लागू होता है +प्रारूप: `Authorization: Bearer ` + +**वेबसोकेट ट्रांसपोर्ट:** +टोकन क्वेरी पैरामीटर के माध्यम से, जो वेबसोकेट यूआरएल में जोड़ा जाता है +कनेक्शन स्थापित करते समय स्वचालित रूप से लागू होता है +प्रारूप: `ws://localhost:8088/api/v1/socket?token=` + +**कार्यान्वयन:** +```python +class SocketClient: + def _connect(self) -> WebSocket: + # Construct WebSocket URL with optional token + ws_url = f"{self.url}/api/v1/socket" + if self.token: + ws_url = f"{ws_url}?token={self.token}" + # Connect to WebSocket + return websocket.connect(ws_url) +``` + +**उदाहरण:** +```python +# REST with auth +api = Api(url="http://localhost:8088/", token="mytoken") +flow = api.flow().id("default") +# All REST calls include: Authorization: Bearer mytoken + +# WebSocket with auth +socket = api.socket() +# Connects to: ws://localhost:8088/api/v1/socket?token=mytoken +``` + +### सुरक्षित संचार + +WS (वेबसॉकेट) और WSS (वेबसॉकेट सिक्योर) दोनों योजनाओं का समर्थन करें। +WSS कनेक्शन के लिए टीएलएस प्रमाणपत्र सत्यापन। +विकास के लिए वैकल्पिक प्रमाणपत्र सत्यापन अक्षम करें (चेतावनी के साथ)। + +### इनपुट सत्यापन + +यूआरएल योजनाओं को मान्य करें (http, https, ws, wss)। +परिवहन पैरामीटर मानों को मान्य करें। +स्ट्रीमिंग पैरामीटर संयोजनों को मान्य करें। +बल्क आयात डेटा प्रकारों को मान्य करें। + +## प्रदर्शन संबंधी विचार + +### विलंबता में सुधार + +**स्ट्रीमिंग एलएलएम ऑपरेशन**: +**पहले टोकन तक का समय**: ~500ms (गैर-स्ट्रीमिंग के मुकाबले ~30s) +**सुधार**: 60 गुना तेज प्रदर्शन +**लागू**: एजेंट, ग्राफ आरएजी, दस्तावेज़ आरएजी, टेक्स्ट कंप्लीशन, प्रॉम्प्ट + +**स्थायी कनेक्शन**: +**कनेक्शन ओवरहेड**: बाद के अनुरोधों के लिए समाप्त +**वेबसॉकेट हैंडशेक**: एक बार की लागत (~100ms) +**लागू**: वेबसॉकेट परिवहन का उपयोग करते समय सभी ऑपरेशन + +### थ्रूपुट में सुधार + +**बल्क ऑपरेशन**: +**ट्रिपल्स आयात**: ~10,000 ट्रिपल्स/सेकंड (REST के साथ प्रति-आइटम ~100/सेकंड की तुलना में) +**एम्बेडिंग आयात**: ~5,000 एम्बेडिंग/सेकंड (REST के साथ प्रति-आइटम ~50/सेकंड की तुलना में) +**सुधार**: बल्क ऑपरेशन के लिए 100 गुना थ्रूपुट + +**अनुरोध मल्टीप्लेक्सिंग**: +**समवर्ती अनुरोध**: एक कनेक्शन पर 15 तक समवर्ती अनुरोध +**कनेक्शन पुन: उपयोग**: समवर्ती ऑपरेशन के लिए कोई कनेक्शन ओवरहेड नहीं + +### मेमोरी संबंधी विचार + +**स्ट्रीमिंग प्रतिक्रियाएं**: +स्थिर मेमोरी उपयोग (जैसे ही वे आते हैं, चंक्स को संसाधित करें) +पूरी प्रतिक्रिया का कोई बफरिंग नहीं +बहुत लंबी आउटपुट (>1MB) के लिए उपयुक्त + +**बल्क ऑपरेशन**: +इटरेटर-आधारित प्रसंस्करण (स्थिर मेमोरी) +संपूर्ण डेटासेट को मेमोरी में लोड नहीं किया जाता है +लाखों आइटम वाले डेटासेट के लिए उपयुक्त + +### बेंचमार्क (अपेक्षित) + +| ऑपरेशन | REST (मौजूदा) | वेबसॉकेट (स्ट्रीमिंग) | सुधार | +|-----------|----------------|----------------------|-------------| +| एजेंट (पहले टोकन तक का समय) | 30s | 0.5s | 60x | +| ग्राफ आरएजी (पहले टोकन तक का समय) | 25s | 0.5s | 50x | +| 10K ट्रिपल्स आयात करें | 100s | 1s | 100x | +| 1M ट्रिपल्स आयात करें | 10,000s (2.7h) | 100s (1.6m) | 100x | +| 10 समवर्ती छोटे अनुरोध | 5s (क्रमिक) | 0.5s (समानांतर) | 10x | + +## परीक्षण रणनीति + +### यूनिट टेस्ट + +**परिवहन परत** (`test_transport.py`): +REST परिवहन अनुरोध/प्रतिक्रिया का परीक्षण करें +WebSocket परिवहन कनेक्शन का परीक्षण करें +WebSocket परिवहन पुन: कनेक्शन का परीक्षण करें +अनुरोध मल्टीप्लेक्सिंग का परीक्षण करें +स्ट्रीमिंग प्रतिक्रिया पार्सिंग का परीक्षण करें +नियतात्मक परीक्षणों के लिए मॉक WebSocket सर्वर + +**API विधियाँ** (`test_flow.py`, `test_library.py`, आदि): +मॉक परिवहन के साथ नई विधियों का परीक्षण करें +स्ट्रीमिंग पैरामीटर हैंडलिंग का परीक्षण करें +बल्क ऑपरेशन इटरेटर का परीक्षण करें +त्रुटि हैंडलिंग का परीक्षण करें + +**प्रकार** (`test_types.py`): +नए स्ट्रीमिंग चंक प्रकारों का परीक्षण करें +प्रकार क्रमबद्धता/वि-क्रमबद्धता का परीक्षण करें + +### एकीकरण परीक्षण + +**एंड-टू-एंड REST** (`test_integration_rest.py`): +वास्तविक गेटवे (REST मोड) के खिलाफ सभी कार्यों का परीक्षण करें +पिछड़े अनुकूलता को सत्यापित करें +त्रुटि स्थितियों का परीक्षण करें + +**एंड-टू-एंड WebSocket** (`test_integration_websocket.py`): +वास्तविक गेटवे (WebSocket मोड) के खिलाफ सभी कार्यों का परीक्षण करें +स्ट्रीमिंग कार्यों का परीक्षण करें +बल्क कार्यों का परीक्षण करें +समवर्ती अनुरोधों का परीक्षण करें +कनेक्शन रिकवरी का परीक्षण करें + +**स्ट्रीमिंग सेवाएं** (`test_streaming_integration.py`): +एजेंट स्ट्रीमिंग का परीक्षण करें (विचार, अवलोकन, उत्तर) +RAG स्ट्रीमिंग का परीक्षण करें (क्रमिक चंक) +टेक्स्ट कंप्लीशन स्ट्रीमिंग का परीक्षण करें (टोकन-दर-टोकन) +प्रॉम्प्ट स्ट्रीमिंग का परीक्षण करें +स्ट्रीमिंग के दौरान त्रुटि हैंडलिंग का परीक्षण करें + +**बल्क ऑपरेशन** (`test_bulk_integration.py`): +ट्रिपल (1K, 10K, 100K आइटम) का बल्क आयात/निर्यात का परीक्षण करें +एम्बेडिंग का बल्क आयात/निर्यात का परीक्षण करें +बल्क कार्यों के दौरान मेमोरी उपयोग का परीक्षण करें +प्रगति ट्रैकिंग का परीक्षण करें + +### प्रदर्शन परीक्षण + +**विलंबता बेंचमार्क** (`test_performance_latency.py`): +पहले टोकन तक लगने वाले समय को मापें (स्ट्रीमिंग बनाम गैर-स्ट्रीमिंग) +कनेक्शन ओवरहेड को मापें (REST बनाम WebSocket) +अपेक्षित बेंचमार्क के विरुद्ध तुलना करें + +**थ्रूपुट बेंचमार्क** (`test_performance_throughput.py`): +बल्क आयात थ्रूपुट को मापें +अनुरोध मल्टीप्लेक्सिंग दक्षता को मापें +अपेक्षित बेंचमार्क के विरुद्ध तुलना करें + +### अनुकूलता परीक्षण + +**पिछड़ी अनुकूलता** (`test_backward_compatibility.py`): +मौजूदा परीक्षण सूट को रिफैक्टर किए गए API के खिलाफ चलाएं +शून्य ब्रेकिंग परिवर्तनों को सत्यापित करें +सामान्य पैटर्न के लिए माइग्रेशन पथ का परीक्षण करें + +## माइग्रेशन योजना + +### चरण 1: पारदर्शी माइग्रेशन (डिफ़ॉल्ट) + +**किसी कोड परिवर्तन की आवश्यकता नहीं है।** मौजूदा कोड काम करना जारी रखता है: + +```python +# Existing code works unchanged +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") +response = flow.agent(question="What is ML?", user="user123") +``` + +### चरण 2: ऑप्ट-इन स्ट्रीमिंग (सरल) + +**स्ट्रीमिंग को सक्षम करने के लिए `api.socket()` इंटरफ़ेस का उपयोग करें:** + +```python +# Before: Non-streaming REST +api = Api(url="http://localhost:8088/") +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# After: Streaming WebSocket (same parameters!) +api = Api(url="http://localhost:8088/") # Same URL +socket_flow = api.socket().flow("default") + +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) +``` + +**मुख्य बातें:** +REST और WebSocket दोनों के लिए समान URL +समान मेथड सिग्नेचर (आसान माइग्रेशन) +बस `.socket()` और `streaming=True` जोड़ें + +### चरण 3: बल्क ऑपरेशन (नई क्षमता) + +बड़े डेटासेट के लिए `api.bulk()` इंटरफ़ेस का उपयोग करें: + +```python +# Before: Inefficient per-item operations +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") + +for triple in my_large_triple_list: + # Slow per-item operations + # (no direct bulk insert in REST API) + pass + +# After: Efficient bulk loading +api = Api(url="http://localhost:8088/") # Same URL +bulk = api.bulk() + +# This is fast (10,000 triples/second) +bulk.import_triples(flow="default", triples=iter(my_large_triple_list)) +``` + +### दस्तावेज़ अद्यतन + +1. **README.md**: स्ट्रीमिंग और वेबसॉकेट उदाहरण जोड़ें +2. **एपीआई संदर्भ**: सभी नए तरीकों और पैरामीटरों का दस्तावेजीकरण करें +3. **माइग्रेशन गाइड**: स्ट्रीमिंग को सक्षम करने के लिए चरण-दर-चरण मार्गदर्शिका +4. **उदाहरण**: सामान्य पैटर्न के लिए उदाहरण स्क्रिप्ट जोड़ें +5. **प्रदर्शन गाइड**: अपेक्षित प्रदर्शन सुधारों का दस्तावेजीकरण करें + +### अप्रचलन नीति + +**कोई अप्रचलन नहीं।** सभी मौजूदा एपीआई समर्थित रहते हैं। यह एक शुद्ध संवर्द्धन है। + +## समयरेखा + +### सप्ताह 1: आधार +परिवहन अमूर्त परत +मौजूदा REST कोड को पुनर्गठित करें +परिवहन परत के लिए यूनिट परीक्षण +पिछड़े अनुकूलता सत्यापन + +### सप्ताह 2: वेबसॉकेट परिवहन +वेबसॉकेट परिवहन कार्यान्वयन +कनेक्शन प्रबंधन और पुन: कनेक्शन +अनुरोध मल्टीप्लेक्सिंग +यूनिट और एकीकरण परीक्षण + +### सप्ताह 3: स्ट्रीमिंग समर्थन +एलएलएम विधियों में स्ट्रीमिंग पैरामीटर जोड़ें +स्ट्रीमिंग प्रतिक्रिया पार्सिंग को लागू करें +स्ट्रीमिंग चंक प्रकार जोड़ें +स्ट्रीमिंग एकीकरण परीक्षण + +### सप्ताह 4: बल्क ऑपरेशन +बल्क आयात/निर्यात विधियाँ जोड़ें +इटरेटर-आधारित संचालन को लागू करें +प्रदर्शन परीक्षण +बल्क ऑपरेशन एकीकरण परीक्षण + +### सप्ताह 5: सुविधा समानता और दस्तावेज़ +ग्राफ एम्बेडिंग क्वेरी जोड़ें +मेट्रिक्स एपीआई जोड़ें +व्यापक दस्तावेज़ +माइग्रेशन गाइड +रिलीज़ उम्मीदवार + +### सप्ताह 6: रिलीज़ +अंतिम एकीकरण परीक्षण +प्रदर्शन बेंचमार्किंग +रिलीज़ दस्तावेज़ +सामुदायिक घोषणा + +**कुल अवधि**: 6 सप्ताह + +## खुले प्रश्न + +### एपीआई डिज़ाइन प्रश्न + +1. **एसिंक्रोनस समर्थन**: ✅ **समाधान** - प्रारंभिक रिलीज़ में पूर्ण एसिंक्रोनस समर्थन शामिल है + सभी इंटरफेस में एसिंक्रोनस वेरिएंट हैं: `async_flow()`, `async_socket()`, `async_bulk()`, `async_metrics()` + सिंक और एसिंक्रोनस एपीआई के बीच पूर्ण समरूपता प्रदान करता है + आधुनिक एसिंक्रोनस फ्रेमवर्क (FastAPI, aiohttp) के लिए आवश्यक है + +2. **प्रगति ट्रैकिंग**: क्या बल्क ऑपरेशन प्रगति कॉलबैक का समर्थन करना चाहिए? + ```python + def progress_callback(processed: int, total: Optional[int]): + print(f"Processed {processed} items") + + bulk.import_triples(flow="default", triples=triples, on_progress=progress_callback) + ``` + **सिफारिश**: चरण 2 में जोड़ें। प्रारंभिक रिलीज़ के लिए महत्वपूर्ण नहीं है। + +3. **स्ट्रीमिंग टाइमआउट**: हमें स्ट्रीमिंग कार्यों के लिए टाइमआउट को कैसे संभालना चाहिए? + **सिफारिश**: गैर-स्ट्रीमिंग के समान टाइमआउट का उपयोग करें, लेकिन प्रत्येक प्राप्त चंक पर इसे रीसेट करें। + +4. **चंक बफरिंग**: क्या हमें चंक्स को बफर करना चाहिए या तुरंत आउटपुट देना चाहिए? + **सिफारिश**: सबसे कम विलंबता के लिए तुरंत आउटपुट दें। + +5. **वेबसॉकेट के माध्यम से वैश्विक सेवाएं**: क्या `api.socket()` को वैश्विक सेवाओं (लाइब्रेरी, ज्ञान, संग्रह, कॉन्फ़िगरेशन) का समर्थन करना चाहिए या केवल फ़्लो-स्कोप सेवाओं का? + **सिफारिश**: केवल फ़्लो-स्कोप के साथ शुरुआत करें (जहां स्ट्रीमिंग मायने रखती है)। यदि आवश्यक हो तो चरण 2 में वैश्विक सेवाओं को जोड़ें। + +### कार्यान्वयन प्रश्न + +1. **वेबसॉकेट लाइब्रेरी**: क्या हमें `websockets`, `websocket-client`, या `aiohttp` का उपयोग करना चाहिए? + **सिफारिश**: `websockets` (एसिंक्रोनस, परिपक्व, अच्छी तरह से बनाए रखा गया)। `asyncio.run()` का उपयोग करके सिंक इंटरफ़ेस में लपेटें। + +2. **कनेक्शन पूलिंग**: क्या हमें कई समवर्ती `Api` उदाहरणों का समर्थन करना चाहिए जो एक कनेक्शन पूल साझा करते हैं? + **सिफारिश**: चरण 2 तक टालें। प्रत्येक `Api` उदाहरण में शुरू में अपने स्वयं के कनेक्शन होंगे। + +3. **कनेक्शन पुन: उपयोग**: क्या `SocketClient` और `BulkClient` एक ही वेबसॉकेट कनेक्शन साझा करेंगे, या अलग-अलग कनेक्शन का उपयोग करेंगे? + **सिफारिश**: अलग कनेक्शन। सरल कार्यान्वयन, चिंताओं का स्पष्ट अलगाव। + +4. **लेजी बनाम ईगर कनेक्शन**: क्या वेबसॉकेट कनेक्शन `api.socket()` में स्थापित किया जाना चाहिए या पहले अनुरोध पर? + **सिफारिश**: लेजी (पहले अनुरोध पर)। यदि उपयोगकर्ता केवल REST विधियों का उपयोग करता है तो कनेक्शन ओवरहेड से बचें। + +### परीक्षण प्रश्न + +1. **मॉक गेटवे**: क्या हमें परीक्षण के लिए एक हल्के मॉक गेटवे बनाना चाहिए, या वास्तविक गेटवे के खिलाफ परीक्षण करना चाहिए? + **सिफारिश**: दोनों। यूनिट परीक्षणों के लिए मॉक का उपयोग करें, एकीकरण परीक्षणों के लिए वास्तविक गेटवे का उपयोग करें। + +2. **प्रदर्शन प्रतिगमन परीक्षण**: क्या हमें CI में स्वचालित प्रदर्शन प्रतिगमन परीक्षण जोड़ना चाहिए? + **सिफारिश**: हाँ, लेकिन CI वातावरण की परिवर्तनशीलता को ध्यान में रखते हुए उदार सीमाओं के साथ। + +## संदर्भ + +### संबंधित तकनीकी विनिर्देश +`docs/tech-specs/streaming-llm-responses.md` - गेटवे में स्ट्रीमिंग कार्यान्वयन +`docs/tech-specs/rag-streaming-support.md` - RAG स्ट्रीमिंग समर्थन + +### कार्यान्वयन फ़ाइलें +`trustgraph-base/trustgraph/api/` - पायथन एपीआई स्रोत +`trustgraph-flow/trustgraph/gateway/` - गेटवे स्रोत +`trustgraph-flow/trustgraph/gateway/dispatch/mux.py` - वेबसॉकेट मल्टीप्लेक्सर संदर्भ कार्यान्वयन + +### दस्तावेज़ +`docs/apiSpecification.md` - पूर्ण एपीआई संदर्भ +`docs/api-status-summary.md` - एपीआई स्थिति सारांश +`README.websocket` - वेबसॉकेट प्रोटोकॉल दस्तावेज़ +`STREAMING-IMPLEMENTATION-NOTES.txt` - स्ट्रीमिंग कार्यान्वयन नोट्स + +### बाहरी लाइब्रेरी +`websockets` - पायथन वेबसॉकेट लाइब्रेरी (https://websockets.readthedocs.io/) +`requests` - पायथन एचटीटीपी लाइब्रेरी (मौजूदा) diff --git a/docs/tech-specs/python-api-refactor.pt.md b/docs/tech-specs/python-api-refactor.pt.md new file mode 100644 index 00000000..4993e774 --- /dev/null +++ b/docs/tech-specs/python-api-refactor.pt.md @@ -0,0 +1,1508 @@ +# Python API Refactor Technical Specification + +## Overview + +Esta especificação descreve uma refatoração abrangente da biblioteca de cliente da API Python TrustGraph para alcançar a paridade de recursos com o API Gateway e adicionar suporte para padrões de comunicação em tempo real modernos. + +A refatoração aborda quatro casos de uso primários: + +1. **Interações de LLM em Streaming**: Habilitar o streaming em tempo real de respostas de LLM (agente, RAG de grafo, RAG de documento, conclusão de texto, prompts) com uma latência ~60 vezes menor (500ms vs 30s para o primeiro token). +2. **Operações em Lote**: Suportar a importação/exportação eficiente em lote de triplas, incorporações de grafos e incorporações de documentos para gerenciamento de grafos de conhecimento em grande escala. +3. **Paridade de Recursos**: Garantir que cada endpoint do API Gateway tenha um método de API Python correspondente, incluindo a consulta de incorporações de grafos. +4. **Conexões Persistentes**: Habilitar a comunicação baseada em WebSocket para solicitações multiplexadas e redução da sobrecarga de conexão. + +## Objetivos + +**Paridade de Recursos**: Cada serviço do Gateway API tem um método de API Python correspondente. +**Suporte para Streaming**: Todos os serviços capazes de streaming (agente, RAG, conclusão de texto, prompt) suportam streaming na API Python. +**Transporte WebSocket**: Adicionar uma camada de transporte WebSocket opcional para conexões persistentes e multiplexação. +**Operações em Lote**: Adicionar importação/exportação eficiente em lote para triplas, incorporações de grafos e incorporações de documentos. +**Suporte Completo Async**: Implementação completa de async/await para todas as interfaces (REST, WebSocket, operações em lote, métricas). +**Compatibilidade com Versões Anteriores**: O código existente continua a funcionar sem modificação. +**Segurança de Tipos**: Manter interfaces com segurança de tipos com dataclasses e dicas de tipo. +**Aprimoramento Progressivo**: Streaming e async são opcionais por meio da seleção explícita da interface. +**Desempenho**: Alcançar uma melhoria de latência de 60 vezes para operações de streaming. +**Python Moderno**: Suporte para paradigmas sync e async para máxima flexibilidade. + +## Contexto + +### Estado Atual + +A API Python (`trustgraph-base/trustgraph/api/`) é uma biblioteca de cliente REST somente com os seguintes módulos: + +`flow.py`: Gerenciamento de fluxo e serviços com escopo de fluxo (50 métodos). +`library.py`: Operações da biblioteca de documentos (9 métodos). +`knowledge.py`: Gerenciamento central do KG (4 métodos). +`collection.py`: Metadados da coleção (3 métodos). +`config.py`: Gerenciamento de configuração (6 métodos). +`types.py`: Definições de tipo de dados (5 dataclasses). + +**Operações Totais**: 50/59 (85% de cobertura). + +### Limitações Atuais + +**Operações Ausentes**: +Consulta de incorporações de grafos (busca semântica sobre entidades de grafos). +Importação/exportação em lote para triplas, incorporações de grafos, incorporações de documentos, contextos de entidades, objetos. +Endpoint de métricas. + +**Capacidades Ausentes**: +Suporte para streaming para serviços de LLM. +Transporte WebSocket. +Solicitações concorrentes multiplexadas. +Conexões persistentes. + +**Problemas de Desempenho**: +Alta latência para interações de LLM (~30s para o primeiro token). +Transferência de dados em lote ineficiente (requisição REST por item). +Sobrecarga de conexão para várias operações sequenciais. + +**Problemas de Experiência do Usuário**: +Sem feedback em tempo real durante a geração de LLM. +Não é possível cancelar operações de LLM em execução prolongada. +Má escalabilidade para operações em lote. + +### Impacto + +O aprimoramento de streaming do API Gateway em novembro de 2024 proporcionou uma melhoria de latência de 60 vezes (500ms vs 30s para o primeiro token) para interações de LLM, mas os usuários da API Python não podem aproveitar essa capacidade. Isso cria uma lacuna significativa de experiência entre usuários de Python e não usuários de Python. + +## Design Técnico + +### Arquitetura + +A API Python refatorada usa uma **abordagem de interface modular** com objetos separados para diferentes padrões de comunicação. Todas as interfaces estão disponíveis tanto em variantes **síncronas quanto assíncronas**: + +1. **Interface REST** (existente, aprimorada). + **Sync**: `api.flow()`, `api.library()`, `api.knowledge()`, `api.collection()`, `api.config()`. + **Async**: `api.async_flow()`. + Requisição/resposta síncrona/assíncrona. + Modelo de conexão simples. + Padrão para compatibilidade com versões anteriores. + +2. **Interface WebSocket** (nova). + **Sync**: `api.socket()`. + **Async**: `api.async_socket()`. + Conexão persistente. + Solicitações multiplexadas. + Suporte para streaming. + Mesmas assinaturas de método do REST onde a funcionalidade se sobrepõe. + +3. **Interface de Operações em Lote** (nova). + **Sync**: `api.bulk()`. + **Async**: `api.async_bulk()`. + Baseado em WebSocket para eficiência. + Importação/exportação baseada em iterador/AsyncIterator. + Lida com grandes conjuntos de dados. + +4. **Interface de Métricas** (nova). + **Sync**: `api.metrics()`. + **Async**: `api.async_metrics()`. + Acesso a métricas Prometheus. + +```python +import asyncio + +# Synchronous interfaces +api = Api(url="http://localhost:8088/") + +# REST (existing, unchanged) +flow = api.flow().id("default") +response = flow.agent(question="...", user="...") + +# WebSocket (new) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="...", user="...") +for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk) + +# Bulk operations (new) +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Asynchronous interfaces +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST (new) + flow = api.async_flow().id("default") + response = await flow.agent(question="...", user="...") + + # Async WebSocket (new) + socket_flow = api.async_socket().flow("default") + async for chunk in socket_flow.agent(question="...", streaming=True): + print(chunk) + + # Async bulk operations (new) + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + +asyncio.run(main()) +``` + +**Princípios de Design Chave:** +**Mesmo URL para todas as interfaces:** `Api(url="http://localhost:8088/")` funciona para todas. +**Simetria Síncrona/Assíncrona:** Cada interface possui variantes síncronas e assíncronas com assinaturas de método idênticas. +**Assinaturas Idênticas:** Onde a funcionalidade se sobrepõe, as assinaturas dos métodos são idênticas entre REST e WebSocket, síncronas e assíncronas. +**Melhoria Progressiva:** Escolha a interface com base nas necessidades (REST para tarefas simples, WebSocket para streaming, Bulk para grandes conjuntos de dados, assíncrono para frameworks modernos). +**Intenção Explícita:** `api.socket()` sinaliza WebSocket, `api.async_socket()` sinaliza WebSocket assíncrono. +**Compatível com versões anteriores:** Código existente permanece inalterado. + +### Componentes + +#### 1. Classe de API Principal (Modificada) + +Módulo: `trustgraph-base/trustgraph/api/api.py` + +**Classe de API Aprimorada:** + +```python +class Api: + def __init__(self, url: str, timeout: int = 60, token: Optional[str] = None): + self.url = url + self.timeout = timeout + self.token = token # Optional bearer token for REST, query param for WebSocket + self._socket_client = None + self._bulk_client = None + self._async_flow = None + self._async_socket_client = None + self._async_bulk_client = None + + # Existing synchronous methods (unchanged) + def flow(self) -> Flow: + """Synchronous REST-based flow interface""" + pass + + def library(self) -> Library: + """Synchronous REST-based library interface""" + pass + + def knowledge(self) -> Knowledge: + """Synchronous REST-based knowledge interface""" + pass + + def collection(self) -> Collection: + """Synchronous REST-based collection interface""" + pass + + def config(self) -> Config: + """Synchronous REST-based config interface""" + pass + + # New synchronous methods + def socket(self) -> SocketClient: + """Synchronous WebSocket-based interface for streaming operations""" + if self._socket_client is None: + self._socket_client = SocketClient(self.url, self.timeout, self.token) + return self._socket_client + + def bulk(self) -> BulkClient: + """Synchronous bulk operations interface for import/export""" + if self._bulk_client is None: + self._bulk_client = BulkClient(self.url, self.timeout, self.token) + return self._bulk_client + + def metrics(self) -> Metrics: + """Synchronous metrics interface""" + return Metrics(self.url, self.timeout, self.token) + + # New asynchronous methods + def async_flow(self) -> AsyncFlow: + """Asynchronous REST-based flow interface""" + if self._async_flow is None: + self._async_flow = AsyncFlow(self.url, self.timeout, self.token) + return self._async_flow + + def async_socket(self) -> AsyncSocketClient: + """Asynchronous WebSocket-based interface for streaming operations""" + if self._async_socket_client is None: + self._async_socket_client = AsyncSocketClient(self.url, self.timeout, self.token) + return self._async_socket_client + + def async_bulk(self) -> AsyncBulkClient: + """Asynchronous bulk operations interface for import/export""" + if self._async_bulk_client is None: + self._async_bulk_client = AsyncBulkClient(self.url, self.timeout, self.token) + return self._async_bulk_client + + def async_metrics(self) -> AsyncMetrics: + """Asynchronous metrics interface""" + return AsyncMetrics(self.url, self.timeout, self.token) + + # Resource management + def close(self) -> None: + """Close all synchronous connections""" + if self._socket_client: + self._socket_client.close() + if self._bulk_client: + self._bulk_client.close() + + async def aclose(self) -> None: + """Close all asynchronous connections""" + if self._async_socket_client: + await self._async_socket_client.aclose() + if self._async_bulk_client: + await self._async_bulk_client.aclose() + if self._async_flow: + await self._async_flow.aclose() + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + async def __aenter__(self): + return self + + async def __aexit__(self, *args): + await self.aclose() +``` + +#### 2. Cliente WebSocket Síncrono + +Módulo: `trustgraph-base/trustgraph/api/socket_client.py` (novo) + +**Classe SocketClient**: + +```python +class SocketClient: + """Synchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> SocketFlowInstance: + """Get flow instance for WebSocket operations""" + return SocketFlowInstance(self, flow_id) + + def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Uses asyncio.run() internally to wrap async websockets library + pass + + def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + # Synchronous wrapper around async WebSocket calls + pass + + def close(self) -> None: + """Close WebSocket connection""" + pass + +class SocketFlowInstance: + """Synchronous WebSocket flow instance with same interface as REST FlowInstance""" + def __init__(self, client: SocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance + def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, Iterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**Principais Características:** +Conexão preguiçosa (conecta apenas quando o primeiro pedido é enviado) +Multiplexação de requisições (até 15 simultâneas) +Reconexão automática em caso de desconexão +Análise de resposta em streaming +Operação thread-safe +Wrapper síncrono em torno da biblioteca assíncrona de WebSockets + +#### 3. Cliente WebSocket Assíncrono + +Módulo: `trustgraph-base/trustgraph/api/async_socket_client.py` (novo) + +**Classe AsyncSocketClient:** + +```python +class AsyncSocketClient: + """Asynchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> AsyncSocketFlowInstance: + """Get async flow instance for WebSocket operations""" + return AsyncSocketFlowInstance(self, flow_id) + + async def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Native async websockets library + pass + + async def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + pass + + async def aclose(self) -> None: + """Close WebSocket connection""" + pass + +class AsyncSocketFlowInstance: + """Asynchronous WebSocket flow instance""" + def __init__(self, client: AsyncSocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance (but async) + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, AsyncIterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**Principais Características:** +Suporte nativo para async/await +Eficiente para aplicações assíncronas (FastAPI, aiohttp) +Sem bloqueio de threads +Mesma interface da versão síncrona +AsyncIterator para streaming + +#### 4. Cliente de Operações em Lote Síncronas + +Módulo: `trustgraph-base/trustgraph/api/bulk_client.py` (novo) + +**Classe BulkClient:** + +```python +class BulkClient: + """Synchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + def import_triples( + self, + flow: str, + triples: Iterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + def export_triples( + self, + flow: str, + **kwargs + ) -> Iterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + def import_graph_embeddings( + self, + flow: str, + embeddings: Iterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> Iterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + def close(self) -> None: + """Close connections""" + pass +``` + +**Principais Características:** +Baseado em iteradores para uso constante de memória. +Conexões WebSocket dedicadas por operação. +Rastreamento de progresso (callback opcional). +Tratamento de erros com relatórios de sucesso parcial. + +#### 5. Cliente de Operações em Massa Assíncronas + +Módulo: `trustgraph-base/trustgraph/api/async_bulk_client.py` (novo) + +**Classe AsyncBulkClient:** + +```python +class AsyncBulkClient: + """Asynchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + async def import_triples( + self, + flow: str, + triples: AsyncIterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + async def export_triples( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + async def import_graph_embeddings( + self, + flow: str, + embeddings: AsyncIterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + async def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + async def aclose(self) -> None: + """Close connections""" + pass +``` + +**Principais Características:** +Baseado em AsyncIterator para uso constante de memória +Eficiente para aplicações assíncronas +Suporte nativo para async/await +Mesma interface da versão síncrona + +#### 6. API REST Flow (Síncrona - Inalterada) + +Módulo: `trustgraph-base/trustgraph/api/flow.py` + +A API REST Flow permanece **completamente inalterada** para compatibilidade com versões anteriores. Todos os métodos existentes continuam a funcionar: + +`Flow.list()`, `Flow.start()`, `Flow.stop()`, etc. +`FlowInstance.agent()`, `FlowInstance.text_completion()`, `FlowInstance.graph_rag()`, etc. +Todas as assinaturas e tipos de retorno existentes preservados + +**Novo:** Adicione `graph_embeddings_query()` a REST FlowInstance para paridade de recursos: + +```python +class FlowInstance: + # All existing methods unchanged... + + # New: Graph embeddings query (REST) + def graph_embeddings_query( + self, + text: str, + user: str, + collection: str, + limit: int = 10, + **kwargs + ) -> List[Dict[str, Any]]: + """Query graph embeddings for semantic search""" + # Calls POST /api/v1/flow/{flow}/service/graph-embeddings + pass +``` + +#### 7. API de Fluxo REST Assíncrono + +Módulo: `trustgraph-base/trustgraph/api/async_flow.py` (novo) + +**Classes AsyncFlow e AsyncFlowInstance:** + +```python +class AsyncFlow: + """Asynchronous REST-based flow interface""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def list(self) -> List[Dict[str, Any]]: + """List all flows""" + pass + + async def get(self, id: str) -> Dict[str, Any]: + """Get flow definition""" + pass + + async def start(self, class_name: str, id: str, description: str, parameters: Dict) -> None: + """Start a flow""" + pass + + async def stop(self, id: str) -> None: + """Stop a flow""" + pass + + def id(self, flow_id: str) -> AsyncFlowInstance: + """Get async flow instance""" + return AsyncFlowInstance(self.url, self.timeout, self.token, flow_id) + + async def aclose(self) -> None: + """Close connection""" + pass + +class AsyncFlowInstance: + """Asynchronous REST flow instance""" + + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + **kwargs + ) -> Dict[str, Any]: + """Async agent execution""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + **kwargs + ) -> str: + """Async text completion""" + pass + + async def graph_rag( + self, + question: str, + user: str, + collection: str, + **kwargs + ) -> str: + """Async graph RAG""" + pass + + # ... all other FlowInstance methods as async versions +``` + +**Principais Características:** +HTTP assíncrono nativo usando `aiohttp` ou `httpx` +Mesmas assinaturas de método da API REST síncrona +Sem streaming (use `async_socket()` para streaming) +Eficiente para aplicações assíncronas + +#### 8. API de Métricas + +Módulo: `trustgraph-base/trustgraph/api/metrics.py` (novo) + +**Métricas Síncronas:** + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +**Métricas Assíncronas**: + +```python +class AsyncMetrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +#### 9. Tipos Aprimorados + +Módulo: `trustgraph-base/trustgraph/api/types.py` (modificado) + +**Novos Tipos**: + +```python +from typing import Iterator, Union, Dict, Any +import dataclasses + +@dataclasses.dataclass +class StreamingChunk: + """Base class for streaming chunks""" + content: str + end_of_message: bool = False + +@dataclasses.dataclass +class AgentThought(StreamingChunk): + """Agent reasoning chunk""" + chunk_type: str = "thought" + +@dataclasses.dataclass +class AgentObservation(StreamingChunk): + """Agent tool observation chunk""" + chunk_type: str = "observation" + +@dataclasses.dataclass +class AgentAnswer(StreamingChunk): + """Agent final answer chunk""" + chunk_type: str = "final-answer" + end_of_dialog: bool = False + +@dataclasses.dataclass +class RAGChunk(StreamingChunk): + """RAG streaming chunk""" + end_of_stream: bool = False + error: Optional[Dict[str, str]] = None + +# Type aliases for clarity +AgentStream = Iterator[Union[AgentThought, AgentObservation, AgentAnswer]] +RAGStream = Iterator[RAGChunk] +CompletionStream = Iterator[str] +``` + +#### 6. API de Métricas + +Módulo: `trustgraph-base/trustgraph/api/metrics.py` (novo) + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +### Abordagem de Implementação + +#### Fase 1: Aprimoramento da API Central (Semana 1) + +1. Adicionar métodos `socket()`, `bulk()` e `metrics()` à classe `Api` +2. Implementar inicialização preguiçosa para clientes WebSocket e em lote +3. Adicionar suporte a gerenciador de contexto (`__enter__`, `__exit__`) +4. Adicionar método `close()` para limpeza +5. Adicionar testes unitários para aprimoramentos da classe da API +6. Verificar compatibilidade com versões anteriores + +**Compatibilidade com versões anteriores**: Nenhuma alteração disruptiva. Apenas novos métodos. + +#### Fase 2: Cliente WebSocket (Semana 2-3) + +1. Implementar classe `SocketClient` com gerenciamento de conexão +2. Implementar `SocketFlowInstance` com as mesmas assinaturas de método de `FlowInstance` +3. Adicionar suporte para multiplexação de solicitações (até 15 simultâneas) +4. Adicionar análise de resposta em streaming para diferentes tipos de fragmentos +5. Adicionar lógica de reconexão automática +6. Adicionar testes unitários e de integração +7. Documentar padrões de uso do WebSocket + +**Compatibilidade com versões anteriores**: Nova interface apenas. Sem impacto no código existente. + +#### Fase 3: Suporte a Streaming (Semana 3-4) + +1. Adicionar classes de tipo de fragmento de streaming (`AgentThought`, `AgentObservation`, `AgentAnswer`, `RAGChunk`) +2. Implementar análise de resposta em streaming em `SocketClient` +3. Adicionar parâmetro de streaming a todos os métodos LLM em `SocketFlowInstance` +4. Lidar com casos de erro durante o streaming +5. Adicionar testes unitários e de integração para streaming +6. Adicionar exemplos de streaming à documentação + +**Compatibilidade com versões anteriores**: Nova interface apenas. API REST existente inalterada. + +#### Fase 4: Operações em Lote (Semana 4-5) + +1. Implementar classe `BulkClient` +2. Adicionar métodos de importação/exportação em lote para triplas, incorporações, contextos, objetos +3. Implementar processamento baseado em iterador para uso de memória constante +4. Adicionar rastreamento de progresso (callback opcional) +5. Adicionar tratamento de erros com relatório de sucesso parcial +6. Adicionar testes unitários e de integração +7. Adicionar exemplos de operações em lote + +**Compatibilidade com versões anteriores**: Nova interface apenas. Sem impacto no código existente. + +#### Fase 5: Paridade de Recursos e Refinamento (Semana 5) + +1. Adicionar `graph_embeddings_query()` ao REST `FlowInstance` +2. Implementar classe `Metrics` +3. Adicionar testes de integração abrangentes +4. Teste de desempenho +5. Atualizar toda a documentação +6. Criar guia de migração + +**Compatibilidade com versões anteriores**: Novos métodos apenas. Sem impacto no código existente. + +### Modelos de Dados + +#### Seleção de Interface + +```python +# Single API instance, same URL for all interfaces +api = Api(url="http://localhost:8088/") + +# Synchronous interfaces +rest_flow = api.flow().id("default") # Sync REST +socket_flow = api.socket().flow("default") # Sync WebSocket +bulk = api.bulk() # Sync bulk operations +metrics = api.metrics() # Sync metrics + +# Asynchronous interfaces +async_rest_flow = api.async_flow().id("default") # Async REST +async_socket_flow = api.async_socket().flow("default") # Async WebSocket +async_bulk = api.async_bulk() # Async bulk operations +async_metrics = api.async_metrics() # Async metrics +``` + +#### Tipos de Resposta de Streaming + +**Streaming do Agente**: + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - non-streaming (same signature) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - streaming (new) +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentThought): + print(f"Thinking: {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"Observed: {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"Answer: {chunk.content}") + if chunk.end_of_dialog: + break +``` + +**Streaming RAG**: + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.graph_rag(question="What is Python?", user="user123", collection="default") +print(response) + +# WebSocket interface - streaming (new) +socket_flow = api.socket().flow("default") +for chunk in socket_flow.graph_rag( + question="What is Python?", + user="user123", + collection="default", + streaming=True +): + print(chunk.content, end="", flush=True) + if chunk.end_of_stream: + break +``` + +**Operações em Lote (Síncronas):** + +```python +api = Api(url="http://localhost:8088/") + +# Bulk import triples +def triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Bulk export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +**Operações em Lote (Assíncronas):** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async bulk import triples + async def async_triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + + # Async bulk export triples + async for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") + +asyncio.run(main()) +``` + +**Exemplo de REST Assíncrono:** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST flow operations + flow = api.async_flow().id("default") + response = await flow.agent(question="What is ML?", user="user123") + print(response["response"]) + +asyncio.run(main()) +``` + +**Exemplo de Streaming WebSocket Assíncrono:** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async WebSocket streaming + socket = api.async_socket() + flow = socket.flow("default") + + async for chunk in flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) + if chunk.end_of_dialog: + break + +asyncio.run(main()) +``` + +### APIs + +#### New APIs + +1. **Classe de API Core**: + **Síncrono**: + `Api.socket()` - Obter cliente WebSocket síncrono + `Api.bulk()` - Obter cliente de operações em lote síncrono + `Api.metrics()` - Obter cliente de métricas síncrono + `Api.close()` - Fechar todas as conexões síncronas + Suporte a gerenciador de contexto (`__enter__`, `__exit__`) + **Assíncrono**: + `Api.async_flow()` - Obter cliente de fluxo REST assíncrono + `Api.async_socket()` - Obter cliente WebSocket assíncrono + `Api.async_bulk()` - Obter cliente de operações em lote assíncrono + `Api.async_metrics()` - Obter cliente de métricas assíncrono + `Api.aclose()` - Fechar todas as conexões assíncronas + Suporte a gerenciador de contexto assíncrono (`__aenter__`, `__aexit__`) + +2. **Cliente WebSocket Síncrono**: + `SocketClient.flow(flow_id)` - Obter instância de fluxo WebSocket + `SocketFlowInstance.agent(..., streaming: bool = False)` - Agente com streaming opcional + `SocketFlowInstance.text_completion(..., streaming: bool = False)` - Conclusão de texto com streaming opcional + `SocketFlowInstance.graph_rag(..., streaming: bool = False)` - Graph RAG com streaming opcional + `SocketFlowInstance.document_rag(..., streaming: bool = False)` - Document RAG com streaming opcional + `SocketFlowInstance.prompt(..., streaming: bool = False)` - Prompt com streaming opcional + `SocketFlowInstance.graph_embeddings_query()` - Consulta de embeddings de grafo + Todos os outros métodos FlowInstance com assinaturas idênticas + +3. **Cliente WebSocket Assíncrono**: + `AsyncSocketClient.flow(flow_id)` - Obter instância de fluxo WebSocket assíncrono + `AsyncSocketFlowInstance.agent(..., streaming: bool = False)` - Agente assíncrono com streaming opcional + `AsyncSocketFlowInstance.text_completion(..., streaming: bool = False)` - Conclusão de texto assíncrona com streaming opcional + `AsyncSocketFlowInstance.graph_rag(..., streaming: bool = False)` - Graph RAG assíncrono com streaming opcional + `AsyncSocketFlowInstance.document_rag(..., streaming: bool = False)` - Document RAG assíncrono com streaming opcional + `AsyncSocketFlowInstance.prompt(..., streaming: bool = False)` - Prompt assíncrono com streaming opcional + `AsyncSocketFlowInstance.graph_embeddings_query()` - Consulta de embeddings de grafo assíncrona + Todos os outros métodos FlowInstance como versões assíncronas + +4. **Cliente de Operações em Lote Síncrono**: + `BulkClient.import_triples(flow, triples)` - Importação em lote de triplas + `BulkClient.export_triples(flow)` - Exportação em lote de triplas + `BulkClient.import_graph_embeddings(flow, embeddings)` - Importação em lote de embeddings de grafo + `BulkClient.export_graph_embeddings(flow)` - Exportação em lote de embeddings de grafo + `BulkClient.import_document_embeddings(flow, embeddings)` - Importação em lote de embeddings de documentos + `BulkClient.export_document_embeddings(flow)` - Exportação em lote de embeddings de documentos + `BulkClient.import_entity_contexts(flow, contexts)` - Importação em lote de contextos de entidades + `BulkClient.export_entity_contexts(flow)` - Exportação em lote de contextos de entidades + `BulkClient.import_objects(flow, objects)` - Importação em lote de objetos + +5. **Cliente de Operações em Lote Assíncrono**: + `AsyncBulkClient.import_triples(flow, triples)` - Importação assíncrona em lote de triplas + `AsyncBulkClient.export_triples(flow)` - Exportação assíncrona em lote de triplas + `AsyncBulkClient.import_graph_embeddings(flow, embeddings)` - Importação assíncrona em lote de embeddings de grafo + `AsyncBulkClient.export_graph_embeddings(flow)` - Exportação assíncrona em lote de embeddings de grafo + `AsyncBulkClient.import_document_embeddings(flow, embeddings)` - Importação assíncrona em lote de embeddings de documentos + `AsyncBulkClient.export_document_embeddings(flow)` - Exportação assíncrona em lote de embeddings de documentos + `AsyncBulkClient.import_entity_contexts(flow, contexts)` - Importação assíncrona em lote de contextos de entidades + `AsyncBulkClient.export_entity_contexts(flow)` - Exportação assíncrona em lote de contextos de entidades + `AsyncBulkClient.import_objects(flow, objects)` - Importação assíncrona em lote de objetos + +6. **Cliente de Fluxo REST Assíncrono**: + `AsyncFlow.list()` - Listar todos os fluxos de forma assíncrona + `AsyncFlow.get(id)` - Obter definição de fluxo de forma assíncrona + `AsyncFlow.start(...)` - Iniciar fluxo de forma assíncrona + `AsyncFlow.stop(id)` - Parar fluxo de forma assíncrona + `AsyncFlow.id(flow_id)` - Obter instância de fluxo de forma assíncrona + `AsyncFlowInstance.agent(...)` - Execução de agente assíncrona + `AsyncFlowInstance.text_completion(...)` - Conclusão de texto assíncrona + `AsyncFlowInstance.graph_rag(...)` - Graph RAG assíncrono + Todos os outros métodos FlowInstance como versões assíncronas + +7. **Clientes de Métricas**: + `Metrics.get()` - Métricas Prometheus síncronas + `AsyncMetrics.get()` - Métricas Prometheus assíncronas + +8. **Aprimoramento da API de Fluxo REST**: + `FlowInstance.graph_embeddings_query()` - Consulta de embeddings de grafo (paridade de recursos síncrona) + `AsyncFlowInstance.graph_embeddings_query()` - Consulta de embeddings de grafo (paridade de recursos assíncrona) + +#### APIs Modificadas + +1. **Construtor** (melhoria menor): + ```python + Api(url: str, timeout: int = 60, token: Optional[str] = None) + ``` + Adicionado parâmetro `token` (opcional, para autenticação) + Se `None` (padrão): Nenhuma autenticação utilizada + Se especificado: Usado como token bearer para REST (`Authorization: Bearer `), parâmetro de consulta para WebSocket (`?token=`) + Nenhuma outra alteração - totalmente compatível com versões anteriores + +2. **Nenhuma Alteração Significativa**: + Todos os métodos da API REST existentes permanecem inalterados + Todas as assinaturas existentes são preservadas + Todos os tipos de retorno existentes são preservados + +### Detalhes da Implementação + +#### Tratamento de Erros + +**Erros de Conexão WebSocket**: +```python +try: + api = Api(url="http://localhost:8088/") + socket = api.socket() + socket_flow = socket.flow("default") + response = socket_flow.agent(question="...", user="user123") +except ConnectionError as e: + print(f"WebSocket connection failed: {e}") + print("Hint: Ensure Gateway is running and WebSocket endpoint is accessible") +``` + +**Fallback Elegante**: +```python +api = Api(url="http://localhost:8088/") + +try: + # Try WebSocket streaming first + socket_flow = api.socket().flow("default") + for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk.content) +except ConnectionError: + # Fall back to REST non-streaming + print("WebSocket unavailable, falling back to REST") + rest_flow = api.flow().id("default") + response = rest_flow.agent(question="...", user="...") + print(response["response"]) +``` + +**Erros de Streaming Parcial:** +```python +api = Api(url="http://localhost:8088/") +socket_flow = api.socket().flow("default") + +accumulated = [] +try: + for chunk in socket_flow.graph_rag(question="...", streaming=True): + accumulated.append(chunk.content) + if chunk.error: + print(f"Error occurred: {chunk.error}") + print(f"Partial response: {''.join(accumulated)}") + break +except Exception as e: + print(f"Streaming error: {e}") + print(f"Partial response: {''.join(accumulated)}") +``` + +#### Gerenciamento de Recursos + +**Suporte a Gerenciadores de Contexto**: +```python +# Automatic cleanup +with Api(url="http://localhost:8088/") as api: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +# All connections automatically closed + +# Manual cleanup +api = Api(url="http://localhost:8088/") +try: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +finally: + api.close() # Explicitly close all connections (WebSocket, bulk, etc.) +``` + +#### Threads e Concorrência + +**Segurança de Threads**: +Cada instância de `Api` mantém sua própria conexão. +O transporte WebSocket usa bloqueios para multiplexação de solicitações com segurança de thread. +Múltiplas threads podem compartilhar uma instância de `Api` com segurança. +Iteradores de streaming não são seguros para threads (consumir de uma única thread). + +**Suporte Assíncrono** (consideração futura): +```python +# Phase 2 enhancement (not in initial scope) +import asyncio + +async def main(): + api = await AsyncApi(url="ws://localhost:8088/") + flow = api.flow().id("default") + + async for chunk in flow.agent(question="...", streaming=True): + print(chunk.content) + + await api.close() + +asyncio.run(main()) +``` + +## Considerações de Segurança + +### Autenticação + +**Parâmetro de Token**: +```python +# No authentication (default) +api = Api(url="http://localhost:8088/") + +# With authentication +api = Api(url="http://localhost:8088/", token="mytoken") +``` + +**Transporte REST**: +Token do transportador via cabeçalho `Authorization` +Aplicado automaticamente a todas as requisições REST +Formato: `Authorization: Bearer ` + +**Transporte WebSocket**: +Token via parâmetro de consulta anexado à URL do WebSocket +Aplicado automaticamente durante o estabelecimento da conexão +Formato: `ws://localhost:8088/api/v1/socket?token=` + +**Implementação**: +```python +class SocketClient: + def _connect(self) -> WebSocket: + # Construct WebSocket URL with optional token + ws_url = f"{self.url}/api/v1/socket" + if self.token: + ws_url = f"{ws_url}?token={self.token}" + # Connect to WebSocket + return websocket.connect(ws_url) +``` + +**Exemplo**: +```python +# REST with auth +api = Api(url="http://localhost:8088/", token="mytoken") +flow = api.flow().id("default") +# All REST calls include: Authorization: Bearer mytoken + +# WebSocket with auth +socket = api.socket() +# Connects to: ws://localhost:8088/api/v1/socket?token=mytoken +``` + +### Comunicação Segura + +Suporta os esquemas WS (WebSocket) e WSS (WebSocket Secure). +Validação de certificado TLS para conexões WSS. +Verificação de certificado opcional para desenvolvimento (com aviso). + +### Validação de Entrada + +Valida esquemas de URL (http, https, ws, wss). +Valida valores de parâmetros de transporte. +Valida combinações de parâmetros de streaming. +Valida tipos de dados para importação em lote. + +## Considerações de Desempenho + +### Melhorias de Latência + +**Operações LLM em Streaming**: +**Tempo para o primeiro token**: ~500ms (vs ~30s sem streaming) +**Melhoria**: 60 vezes mais rápido em termos de desempenho percebido. +**Aplicável a**: Agente, Graph RAG, Document RAG, Geração de Texto, Prompt. + +**Conexões Persistentes**: +**Sobrecarga de conexão**: Eliminada para solicitações subsequentes. +**Handshake WebSocket**: Custo único (~100ms). +**Aplicável a**: Todas as operações ao usar o transporte WebSocket. + +### Melhorias de Throughput + +**Operações em Lote**: +**Importação de triplas**: ~10.000 triplas/segundo (vs ~100/segundo com REST por item). +**Importação de embeddings**: ~5.000 embeddings/segundo (vs ~50/segundo com REST por item). +**Melhoria**: 100 vezes mais rápido para operações em lote. + +**Multiplexação de Requisições**: +**Requisições concorrentes**: Até 15 requisições simultâneas sobre uma única conexão. +**Reutilização de conexão**: Sem sobrecarga de conexão para operações concorrentes. + +### Considerações de Memória + +**Respostas em Streaming**: +Uso constante de memória (processa os chunks à medida que chegam). +Sem bufferização da resposta completa. +Adequado para saídas muito longas (>1MB). + +**Operações em Lote**: +Processamento baseado em iterador (uso constante de memória). +Sem carregamento do conjunto de dados inteiro na memória. +Adequado para conjuntos de dados com milhões de itens. + +### Benchmarks (Esperados) + +| Operação | REST (existente) | WebSocket (streaming) | Melhoria | +|-----------|----------------|----------------------|-------------| +| Agente (tempo para o primeiro token) | 30s | 0.5s | 60x | +| Graph RAG (tempo para o primeiro token) | 25s | 0.5s | 50x | +| Importação de 10K triplas | 100s | 1s | 100x | +| Importação de 1M triplas | 10.000s (2.7h) | 100s (1.6m) | 100x | +| 10 requisições pequenas concorrentes | 5s (sequencial) | 0.5s (paralelo) | 10x | + +## Estratégia de Testes + +### Testes Unitários + +**Camada de Transporte** (`test_transport.py`): +Testar requisição/resposta de transporte REST +Testar conexão de transporte WebSocket +Testar reconexão de transporte WebSocket +Testar multiplexação de requisições +Testar análise de resposta em streaming +Simular um servidor WebSocket para testes determinísticos + +**Métodos da API** (`test_flow.py`, `test_library.py`, etc.): +Testar novos métodos com transporte simulado +Testar tratamento de parâmetros em streaming +Testar iteradores de operações em lote +Testar tratamento de erros + +**Tipos** (`test_types.py`): +Testar novos tipos de fragmentos em streaming +Testar serialização/desserialização de tipos + +### Testes de Integração + +**REST de Ponta a Ponta** (`test_integration_rest.py`): +Testar todas as operações contra o Gateway real (modo REST) +Verificar compatibilidade com versões anteriores +Testar condições de erro + +**WebSocket de Ponta a Ponta** (`test_integration_websocket.py`): +Testar todas as operações contra o Gateway real (modo WebSocket) +Testar operações de streaming +Testar operações em lote +Testar requisições concorrentes +Testar recuperação de conexão + +**Serviços de Streaming** (`test_streaming_integration.py`): +Testar streaming de agentes (pensamentos, observações, respostas) +Testar streaming RAG (fragmentos incrementais) +Testar streaming de conclusão de texto (token por token) +Testar streaming de prompts +Testar tratamento de erros durante o streaming + +**Operações em Lote** (`test_bulk_integration.py`): +Testar importação/exportação em lote de triplas (1K, 10K, 100K itens) +Testar importação/exportação em lote de embeddings +Testar o uso de memória durante operações em lote +Testar o rastreamento de progresso + +### Testes de Desempenho + +**Benchmarks de Latência** (`test_performance_latency.py`): +Medir o tempo para o primeiro token (streaming vs não streaming) +Medir a sobrecarga de conexão (REST vs WebSocket) +Comparar com benchmarks esperados + +**Benchmarks de Throughput** (`test_performance_throughput.py`): +Medir o throughput de importação em lote +Medir a eficiência da multiplexação de requisições +Comparar com benchmarks esperados + +### Testes de Compatibilidade + +**Compatibilidade com Versões Anteriores** (`test_backward_compatibility.py`): +Executar o conjunto de testes existente contra a API refatorada +Verificar a ausência de alterações que quebrem a compatibilidade +Testar o caminho de migração para padrões comuns + +## Plano de Migração + +### Fase 1: Migração Transparente (Padrão) + +**Não são necessárias alterações no código**. O código existente continua a funcionar: + +```python +# Existing code works unchanged +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") +response = flow.agent(question="What is ML?", user="user123") +``` + +### Fase 2: Streaming Opcional (Simples) + +**Use a interface `api.socket()`** para habilitar o streaming: + +```python +# Before: Non-streaming REST +api = Api(url="http://localhost:8088/") +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# After: Streaming WebSocket (same parameters!) +api = Api(url="http://localhost:8088/") # Same URL +socket_flow = api.socket().flow("default") + +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) +``` + +**Pontos-chave:** +Mesma URL para REST e WebSocket +Mesmas assinaturas de método (fácil migração) +Basta adicionar `.socket()` e `streaming=True` + +### Fase 3: Operações em Lote (Nova Funcionalidade) + +**Use a interface `api.bulk()`** para grandes conjuntos de dados: + +```python +# Before: Inefficient per-item operations +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") + +for triple in my_large_triple_list: + # Slow per-item operations + # (no direct bulk insert in REST API) + pass + +# After: Efficient bulk loading +api = Api(url="http://localhost:8088/") # Same URL +bulk = api.bulk() + +# This is fast (10,000 triples/second) +bulk.import_triples(flow="default", triples=iter(my_large_triple_list)) +``` + +### Atualizações na Documentação + +1. **README.md**: Adicionar exemplos de streaming e WebSocket +2. **Referência da API**: Documentar todos os novos métodos e parâmetros +3. **Guia de Migração**: Guia passo a passo para habilitar o streaming +4. **Exemplos**: Adicionar scripts de exemplo para padrões comuns +5. **Guia de Desempenho**: Documentar as melhorias de desempenho esperadas + +### Política de Descontinuação + +**Nenhuma descontinuação**. Todas as APIs existentes permanecem suportadas. Esta é uma melhoria pura. + +## Cronograma + +### Semana 1: Fundação +Camada de abstração de transporte +Refatorar o código REST existente +Testes unitários para a camada de transporte +Verificação de compatibilidade com versões anteriores + +### Semana 2: Transporte WebSocket +Implementação do transporte WebSocket +Gerenciamento de conexão e reconexão +Multiplexação de requisições +Testes unitários e de integração + +### Semana 3: Suporte a Streaming +Adicionar parâmetro de streaming aos métodos LLM +Implementar análise de resposta de streaming +Adicionar tipos de fragmentos de streaming +Testes de integração de streaming + +### Semana 4: Operações em Lote +Adicionar métodos de importação/exportação em lote +Implementar operações baseadas em iteradores +Testes de desempenho +Testes de integração de operações em lote + +### Semana 5: Paridade de Recursos e Documentação +Adicionar consulta de incorporações de grafos +Adicionar API de métricas +Documentação abrangente +Guia de migração +Versão candidata + +### Semana 6: Lançamento +Testes de integração finais +Benchmarking de desempenho +Documentação de lançamento +Anúncio para a comunidade + +**Duração Total**: 6 semanas + +## Perguntas Abertas + +### Perguntas de Design da API + +1. **Suporte Assíncrono**: ✅ **RESOLVIDO** - Suporte assíncrono completo incluído no lançamento inicial + Todas as interfaces possuem variantes assíncronas: `async_flow()`, `async_socket()`, `async_bulk()`, `async_metrics()` + Fornece total simetria entre as APIs síncronas e assíncronas + Essencial para frameworks assíncronos modernos (FastAPI, aiohttp) + +2. **Rastreamento de Progresso**: As operações em lote devem suportar callbacks de progresso? + ```python + def progress_callback(processed: int, total: Optional[int]): + print(f"Processed {processed} items") + + bulk.import_triples(flow="default", triples=triples, on_progress=progress_callback) + ``` + **Recomendação**: Adicionar na Fase 2. Não é crítico para a versão inicial. + +3. **Tempo Limite de Streaming**: Como devemos tratar os tempos limite para operações de streaming? + **Recomendação**: Usar o mesmo tempo limite que as operações não-streaming, mas resetar a cada bloco recebido. + +4. **Bufferização de Blocos**: Devemos bufferizar os blocos ou retornar imediatamente? + **Recomendação**: Retornar imediatamente para a menor latência. + +5. **Serviços Globais via WebSocket**: `api.socket()` deve suportar serviços globais (biblioteca, conhecimento, coleção, configuração) ou apenas serviços específicos do fluxo? + **Recomendação**: Começar apenas com serviços específicos do fluxo (onde o streaming é importante). Adicionar serviços globais, se necessário, na Fase 2. + +### Perguntas de Implementação + +1. **Biblioteca WebSocket**: Devemos usar `websockets`, `websocket-client` ou `aiohttp`? + **Recomendação**: `websockets` (assíncrono, maduro, bem mantido). Envolver em uma interface síncrona usando `asyncio.run()`. + +2. **Pool de Conexões**: Devemos suportar múltiplas instâncias concorrentes de `Api` compartilhando um pool de conexões? + **Recomendação**: Adiar para a Fase 2. Cada instância de `Api` terá suas próprias conexões inicialmente. + +3. **Reutilização de Conexões**: `SocketClient` e `BulkClient` devem compartilhar a mesma conexão WebSocket, ou usar conexões separadas? + **Recomendação**: Conexões separadas. Implementação mais simples, separação mais clara de responsabilidades. + +4. **Conexão Preguiçosa vs. Ansiosa**: A conexão WebSocket deve ser estabelecida em `api.socket()` ou na primeira requisição? + **Recomendação**: Preguiçosa (na primeira requisição). Evita a sobrecarga da conexão se o usuário usar apenas métodos REST. + +### Perguntas de Teste + +1. **Gateway Mock**: Devemos criar um Gateway mock leve para testes, ou testar contra o Gateway real? + **Recomendação**: Ambos. Usar mocks para testes unitários, Gateway real para testes de integração. + +2. **Testes de Regressão de Desempenho**: Devemos adicionar testes de regressão de desempenho automatizados ao CI? + **Recomendação**: Sim, mas com limites generosos para levar em conta a variabilidade do ambiente do CI. + +## Referências + +### Especificações Técnicas Relacionadas +`docs/tech-specs/streaming-llm-responses.md` - Implementação de streaming no Gateway +`docs/tech-specs/rag-streaming-support.md` - Suporte de streaming RAG + +### Arquivos de Implementação +`trustgraph-base/trustgraph/api/` - Código fonte da API Python +`trustgraph-flow/trustgraph/gateway/` - Código fonte do Gateway +`trustgraph-flow/trustgraph/gateway/dispatch/mux.py` - Implementação de referência de multiplexador WebSocket + +### Documentação +`docs/apiSpecification.md` - Referência completa da API +`docs/api-status-summary.md` - Resumo do status da API +`README.websocket` - Documentação do protocolo WebSocket +`STREAMING-IMPLEMENTATION-NOTES.txt` - Notas sobre a implementação de streaming + +### Bibliotecas Externas +`websockets` - Biblioteca WebSocket Python (https://websockets.readthedocs.io/) +`requests` - Biblioteca HTTP Python (existente) diff --git a/docs/tech-specs/python-api-refactor.ru.md b/docs/tech-specs/python-api-refactor.ru.md new file mode 100644 index 00000000..53018a9f --- /dev/null +++ b/docs/tech-specs/python-api-refactor.ru.md @@ -0,0 +1,1508 @@ +# Python API Refactor Technical Specification + +## Overview + +This specification describes a comprehensive refactor of the TrustGraph Python API client library to achieve feature parity with the API Gateway and add support for modern real-time communication patterns. + +The refactor addresses four primary use cases: + +1. **Streaming LLM Interactions**: Enable real-time streaming of LLM responses (agent, graph RAG, document RAG, text completion, prompts) with ~60x lower latency (500ms vs 30s for first token) +2. **Bulk Data Operations**: Support efficient bulk import/export of triples, graph embeddings, and document embeddings for large-scale knowledge graph management +3. **Feature Parity**: Ensure every API Gateway endpoint has a corresponding Python API method, including graph embeddings query +4. **Persistent Connections**: Enable WebSocket-based communication for multiplexed requests and reduced connection overhead + +## Goals + +**Feature Parity**: Every Gateway API service has a corresponding Python API method +**Streaming Support**: All streaming-capable services (agent, RAG, text completion, prompt) support streaming in Python API +**WebSocket Transport**: Add optional WebSocket transport layer for persistent connections and multiplexing +**Bulk Operations**: Add efficient bulk import/export for triples, graph embeddings, and document embeddings +**Full Async Support**: Complete async/await implementation for all interfaces (REST, WebSocket, bulk operations, metrics) +**Backward Compatibility**: Existing code continues to work without modification +**Type Safety**: Maintain type-safe interfaces with dataclasses and type hints +**Progressive Enhancement**: Streaming and async are opt-in via explicit interface selection +**Performance**: Achieve 60x latency improvement for streaming operations +**Modern Python**: Support for both sync and async paradigms for maximum flexibility + +## Background + +### Current State + +The Python API (`trustgraph-base/trustgraph/api/`) is a REST-only client library with the following modules: + +`flow.py`: Flow management and flow-scoped services (50 methods) +`library.py`: Document library operations (9 methods) +`knowledge.py`: KG core management (4 methods) +`collection.py`: Collection metadata (3 methods) +`config.py`: Configuration management (6 methods) +`types.py`: Data type definitions (5 dataclasses) + +**Total Operations**: 50/59 (85% coverage) + +### Current Limitations + +**Missing Operations**: +Graph embeddings query (semantic search over graph entities) +Bulk import/export for triples, graph embeddings, document embeddings, entity contexts, objects +Metrics endpoint + +**Missing Capabilities**: +Streaming support for LLM services +WebSocket transport +Multiplexed concurrent requests +Persistent connections + +**Performance Issues**: +High latency for LLM interactions (~30s time-to-first-token) +Inefficient bulk data transfer (REST request per item) +Connection overhead for multiple sequential operations + +**User Experience Issues**: +No real-time feedback during LLM generation +Cannot cancel long-running LLM operations +Poor scalability for bulk operations + +### Impact + +The November 2024 streaming enhancement to the Gateway API provided 60x latency improvement (500ms vs 30s first token) for LLM interactions, but Python API users cannot leverage this capability. This creates a significant experience gap between Python and non-Python users. + +## Technical Design + +### Architecture + +The refactored Python API uses a **modular interface approach** with separate objects for different communication patterns. All interfaces are available in both **synchronous and asynchronous** variants: + +1. **REST Interface** (existing, enhanced) + **Sync**: `api.flow()`, `api.library()`, `api.knowledge()`, `api.collection()`, `api.config()` + **Async**: `api.async_flow()` + Synchronous/asynchronous request/response + Simple connection model + Default for backward compatibility + +2. **WebSocket Interface** (new) + **Sync**: `api.socket()` + **Async**: `api.async_socket()` + Persistent connection + Multiplexed requests + Streaming support + Same method signatures as REST where functionality overlaps + +3. **Bulk Operations Interface** (new) + **Sync**: `api.bulk()` + **Async**: `api.async_bulk()` + WebSocket-based for efficiency + Iterator/AsyncIterator-based import/export + Handles large datasets + +4. **Metrics Interface** (new) + **Sync**: `api.metrics()` + **Async**: `api.async_metrics()` + Prometheus metrics access + +```python +import asyncio + +# Synchronous interfaces +api = Api(url="http://localhost:8088/") + +# REST (existing, unchanged) +flow = api.flow().id("default") +response = flow.agent(question="...", user="...") + +# WebSocket (new) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="...", user="...") +for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk) + +# Bulk operations (new) +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Asynchronous interfaces +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST (new) + flow = api.async_flow().id("default") + response = await flow.agent(question="...", user="...") + + # Async WebSocket (new) + socket_flow = api.async_socket().flow("default") + async for chunk in socket_flow.agent(question="...", streaming=True): + print(chunk) + + # Async bulk operations (new) + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + +asyncio.run(main()) +``` + +**Основные принципы проектирования**: +**Одинаковый URL для всех интерфейсов**: `Api(url="http://localhost:8088/")` работает для всех. +**Симметрия синхронной/асинхронной работы**: Каждый интерфейс имеет как синхронные, так и асинхронные варианты с идентичными сигнатурами методов. +**Идентичные сигнатуры**: Там, где функциональность перекрывается, сигнатуры методов одинаковы для REST и WebSocket, а также для синхронных и асинхронных операций. +**Постепенное улучшение**: Выберите интерфейс в зависимости от потребностей (REST для простых задач, WebSocket для потоковой передачи данных, Bulk для больших наборов данных, асинхронный режим для современных фреймворков). +**Явное указание**: `api.socket()` указывает на WebSocket, `api.async_socket()` указывает на асинхронный WebSocket. +**Обратная совместимость**: Существующий код не изменяется. + +### Компоненты + +#### 1. Класс API (модифицированный) + +Модуль: `trustgraph-base/trustgraph/api/api.py` + +**Улучшенный класс API**: + +```python +class Api: + def __init__(self, url: str, timeout: int = 60, token: Optional[str] = None): + self.url = url + self.timeout = timeout + self.token = token # Optional bearer token for REST, query param for WebSocket + self._socket_client = None + self._bulk_client = None + self._async_flow = None + self._async_socket_client = None + self._async_bulk_client = None + + # Existing synchronous methods (unchanged) + def flow(self) -> Flow: + """Synchronous REST-based flow interface""" + pass + + def library(self) -> Library: + """Synchronous REST-based library interface""" + pass + + def knowledge(self) -> Knowledge: + """Synchronous REST-based knowledge interface""" + pass + + def collection(self) -> Collection: + """Synchronous REST-based collection interface""" + pass + + def config(self) -> Config: + """Synchronous REST-based config interface""" + pass + + # New synchronous methods + def socket(self) -> SocketClient: + """Synchronous WebSocket-based interface for streaming operations""" + if self._socket_client is None: + self._socket_client = SocketClient(self.url, self.timeout, self.token) + return self._socket_client + + def bulk(self) -> BulkClient: + """Synchronous bulk operations interface for import/export""" + if self._bulk_client is None: + self._bulk_client = BulkClient(self.url, self.timeout, self.token) + return self._bulk_client + + def metrics(self) -> Metrics: + """Synchronous metrics interface""" + return Metrics(self.url, self.timeout, self.token) + + # New asynchronous methods + def async_flow(self) -> AsyncFlow: + """Asynchronous REST-based flow interface""" + if self._async_flow is None: + self._async_flow = AsyncFlow(self.url, self.timeout, self.token) + return self._async_flow + + def async_socket(self) -> AsyncSocketClient: + """Asynchronous WebSocket-based interface for streaming operations""" + if self._async_socket_client is None: + self._async_socket_client = AsyncSocketClient(self.url, self.timeout, self.token) + return self._async_socket_client + + def async_bulk(self) -> AsyncBulkClient: + """Asynchronous bulk operations interface for import/export""" + if self._async_bulk_client is None: + self._async_bulk_client = AsyncBulkClient(self.url, self.timeout, self.token) + return self._async_bulk_client + + def async_metrics(self) -> AsyncMetrics: + """Asynchronous metrics interface""" + return AsyncMetrics(self.url, self.timeout, self.token) + + # Resource management + def close(self) -> None: + """Close all synchronous connections""" + if self._socket_client: + self._socket_client.close() + if self._bulk_client: + self._bulk_client.close() + + async def aclose(self) -> None: + """Close all asynchronous connections""" + if self._async_socket_client: + await self._async_socket_client.aclose() + if self._async_bulk_client: + await self._async_bulk_client.aclose() + if self._async_flow: + await self._async_flow.aclose() + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + async def __aenter__(self): + return self + + async def __aexit__(self, *args): + await self.aclose() +``` + +#### 2. Синхронный WebSocket-клиент + +Модуль: `trustgraph-base/trustgraph/api/socket_client.py` (новый) + +**Класс SocketClient**: + +```python +class SocketClient: + """Synchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> SocketFlowInstance: + """Get flow instance for WebSocket operations""" + return SocketFlowInstance(self, flow_id) + + def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Uses asyncio.run() internally to wrap async websockets library + pass + + def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + # Synchronous wrapper around async WebSocket calls + pass + + def close(self) -> None: + """Close WebSocket connection""" + pass + +class SocketFlowInstance: + """Synchronous WebSocket flow instance with same interface as REST FlowInstance""" + def __init__(self, client: SocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance + def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, Iterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**Основные характеристики:** +Ленивое подключение (устанавливается только при отправке первого запроса) +Мультиплексирование запросов (до 15 одновременных) +Автоматическое переподключение при разрыве соединения +Потоковая обработка ответа +Потокобезопасная работа +Синхронная обертка вокруг асинхронной библиотеки веб-сокетов + +#### 3. Асинхронный клиент WebSocket + +Модуль: `trustgraph-base/trustgraph/api/async_socket_client.py` (новый) + +**Класс AsyncSocketClient:** + +```python +class AsyncSocketClient: + """Asynchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> AsyncSocketFlowInstance: + """Get async flow instance for WebSocket operations""" + return AsyncSocketFlowInstance(self, flow_id) + + async def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Native async websockets library + pass + + async def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + pass + + async def aclose(self) -> None: + """Close WebSocket connection""" + pass + +class AsyncSocketFlowInstance: + """Asynchronous WebSocket flow instance""" + def __init__(self, client: AsyncSocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance (but async) + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, AsyncIterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**Основные характеристики:** +Встроенная поддержка async/await +Эффективно для асинхронных приложений (FastAPI, aiohttp) +Отсутствие блокировок потоков +Тот же интерфейс, что и у синхронной версии +AsyncIterator для потоковой передачи + +#### 4. Клиент для синхронных пакетных операций + +Модуль: `trustgraph-base/trustgraph/api/bulk_client.py` (новый) + +**Класс BulkClient:** + +```python +class BulkClient: + """Synchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + def import_triples( + self, + flow: str, + triples: Iterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + def export_triples( + self, + flow: str, + **kwargs + ) -> Iterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + def import_graph_embeddings( + self, + flow: str, + embeddings: Iterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> Iterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + def close(self) -> None: + """Close connections""" + pass +``` + +**Основные характеристики:** +Основан на итераторах для постоянного использования памяти. +Выделенные WebSocket-соединения для каждой операции. +Отслеживание прогресса (необязательный обратный вызов). +Обработка ошибок с частичным сообщением об успехе. + +#### 5. Асинхронный клиент массовых операций + +Модуль: `trustgraph-base/trustgraph/api/async_bulk_client.py` (новый) + +**Класс AsyncBulkClient:** + +```python +class AsyncBulkClient: + """Asynchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + async def import_triples( + self, + flow: str, + triples: AsyncIterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + async def export_triples( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + async def import_graph_embeddings( + self, + flow: str, + embeddings: AsyncIterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + async def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + async def aclose(self) -> None: + """Close connections""" + pass +``` + +**Основные характеристики:** +Основан на AsyncIterator для постоянного использования памяти. +Эффективен для асинхронных приложений. +Поддержка нативных асинхронных операций async/await. +Тот же интерфейс, что и у синхронной версии. + +#### 6. REST Flow API (Синхронный - Без изменений) + +Модуль: `trustgraph-base/trustgraph/api/flow.py` + +REST Flow API остается **полностью неизменным** для обеспечения обратной совместимости. Все существующие методы продолжают работать: + +`Flow.list()`, `Flow.start()`, `Flow.stop()` и т.д. +`FlowInstance.agent()`, `FlowInstance.text_completion()`, `FlowInstance.graph_rag()` и т.д. +Все существующие сигнатуры и типы возвращаемых значений сохранены. + +**Новое:** Добавьте `graph_embeddings_query()` в REST FlowInstance для обеспечения соответствия функциональности: + +```python +class FlowInstance: + # All existing methods unchanged... + + # New: Graph embeddings query (REST) + def graph_embeddings_query( + self, + text: str, + user: str, + collection: str, + limit: int = 10, + **kwargs + ) -> List[Dict[str, Any]]: + """Query graph embeddings for semantic search""" + # Calls POST /api/v1/flow/{flow}/service/graph-embeddings + pass +``` + +#### 7. Асинхронный REST API + +Модуль: `trustgraph-base/trustgraph/api/async_flow.py` (новый) + +**Классы AsyncFlow и AsyncFlowInstance**: + +```python +class AsyncFlow: + """Asynchronous REST-based flow interface""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def list(self) -> List[Dict[str, Any]]: + """List all flows""" + pass + + async def get(self, id: str) -> Dict[str, Any]: + """Get flow definition""" + pass + + async def start(self, class_name: str, id: str, description: str, parameters: Dict) -> None: + """Start a flow""" + pass + + async def stop(self, id: str) -> None: + """Stop a flow""" + pass + + def id(self, flow_id: str) -> AsyncFlowInstance: + """Get async flow instance""" + return AsyncFlowInstance(self.url, self.timeout, self.token, flow_id) + + async def aclose(self) -> None: + """Close connection""" + pass + +class AsyncFlowInstance: + """Asynchronous REST flow instance""" + + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + **kwargs + ) -> Dict[str, Any]: + """Async agent execution""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + **kwargs + ) -> str: + """Async text completion""" + pass + + async def graph_rag( + self, + question: str, + user: str, + collection: str, + **kwargs + ) -> str: + """Async graph RAG""" + pass + + # ... all other FlowInstance methods as async versions +``` + +**Основные характеристики:** +Асинхронные HTTP-запросы с использованием `aiohttp` или `httpx` +Те же сигнатуры методов, что и у синхронного REST API +Без потоковой передачи (используйте `async_socket()` для потоковой передачи) +Эффективно для асинхронных приложений + +#### 8. API метрик + +Модуль: `trustgraph-base/trustgraph/api/metrics.py` (новый) + +**Синхронные метрики:** + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +**Асинхронные метрики**: + +```python +class AsyncMetrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +#### 9. Улучшенные типы + +Модуль: `trustgraph-base/trustgraph/api/types.py` (изменен) + +**Новые типы**: + +```python +from typing import Iterator, Union, Dict, Any +import dataclasses + +@dataclasses.dataclass +class StreamingChunk: + """Base class for streaming chunks""" + content: str + end_of_message: bool = False + +@dataclasses.dataclass +class AgentThought(StreamingChunk): + """Agent reasoning chunk""" + chunk_type: str = "thought" + +@dataclasses.dataclass +class AgentObservation(StreamingChunk): + """Agent tool observation chunk""" + chunk_type: str = "observation" + +@dataclasses.dataclass +class AgentAnswer(StreamingChunk): + """Agent final answer chunk""" + chunk_type: str = "final-answer" + end_of_dialog: bool = False + +@dataclasses.dataclass +class RAGChunk(StreamingChunk): + """RAG streaming chunk""" + end_of_stream: bool = False + error: Optional[Dict[str, str]] = None + +# Type aliases for clarity +AgentStream = Iterator[Union[AgentThought, AgentObservation, AgentAnswer]] +RAGStream = Iterator[RAGChunk] +CompletionStream = Iterator[str] +``` + +#### 6. API метрик + +Модуль: `trustgraph-base/trustgraph/api/metrics.py` (новый) + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +### Подход к реализации + +#### Этап 1: Улучшение основного API (1 неделя) + +1. Добавить методы `socket()`, `bulk()` и `metrics()` в класс `Api` +2. Реализовать ленивую инициализацию для WebSocket и пакетных клиентов +3. Добавить поддержку менеджеров контекста (`__enter__`, `__exit__`) +4. Добавить метод `close()` для очистки +5. Добавить модульные тесты для улучшений API +6. Проверить обратную совместимость + +**Обратная совместимость**: Отсутствуют критические изменения. Только новые методы. + +#### Этап 2: WebSocket клиент (2-3 недели) + +1. Реализовать класс `SocketClient` с управлением подключением +2. Реализовать `SocketFlowInstance` с теми же сигнатурами методов, что и у `FlowInstance` +3. Добавить поддержку множественной отправки запросов (до 15 одновременных) +4. Добавить парсинг потоковых ответов для различных типов фрагментов +5. Добавить логику автоматического переподключения +6. Добавить модульные и интеграционные тесты +7. Добавить документацию по использованию WebSocket + +**Обратная совместимость**: Новый интерфейс. Отсутствует влияние на существующий код. + +#### Этап 3: Поддержка потоковой передачи (3-4 недели) + +1. Добавить классы для типов фрагментов потоковой передачи (`AgentThought`, `AgentObservation`, `AgentAnswer`, `RAGChunk`) +2. Реализовать парсинг потоковых ответов в `SocketClient` +3. Добавить параметр потоковой передачи ко всем методам LLM в `SocketFlowInstance` +4. Обрабатывать ошибки во время потоковой передачи +5. Добавить модульные и интеграционные тесты для потоковой передачи +6. Добавить примеры потоковой передачи в документацию + +**Обратная совместимость**: Новый интерфейс. Существующий REST API не изменен. + +#### Этап 4: Пакетные операции (4-5 недели) + +1. Реализовать класс `BulkClient` +2. Добавить методы пакетного импорта/экспорта для троек, векторов, контекстов, объектов +3. Реализовать обработку с использованием итераторов для экономии памяти +4. Добавить отслеживание прогресса (необязательный обратный вызов) +5. Добавить обработку ошибок с отчетом о частичном успехе +6. Добавить модульные и интеграционные тесты +7. Добавить примеры пакетных операций + +**Обратная совместимость**: Новый интерфейс. Отсутствует влияние на существующий код. + +#### Этап 5: Обеспечение совместимости и доработка (5 неделя) + +1. Добавить `graph_embeddings_query()` в REST `FlowInstance` +2. Реализовать класс `Metrics` +3. Добавить комплексные интеграционные тесты +4. Проведение бенчмаркинга производительности +5. Обновить всю документацию +6. Создать руководство по миграции + +**Обратная совместимость**: Только новые методы. Отсутствует влияние на существующий код. + +### Модели данных + +#### Выбор интерфейса + +```python +# Single API instance, same URL for all interfaces +api = Api(url="http://localhost:8088/") + +# Synchronous interfaces +rest_flow = api.flow().id("default") # Sync REST +socket_flow = api.socket().flow("default") # Sync WebSocket +bulk = api.bulk() # Sync bulk operations +metrics = api.metrics() # Sync metrics + +# Asynchronous interfaces +async_rest_flow = api.async_flow().id("default") # Async REST +async_socket_flow = api.async_socket().flow("default") # Async WebSocket +async_bulk = api.async_bulk() # Async bulk operations +async_metrics = api.async_metrics() # Async metrics +``` + +#### Типы ответов потоковой передачи + +**Потоковая передача от агента**: + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - non-streaming (same signature) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - streaming (new) +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentThought): + print(f"Thinking: {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"Observed: {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"Answer: {chunk.content}") + if chunk.end_of_dialog: + break +``` + +**Потоковая передача RAG**: + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.graph_rag(question="What is Python?", user="user123", collection="default") +print(response) + +# WebSocket interface - streaming (new) +socket_flow = api.socket().flow("default") +for chunk in socket_flow.graph_rag( + question="What is Python?", + user="user123", + collection="default", + streaming=True +): + print(chunk.content, end="", flush=True) + if chunk.end_of_stream: + break +``` + +**Массовые операции (синхронные):** + +```python +api = Api(url="http://localhost:8088/") + +# Bulk import triples +def triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Bulk export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +**Массовые операции (асинхронные):** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async bulk import triples + async def async_triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + + # Async bulk export triples + async for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") + +asyncio.run(main()) +``` + +**Пример асинхронного REST:** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST flow operations + flow = api.async_flow().id("default") + response = await flow.agent(question="What is ML?", user="user123") + print(response["response"]) + +asyncio.run(main()) +``` + +**Пример асинхронной потоковой передачи данных через WebSocket:** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async WebSocket streaming + socket = api.async_socket() + flow = socket.flow("default") + + async for chunk in flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) + if chunk.end_of_dialog: + break + +asyncio.run(main()) +``` + +### APIs + +#### New APIs + +1. **Класс API для основных операций**: + **Синхронный**: + `Api.socket()` - Получить синхронного клиента WebSocket + `Api.bulk()` - Получить синхронного клиента для пакетных операций + `Api.metrics()` - Получить синхронного клиента для метрик + `Api.close()` - Закрыть все синхронные соединения + Поддержка менеджера контекста (`__enter__`, `__exit__`) + **Асинхронный**: + `Api.async_flow()` - Получить асинхронного клиента REST flow + `Api.async_socket()` - Получить асинхронного клиента WebSocket + `Api.async_bulk()` - Получить асинхронного клиента для пакетных операций + `Api.async_metrics()` - Получить асинхронного клиента для метрик + `Api.aclose()` - Закрыть все асинхронные соединения + Поддержка асинхронного менеджера контекста (`__aenter__`, `__aexit__`) + +2. **Синхронный клиент WebSocket**: + `SocketClient.flow(flow_id)` - Получить экземпляр WebSocket flow + `SocketFlowInstance.agent(..., streaming: bool = False)` - Агент с опциональной потоковой передачей + `SocketFlowInstance.text_completion(..., streaming: bool = False)` - Завершение текста с опциональной потоковой передачей + `SocketFlowInstance.graph_rag(..., streaming: bool = False)` - Graph RAG с опциональной потоковой передачей + `SocketFlowInstance.document_rag(..., streaming: bool = False)` - Document RAG с опциональной потоковой передачей + `SocketFlowInstance.prompt(..., streaming: bool = False)` - Prompt с опциональной потоковой передачей + `SocketFlowInstance.graph_embeddings_query()` - Запрос graph embeddings + Все остальные методы FlowInstance с идентичными сигнатурами + +3. **Асинхронный клиент WebSocket**: + `AsyncSocketClient.flow(flow_id)` - Получить асинхронный экземпляр WebSocket flow + `AsyncSocketFlowInstance.agent(..., streaming: bool = False)` - Асинхронный агент с опциональной потоковой передачей + `AsyncSocketFlowInstance.text_completion(..., streaming: bool = False)` - Асинхронное завершение текста с опциональной потоковой передачей + `AsyncSocketFlowInstance.graph_rag(..., streaming: bool = False)` - Асинхронный graph RAG с опциональной потоковой передачей + `AsyncSocketFlowInstance.document_rag(..., streaming: bool = False)` - Асинхронный document RAG с опциональной потоковой передачей + `AsyncSocketFlowInstance.prompt(..., streaming: bool = False)` - Асинхронный prompt с опциональной потоковой передачей + `AsyncSocketFlowInstance.graph_embeddings_query()` - Асинхронный запрос graph embeddings + Все остальные методы FlowInstance как асинхронные версии + +4. **Синхронный клиент для пакетных операций**: + `BulkClient.import_triples(flow, triples)` - Пакетный импорт триплетов + `BulkClient.export_triples(flow)` - Пакетный экспорт триплетов + `BulkClient.import_graph_embeddings(flow, embeddings)` - Пакетный импорт graph embeddings + `BulkClient.export_graph_embeddings(flow)` - Пакетный экспорт graph embeddings + `BulkClient.import_document_embeddings(flow, embeddings)` - Пакетный импорт document embeddings + `BulkClient.export_document_embeddings(flow)` - Пакетный экспорт document embeddings + `BulkClient.import_entity_contexts(flow, contexts)` - Пакетный импорт entity contexts + `BulkClient.export_entity_contexts(flow)` - Пакетный экспорт entity contexts + `BulkClient.import_objects(flow, objects)` - Пакетный импорт объектов + +5. **Асинхронный клиент для пакетных операций**: + `AsyncBulkClient.import_triples(flow, triples)` - Асинхронный пакетный импорт триплетов + `AsyncBulkClient.export_triples(flow)` - Асинхронный пакетный экспорт триплетов + `AsyncBulkClient.import_graph_embeddings(flow, embeddings)` - Асинхронный пакетный импорт graph embeddings + `AsyncBulkClient.export_graph_embeddings(flow)` - Асинхронный пакетный экспорт graph embeddings + `AsyncBulkClient.import_document_embeddings(flow, embeddings)` - Асинхронный пакетный импорт document embeddings + `AsyncBulkClient.export_document_embeddings(flow)` - Асинхронный пакетный экспорт document embeddings + `AsyncBulkClient.import_entity_contexts(flow, contexts)` - Асинхронный пакетный импорт entity contexts + `AsyncBulkClient.export_entity_contexts(flow)` - Асинхронный пакетный экспорт entity contexts + `AsyncBulkClient.import_objects(flow, objects)` - Асинхронный пакетный импорт объектов + +6. **Асинхронный клиент REST Flow API**: + `AsyncFlow.list()` - Асинхронный список всех flows + `AsyncFlow.get(id)` - Асинхронное получение определения flow + `AsyncFlow.start(...)` - Асинхронный запуск flow + `AsyncFlow.stop(id)` - Асинхронная остановка flow + `AsyncFlow.id(flow_id)` - Получить асинхронный экземпляр flow + `AsyncFlowInstance.agent(...)` - Асинхронное выполнение агента + `AsyncFlowInstance.text_completion(...)` - Асинхронное завершение текста + `AsyncFlowInstance.graph_rag(...)` - Асинхронный graph RAG + Все остальные методы FlowInstance как асинхронные версии + +7. **Клиенты для метрик**: + `Metrics.get()` - Синхронные метрики Prometheus + `AsyncMetrics.get()` - Асинхронные метрики Prometheus + +8. **Улучшение REST Flow API**: + `FlowInstance.graph_embeddings_query()` - Запрос graph embeddings (синхронная функциональность) + `AsyncFlowInstance.graph_embeddings_query()` - Запрос graph embeddings (асинхронная функциональность) + +#### Измененные API + +1. **Конструктор** (незначительное улучшение): + ```python + Api(url: str, timeout: int = 60, token: Optional[str] = None) + ``` + Добавлен параметр `token` (необязательный, для аутентификации). + Если `None` не указан (по умолчанию): аутентификация не используется. + Если указан: используется как токен доступа для REST (`Authorization: Bearer `), параметр запроса для WebSocket (`?token=`). + Других изменений нет - полностью обратно совместимо. + +2. **Отсутствие изменений, нарушающих обратную совместимость**: + Все существующие методы REST API не изменены. + Все существующие сигнатуры сохранены. + Все существующие типы возвращаемых значений сохранены. + +### Детали реализации + +#### Обработка ошибок + +**Ошибки подключения WebSocket**: +```python +try: + api = Api(url="http://localhost:8088/") + socket = api.socket() + socket_flow = socket.flow("default") + response = socket_flow.agent(question="...", user="user123") +except ConnectionError as e: + print(f"WebSocket connection failed: {e}") + print("Hint: Ensure Gateway is running and WebSocket endpoint is accessible") +``` + +**Плавный переход на резервный вариант**: +```python +api = Api(url="http://localhost:8088/") + +try: + # Try WebSocket streaming first + socket_flow = api.socket().flow("default") + for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk.content) +except ConnectionError: + # Fall back to REST non-streaming + print("WebSocket unavailable, falling back to REST") + rest_flow = api.flow().id("default") + response = rest_flow.agent(question="...", user="...") + print(response["response"]) +``` + +**Частичные ошибки потоковой передачи**: +```python +api = Api(url="http://localhost:8088/") +socket_flow = api.socket().flow("default") + +accumulated = [] +try: + for chunk in socket_flow.graph_rag(question="...", streaming=True): + accumulated.append(chunk.content) + if chunk.error: + print(f"Error occurred: {chunk.error}") + print(f"Partial response: {''.join(accumulated)}") + break +except Exception as e: + print(f"Streaming error: {e}") + print(f"Partial response: {''.join(accumulated)}") +``` + +#### Управление ресурсами + +**Поддержка контекстных менеджеров**: +```python +# Automatic cleanup +with Api(url="http://localhost:8088/") as api: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +# All connections automatically closed + +# Manual cleanup +api = Api(url="http://localhost:8088/") +try: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +finally: + api.close() # Explicitly close all connections (WebSocket, bulk, etc.) +``` + +#### Многопоточность и параллелизм + +**Потоковая безопасность**: +Каждый экземпляр `Api` поддерживает собственное соединение. +Транспорт WebSocket использует блокировки для потокобезопасной мультиплексирования запросов. +Несколько потоков могут безопасно совместно использовать экземпляр `Api`. +Потоковые итераторы не являются потокобезопасными (используйте из одного потока). + +**Асинхронная поддержка** (планируется к реализации в будущем): +```python +# Phase 2 enhancement (not in initial scope) +import asyncio + +async def main(): + api = await AsyncApi(url="ws://localhost:8088/") + flow = api.flow().id("default") + + async for chunk in flow.agent(question="...", streaming=True): + print(chunk.content) + + await api.close() + +asyncio.run(main()) +``` + +## Соображения безопасности + +### Аутентификация + +**Параметр токена**: +```python +# No authentication (default) +api = Api(url="http://localhost:8088/") + +# With authentication +api = Api(url="http://localhost:8088/", token="mytoken") +``` + +**REST-транспорт:** +Токен передается через заголовок `Authorization` +Применяется автоматически ко всем REST-запросам +Формат: `Authorization: Bearer ` + +**WebSocket-транспорт:** +Токен передается через параметр запроса, добавляемый к URL WebSocket +Применяется автоматически во время установления соединения +Формат: `ws://localhost:8088/api/v1/socket?token=` + +**Реализация:** +```python +class SocketClient: + def _connect(self) -> WebSocket: + # Construct WebSocket URL with optional token + ws_url = f"{self.url}/api/v1/socket" + if self.token: + ws_url = f"{ws_url}?token={self.token}" + # Connect to WebSocket + return websocket.connect(ws_url) +``` + +**Пример:** +```python +# REST with auth +api = Api(url="http://localhost:8088/", token="mytoken") +flow = api.flow().id("default") +# All REST calls include: Authorization: Bearer mytoken + +# WebSocket with auth +socket = api.socket() +# Connects to: ws://localhost:8088/api/v1/socket?token=mytoken +``` + +### Безопасная связь + +Поддержка схем WS (WebSocket) и WSS (WebSocket Secure). +Проверка сертификатов TLS для соединений WSS. +Опциональное отключение проверки сертификатов для разработки (с предупреждением). + +### Валидация входных данных + +Проверка схем URL (http, https, ws, wss). +Проверка значений параметров передачи данных. +Проверка комбинаций параметров потоковой передачи. +Проверка типов данных для массового импорта. + +## Вопросы производительности + +### Оптимизация задержки + +**Потоковые операции с LLM**: +**Время получения первого токена**: ~500 мс (против ~30 секунд без потоковой передачи). +**Улучшение**: Воспринимаемая производительность увеличена в 60 раз. +**Применимо к**: Agent, Graph RAG, Document RAG, Text Completion, Prompt. + +**Постоянные соединения**: +**Накладные расходы на соединение**: Устранены для последующих запросов. +**Установление WebSocket-соединения**: Единоразовая операция (~100 мс). +**Применимо к**: Всем операциям при использовании транспорта WebSocket. + +### Оптимизация пропускной способности + +**Массовые операции**: +**Импорт триплетов**: ~10 000 триплетов/секунду (против ~100/секунду с REST для каждого элемента). +**Импорт векторов**: ~5 000 векторов/секунду (против ~50/секунду с REST для каждого элемента). +**Улучшение**: Пропускная способность увеличена в 100 раз для массовых операций. + +**Множественная отправка запросов**: +**Параллельные запросы**: До 15 одновременных запросов через одно соединение. +**Повторное использование соединения**: Отсутствуют накладные расходы на соединение для параллельных операций. + +### Вопросы использования памяти + +**Потоковые ответы**: +Постоянное использование памяти (обработка фрагментов по мере их поступления). +Отсутствует буферизация полного ответа. +Подходит для очень длинных ответов (>1 МБ). + +**Массовые операции**: +Обработка с использованием итераторов (постоянное использование памяти). +Отсутствует загрузка всего набора данных в память. +Подходит для наборов данных с миллионами элементов. + +### Результаты тестирования (ожидаемые) + +| Операция | REST (существующий) | WebSocket (потоковая передача) | Улучшение | +|-----------|----------------|----------------------|-------------| +| Agent (время получения первого токена) | 30с | 0.5с | 60x | +| Graph RAG (время получения первого токена) | 25с | 0.5с | 50x | +| Импорт 10K триплетов | 100с | 1с | 100x | +| Импорт 1M триплетов | 10 000с (2.7ч) | 100с (1.6м) | 100x | +| 10 параллельных небольших запросов | 5с (последовательно) | 0.5с (параллельно) | 10x | + +## Стратегия тестирования + +### Модульные тесты + +**Транспортный уровень** (`test_transport.py`): +Проверка запросов и ответов REST +Проверка подключения WebSocket +Проверка повторного подключения WebSocket +Проверка мультиплексирования запросов +Проверка разбора потоковых ответов +Эмуляция WebSocket-сервера для детерминированных тестов + +**Методы API** (`test_flow.py`, `test_library.py` и т.д.): +Проверка новых методов с использованием эмулированного транспорта +Проверка обработки потоковых параметров +Проверка итераторов для пакетных операций +Проверка обработки ошибок + +**Типы данных** (`test_types.py`): +Проверка новых типов данных для потоковой передачи +Проверка сериализации/десериализации типов данных + +### Интеграционные тесты + +**Комплексные тесты REST** (`test_integration_rest.py`): +Проверка всех операций против реального шлюза (режим REST) +Проверка обратной совместимости +Проверка условий ошибок + +**Комплексные тесты WebSocket** (`test_integration_websocket.py`): +Проверка всех операций против реального шлюза (режим WebSocket) +Проверка операций потоковой передачи +Проверка пакетных операций +Проверка одновременных запросов +Проверка восстановления соединения + +**Сервисы потоковой передачи** (`test_streaming_integration.py`): +Проверка потоковой передачи данных агента (мысли, наблюдения, ответы) +Проверка потоковой передачи данных RAG (инкрементные фрагменты) +Проверка потоковой передачи текста (по токенам) +Проверка потоковой передачи запросов +Проверка обработки ошибок во время потоковой передачи + +**Пакетные операции** (`test_bulk_integration.py`): +Проверка пакетного импорта/экспорта троек (1K, 10K, 100K элементов) +Проверка пакетного импорта/экспорта векторных представлений +Проверка использования памяти во время пакетных операций +Проверка отслеживания прогресса + +### Тесты производительности + +**Бенчмарки задержки** (`test_performance_latency.py`): +Измерение времени до первого токена (потоковая передача против не потоковой передачи) +Измерение накладных расходов на подключение (REST против WebSocket) +Сравнение с ожидаемыми результатами + +**Бенчмарки пропускной способности** (`test_performance_throughput.py`): +Измерение пропускной способности пакетного импорта +Измерение эффективности мультиплексирования запросов +Сравнение с ожидаемыми результатами + +### Тесты совместимости + +**Обратная совместимость** (`test_backward_compatibility.py`): +Запуск существующего набора тестов против рефакторингованного API +Проверка отсутствия изменений, нарушающих обратную совместимость +Проверка пути миграции для распространенных сценариев + +## План миграции + +### Этап 1: Прозрачная миграция (по умолчанию) + +**Не требуется внесения изменений в код**. Существующий код продолжает работать: + +```python +# Existing code works unchanged +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") +response = flow.agent(question="What is ML?", user="user123") +``` + +### Фаза 2: Опциональная потоковая передача (простая) + +**Используйте интерфейс `api.socket()`** для включения потоковой передачи: + +```python +# Before: Non-streaming REST +api = Api(url="http://localhost:8088/") +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# After: Streaming WebSocket (same parameters!) +api = Api(url="http://localhost:8088/") # Same URL +socket_flow = api.socket().flow("default") + +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) +``` + +**Основные моменты:** +Один и тот же URL для REST и WebSocket. +Одинаковые сигнатуры методов (простое переключение). +Просто добавьте `.socket()` и `streaming=True`. + +### Фаза 3: Массовые операции (Новая функциональность) + +**Используйте интерфейс `api.bulk()`** для больших наборов данных: + +```python +# Before: Inefficient per-item operations +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") + +for triple in my_large_triple_list: + # Slow per-item operations + # (no direct bulk insert in REST API) + pass + +# After: Efficient bulk loading +api = Api(url="http://localhost:8088/") # Same URL +bulk = api.bulk() + +# This is fast (10,000 triples/second) +bulk.import_triples(flow="default", triples=iter(my_large_triple_list)) +``` + +### Обновления документации + +1. **README.md**: Добавить примеры потоковой передачи и WebSockets +2. **Справочник API**: Описать все новые методы и параметры +3. **Руководство по миграции**: Пошаговое руководство по включению потоковой передачи +4. **Примеры**: Добавить примеры скриптов для распространенных сценариев +5. **Руководство по производительности**: Описать ожидаемые улучшения производительности + +### Политика устаревания + +**Нет устаревших функций**. Все существующие API остаются поддерживаемыми. Это чистое улучшение. + +## План + +### Неделя 1: Основа +Абстрактный слой транспорта +Рефакторинг существующего REST-кода +Юнит-тесты для слоя транспорта +Проверка обратной совместимости + +### Неделя 2: Транспорт WebSockets +Реализация транспорта WebSockets +Управление соединениями и повторное подключение +Мультиплексирование запросов +Юнит-тесты и интеграционные тесты + +### Неделя 3: Поддержка потоковой передачи +Добавить параметр потоковой передачи к методам LLM +Реализовать разбор потоковых ответов +Добавить типы потоковых фрагментов +Интеграционные тесты потоковой передачи + +### Неделя 4: Массовые операции +Добавить методы массового импорта/экспорта +Реализовать операции на основе итераторов +Тестирование производительности +Интеграционные тесты массовых операций + +### Неделя 5: Функциональная совместимость и документация +Добавить запрос графовых вложений +Добавить API метрик +Комплексная документация +Руководство по миграции +Кандидат в релиз + +### Неделя 6: Релиз +Заключительное интеграционное тестирование +Бенчмаркинг производительности +Документация к релизу +Объявление для сообщества + +**Общая продолжительность**: 6 недель + +## Открытые вопросы + +### Вопросы проектирования API + +1. **Поддержка асинхронности**: ✅ **РЕШЕНО** - Полная поддержка асинхронности включена в первоначальный релиз + Все интерфейсы имеют асинхронные варианты: `async_flow()`, `async_socket()`, `async_bulk()`, `async_metrics()` + Обеспечивает полную симметрию между синхронными и асинхронными API + Необходимо для современных асинхронных фреймворков (FastAPI, aiohttp) + +2. **Отслеживание прогресса**: Должны ли массовые операции поддерживать обратные вызовы для отслеживания прогресса? + ```python + def progress_callback(processed: int, total: Optional[int]): + print(f"Processed {processed} items") + + bulk.import_triples(flow="default", triples=triples, on_progress=progress_callback) + ``` + **Рекомендация**: Добавить на Фазе 2. Не критично для первоначального релиза. + +3. **Таймаут потоковой передачи**: Как нам обрабатывать таймауты для операций потоковой передачи? + **Рекомендация**: Использовать тот же таймаут, что и для не-потоковой передачи, но сбрасывать его при получении каждого фрагмента. + +4. **Буферизация фрагментов**: Следует ли нам буферизовать фрагменты или выдавать их немедленно? + **Рекомендация**: Выдавать немедленно для достижения минимальной задержки. + +5. **Глобальные сервисы через WebSocket**: Должен ли `api.socket()` поддерживать глобальные сервисы (библиотека, знания, коллекция, конфигурация) или только сервисы, привязанные к потоку? + **Рекомендация**: Начать только с сервисов, привязанных к потоку (где важна потоковая передача). Добавить глобальные сервисы, если это потребуется, на Фазе 2. + +### Вопросы реализации + +1. **Библиотека WebSocket**: Следует ли нам использовать `websockets`, `websocket-client` или `aiohttp`? + **Рекомендация**: `websockets` (асинхронная, зрелая, хорошо поддерживаемая). Обернуть в синхронный интерфейс с использованием `asyncio.run()`. + +2. **Пул соединений**: Следует ли нам поддерживать несколько одновременных экземпляров `Api`, использующих общий пул соединений? + **Рекомендация**: Отложить до Фазы 2. Изначально каждый экземпляр `Api` имеет свои собственные соединения. + +3. **Повторное использование соединений**: Должны ли `SocketClient` и `BulkClient` использовать одно и то же WebSocket-соединение или отдельные соединения? + **Рекомендация**: Отдельные соединения. Более простая реализация, более четкое разделение ответственности. + +4. **Ленивое vs. Активное соединение**: Должно ли WebSocket-соединение устанавливаться в `api.socket()` или при первом запросе? + **Рекомендация**: Ленивое (при первом запросе). Избегает накладных расходов на соединение, если пользователь использует только методы REST. + +### Вопросы тестирования + +1. **Моковый шлюз**: Следует ли нам создать легковесный моковый шлюз для тестирования или тестировать против реального шлюза? + **Рекомендация**: Оба варианта. Использовать моки для модульных тестов и реальный шлюз для интеграционных тестов. + +2. **Автоматизированные тесты регрессии производительности**: Следует ли нам добавить автоматизированные тесты регрессии производительности в CI? + **Рекомендация**: Да, но с достаточно большими допусками, чтобы учитывать изменчивость среды CI. + +## Ссылки + +### Связанные технические спецификации +`docs/tech-specs/streaming-llm-responses.md` - Реализация потоковой передачи в шлюзе +`docs/tech-specs/rag-streaming-support.md` - Поддержка потоковой передачи RAG + +### Файлы реализации +`trustgraph-base/trustgraph/api/` - Исходный код API на Python +`trustgraph-flow/trustgraph/gateway/` - Исходный код шлюза +`trustgraph-flow/trustgraph/gateway/dispatch/mux.py` - Пример реализации мультиплексора WebSocket + +### Документация +`docs/apiSpecification.md` - Полная справочная документация API +`docs/api-status-summary.md` - Краткое описание статуса API +`README.websocket` - Документация протокола WebSocket +`STREAMING-IMPLEMENTATION-NOTES.txt` - Заметки о реализации потоковой передачи + +### Внешние библиотеки +`websockets` - Библиотека WebSocket на Python (https://websockets.readthedocs.io/) +`requests` - HTTP-библиотека на Python (существующая) diff --git a/docs/tech-specs/python-api-refactor.sw.md b/docs/tech-specs/python-api-refactor.sw.md new file mode 100644 index 00000000..dcc73b68 --- /dev/null +++ b/docs/tech-specs/python-api-refactor.sw.md @@ -0,0 +1,1508 @@ +# Vipangilio vya Kisaikolojia la API ya Python + +## Muhtasari + +Vipangilio hivi vinaelezea marekebisho kamili ya maktaba ya mteja wa API ya Python ya TrustGraph ili kufikia utendaji sawa na API Gateway na kuongeza ufuatiliaji wa mitindo ya kisasa ya mawasiliano ya muda halisi. + +Marekebisho haya yanashughulikia matumizi manne makuu: + +1. **Mwingiliano wa LLM wa Msururu**: Ruhusu utiririshaji wa wakati halisi wa majibu ya LLM (wakala, RAG ya chati, RAG ya hati, kukamilisha maandishi, maagizo) na kuchelewesha chini ya ~60x (500ms dhidi ya 30s kwa tokeni ya kwanza) +2. **Operesheni za Data za Kiasi**: Unga uingizaji/utoaji wa data nyingi wa triples, uingizaji wa chati, na uingizaji wa hati kwa usimamizi wa grafu kubwa. +3. **Ulinganishi wa Vipengele**: Hakikisha kila mwisho wa API Gateway una mbinu inayolingana ya API ya Python, pamoja na swali la uingizaji wa chati. +4. **Miunganisho ya Kudumu**: Ruhusu mawasiliano ya WebSocket kwa maombi ya kuzingatia na kupunguza gharama ya muunganisho. + +## Lengo + +**Ulinganishi wa Vipengele**: Huduma kila Gateway API ina mbinu inayolingana ya API ya Python +**Ufuatiliaji**: Huduma zote za ufuatiliaji (wakala, RAG, kukamilisha maandishi, agizo) zinaunga mkono ufuatiliaji katika API ya Python +**Usafirishaji wa WebSocket**: Ongeza safu ya usafirishaji ya hiari ya WebSocket kwa miunganisho ya kudumu na kuzingatia +**Operesheni za Kiasi**: Ongeza uingizaji/utoaji wa data nyingi wa triples, uingizaji wa chati, na uingizaji wa hati +**Ufuatiliaji Kamili**: Utekelezaji kamili wa async/wait kwa interfaces zote (REST, WebSocket, operesheni za kiasi, metrics) +**Ulinganisho na Msimu wa Uendeshaji**: Msimu wa uendeshaji wa sasa unaendelea kufanya kazi bila mabadiliko +**Usalama wa Aina**: Dumishe interfaces za usalama wa aina na dataclasses na vidokezo vya aina +**Uboreshaji wa Hatua kwa Hatua**: Ufuatiliaji na async ni chaguo kupitia uteuzi wa wazi wa interface +**Utendaji**: Pata uboreshaji wa kuchelewesha wa 60x kwa operesheni za ufuatiliaji +**Python ya Kisasa**: Usaidizi wa paradigm za sync na async kwa uwezekano mwingi + +## Asili + +### Hali ya Sasa + +API ya Python (`trustgraph-base/trustgraph/api/`) ni maktaba ya mteja ya REST pekee na moduli zifuatazo: + +`flow.py`: Usimamizi wa mtiririko na huduma za mtiririko (mbinu 50) +`library.py`: Operesheni za maktaba ya hati (mbinu 9) +`knowledge.py`: Usimamizi wa msingi wa KG (mbinu 4) +`collection.py`: Metadata ya mkusanyiko (mbinu 3) +`config.py`: Usimamizi wa usanidi (mbinu 6) +`types.py`: Ufafanuzi wa aina ya data (dataclasses 5) + +**Operesheni Jumla**: 50/59 (ufafanuzi wa 85%) + +### Mapungufu ya Sasa + +**Operesheni Zinazokosekana**: +Swali la uingizaji wa chati (utafutaji wa kiufundi juu ya vitu vya chati) +Uingizaji/utoaji wa data nyingi wa triples, uingizaji wa chati, uingizaji wa hati, muktadha wa vitu, vitu +Mwisho wa metrics + +**Uwezekano Usio Kutosha**: +Usaidizi wa utiririshaji kwa huduma za LLM +Usafirishaji wa WebSocket +Maombi mengi yanayotendua wakati mmoja +Muunganisho unaoendelea + +**Matatizo ya Utendaji**: +Kuchelewesha kwa muda kwa mwingiliano wa LLM (~sekunde 30 hadi tokeni ya kwanza) +Usafirishaji usio na ufanisi wa data kwa wingi (ombi la REST kwa kila kipengele) +Mizigo ya muunganisho kwa operesheni nyingi mfululizo + +**Matatizo ya Uzoefu wa Mtumiaji**: +Hakuna maoni ya wakati halisi wakati wa uzalishaji wa LLM +Haiwezekani kughairi operesheni ndefu za LLM +Uwezo duni wa kuongezeka kwa operesheni kwa wingi + +### Athari + +Uboresho wa utiririshaji wa Novemba 2024 kwa API ya Gateway uliweka uboreshaji wa ucheleweshaji wa mara 60 (ms 500 dhidi ya sekunde 30 ya tokeni ya kwanza) kwa mwingiliano wa LLM, lakini watumiaji wa API ya Python hawawezi kutumia uwezo huu. Hii huunda pengo kubwa la uzoefu kati ya watumiaji wa Python na wasio wa Python. + +## Muundo wa Kiufundi + +### Usanifu + +API ya Python iliyoboreshwa hutumia **mbinu ya kiolesura ya moduli** na vitu tofauti kwa mifumo tofauti ya mawasiliano. Violesho vyote vinapatikana katika matoleo **ya wakati mmoja na ya isiyo ya wakati mmoja**: + +1. **Kiolesho cha REST** (kipo, kimeboreshwa) + **Sync**: `api.flow()`, `api.library()`, `api.knowledge()`, `api.collection()`, `api.config()` + **Async**: `api.async_flow()` + Ombi/jibu la wakati mmoja/la isiyo ya wakati mmoja + Mfumo rahisi wa muunganisho + Chaguo-msingi kwa utangamano wa nyuma + +2. **Kiolesho cha WebSocket** (kipo) + **Sync**: `api.socket()` + **Async**: `api.async_socket()` + Muunganisho unaoendelea + Maombi yaliyounganishwa + Usaidizi wa utiririshaji + Alama sawa za mbinu kama REST ambapo utendaji unapanuka + +3. **Kiolesho cha Operesheni kwa Wingi** (kipo) + **Sync**: `api.bulk()` + **Async**: `api.async_bulk()` + Kulingana na WebSocket kwa ufanisi + Import/export kulingana na Iterator/AsyncIterator + Hushughulikia data kubwa + +4. **Kiolesho cha Metrics** (kipo) + **Sync**: `api.metrics()` + **Async**: `api.async_metrics()` + Ufikiaji wa metrics ya Prometheus + +```python +import asyncio + +# Synchronous interfaces +api = Api(url="http://localhost:8088/") + +# REST (existing, unchanged) +flow = api.flow().id("default") +response = flow.agent(question="...", user="...") + +# WebSocket (new) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="...", user="...") +for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk) + +# Bulk operations (new) +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Asynchronous interfaces +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST (new) + flow = api.async_flow().id("default") + response = await flow.agent(question="...", user="...") + + # Async WebSocket (new) + socket_flow = api.async_socket().flow("default") + async for chunk in socket_flow.agent(question="...", streaming=True): + print(chunk) + + # Async bulk operations (new) + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + +asyncio.run(main()) +``` + +**Kanuni Muhimu za Ubunifu**: +**URL moja kwa kila aina ya muunganisho**: `Api(url="http://localhost:8088/")` inafanya kazi kwa aina zote. +**Ulinganisho kati ya utendaji wa papo hapo na usio wa papo hapo**: Kila aina ya muunganisho ina matoleo ya utendaji wa papo hapo na yasiyo wa papo hapo yenye saini sawa za mbinu. +**Saini sawa**: Pale ambapo utendaji unapanuka, saini za mbinu ni sawa kati ya REST na WebSocket, utendaji wa papo hapo na usio wa papo hapo. +**Uboreshaji wa hatua kwa hatua**: Chagua aina ya muunganisho kulingana na mahitaji (REST kwa mambo rahisi, WebSocket kwa utiririshaji, Bulk kwa data kubwa, utendaji usio wa papo hapo kwa mifumo ya kisasa). +**Lengo lililo wazi**: `api.socket()` inaonyesha WebSocket, `api.async_socket()` inaonyesha WebSocket ya utendaji usio wa papo hapo. +**Inafaa na mifumo ya zamani**: Msimbo uliopo haubahatishwi. + +### Vipengele + +#### 1. Darasa la API Kuu (Imebadilishwa) + +Moduli: `trustgraph-base/trustgraph/api/api.py` + +**Darasa la API Lililoboreshwa**: + +```python +class Api: + def __init__(self, url: str, timeout: int = 60, token: Optional[str] = None): + self.url = url + self.timeout = timeout + self.token = token # Optional bearer token for REST, query param for WebSocket + self._socket_client = None + self._bulk_client = None + self._async_flow = None + self._async_socket_client = None + self._async_bulk_client = None + + # Existing synchronous methods (unchanged) + def flow(self) -> Flow: + """Synchronous REST-based flow interface""" + pass + + def library(self) -> Library: + """Synchronous REST-based library interface""" + pass + + def knowledge(self) -> Knowledge: + """Synchronous REST-based knowledge interface""" + pass + + def collection(self) -> Collection: + """Synchronous REST-based collection interface""" + pass + + def config(self) -> Config: + """Synchronous REST-based config interface""" + pass + + # New synchronous methods + def socket(self) -> SocketClient: + """Synchronous WebSocket-based interface for streaming operations""" + if self._socket_client is None: + self._socket_client = SocketClient(self.url, self.timeout, self.token) + return self._socket_client + + def bulk(self) -> BulkClient: + """Synchronous bulk operations interface for import/export""" + if self._bulk_client is None: + self._bulk_client = BulkClient(self.url, self.timeout, self.token) + return self._bulk_client + + def metrics(self) -> Metrics: + """Synchronous metrics interface""" + return Metrics(self.url, self.timeout, self.token) + + # New asynchronous methods + def async_flow(self) -> AsyncFlow: + """Asynchronous REST-based flow interface""" + if self._async_flow is None: + self._async_flow = AsyncFlow(self.url, self.timeout, self.token) + return self._async_flow + + def async_socket(self) -> AsyncSocketClient: + """Asynchronous WebSocket-based interface for streaming operations""" + if self._async_socket_client is None: + self._async_socket_client = AsyncSocketClient(self.url, self.timeout, self.token) + return self._async_socket_client + + def async_bulk(self) -> AsyncBulkClient: + """Asynchronous bulk operations interface for import/export""" + if self._async_bulk_client is None: + self._async_bulk_client = AsyncBulkClient(self.url, self.timeout, self.token) + return self._async_bulk_client + + def async_metrics(self) -> AsyncMetrics: + """Asynchronous metrics interface""" + return AsyncMetrics(self.url, self.timeout, self.token) + + # Resource management + def close(self) -> None: + """Close all synchronous connections""" + if self._socket_client: + self._socket_client.close() + if self._bulk_client: + self._bulk_client.close() + + async def aclose(self) -> None: + """Close all asynchronous connections""" + if self._async_socket_client: + await self._async_socket_client.aclose() + if self._async_bulk_client: + await self._async_bulk_client.aclose() + if self._async_flow: + await self._async_flow.aclose() + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + async def __aenter__(self): + return self + + async def __aexit__(self, *args): + await self.aclose() +``` + +#### 2. Mteja wa WebSocket wa Moja kwa Moja + +Moduli: `trustgraph-base/trustgraph/api/socket_client.py` (mpya) + +**Darasa la SocketClient**: + +```python +class SocketClient: + """Synchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> SocketFlowInstance: + """Get flow instance for WebSocket operations""" + return SocketFlowInstance(self, flow_id) + + def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Uses asyncio.run() internally to wrap async websockets library + pass + + def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + # Synchronous wrapper around async WebSocket calls + pass + + def close(self) -> None: + """Close WebSocket connection""" + pass + +class SocketFlowInstance: + """Synchronous WebSocket flow instance with same interface as REST FlowInstance""" + def __init__(self, client: SocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance + def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, Iterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**Sifa Muhimu**: +Muunganisho wa polepole (unaunganisha tu wakati ombi la kwanza lilitumwa) +Uunganishaji wa ombi ( hadi 15 ufuatiliaji) +Muunganisho wa kiotomatiki unapokatika +Uchanganuzi wa jibu la utiririshaji +Uendeshaji salama wa uzi +Kifungashio cha usawisi kwa maktaba ya websockets isiyo na usawisi + +#### 3. Mteja wa WebSocket Usio na Usawisi + +Moduli: `trustgraph-base/trustgraph/api/async_socket_client.py` (mpya) + +**Darasa la AsyncSocketClient**: + +```python +class AsyncSocketClient: + """Asynchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> AsyncSocketFlowInstance: + """Get async flow instance for WebSocket operations""" + return AsyncSocketFlowInstance(self, flow_id) + + async def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Native async websockets library + pass + + async def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + pass + + async def aclose(self) -> None: + """Close WebSocket connection""" + pass + +class AsyncSocketFlowInstance: + """Asynchronous WebSocket flow instance""" + def __init__(self, client: AsyncSocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance (but async) + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, AsyncIterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**Sifa Muhimu**: +Usaidizi wa asilia wa async/await. +Ufanisi kwa matumizi ya async (FastAPI, aiohttp). +Hakuna kuzuiliwa kwa uzi. +Muundo sawa na toleo la sync. +AsyncIterator kwa utiririshaji. + +#### 4. Mteja wa Operesheni za Kiasi za Synchronous + +Moduli: `trustgraph-base/trustgraph/api/bulk_client.py` (mpya) + +**Darasa la BulkClient**: + +```python +class BulkClient: + """Synchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + def import_triples( + self, + flow: str, + triples: Iterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + def export_triples( + self, + flow: str, + **kwargs + ) -> Iterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + def import_graph_embeddings( + self, + flow: str, + embeddings: Iterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> Iterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + def close(self) -> None: + """Close connections""" + pass +``` + +**Sifa Muhimu**: +Inatumia itereja ili kuhakikisha matumizi thabiti ya kumbukumbu. +Miunganisho maalum ya WebSocket kwa kila operesheni. +Ufuatiliaji wa maendeleo (rudisho la hiari). +Usimamizi wa makosa na ripoti ya mafanikio ya kiasi. + +#### 5. Mteja wa Operesheni za Kiasi za Asynchronous + +Moduli: `trustgraph-base/trustgraph/api/async_bulk_client.py` (mpya) + +**Darasa la AsyncBulkClient**: + +```python +class AsyncBulkClient: + """Asynchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + async def import_triples( + self, + flow: str, + triples: AsyncIterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + async def export_triples( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + async def import_graph_embeddings( + self, + flow: str, + embeddings: AsyncIterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + async def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + async def aclose(self) -> None: + """Close connections""" + pass +``` + +**Sifa Muhimu**: +Inatumia AsyncIterator kwa matumizi thabiti ya kumbukumbu. +Inafaa kwa matumizi ya asynchronous. +Inasaidia natively async/await. +Ina interface sawa na toleo la synchronous. + +#### 6. API ya Mtiririko wa REST (Synchronous - Haibadiliki) + +Moduli: `trustgraph-base/trustgraph/api/flow.py` + +API ya Mtiririko wa REST inabaki **haiibadiliki kabisa** kwa utangamano wa nyuma. Njia zote zilizopo zinaendelea kufanya kazi: + +`Flow.list()`, `Flow.start()`, `Flow.stop()`, n.k. +`FlowInstance.agent()`, `FlowInstance.text_completion()`, `FlowInstance.graph_rag()`, n.k. +Alama zote zilizopo na aina za kurudi zimehifadhiwa. + +**Mpya**: Ongeza `graph_embeddings_query()` kwenye REST FlowInstance kwa utangamano wa vipengele: + +```python +class FlowInstance: + # All existing methods unchanged... + + # New: Graph embeddings query (REST) + def graph_embeddings_query( + self, + text: str, + user: str, + collection: str, + limit: int = 10, + **kwargs + ) -> List[Dict[str, Any]]: + """Query graph embeddings for semantic search""" + # Calls POST /api/v1/flow/{flow}/service/graph-embeddings + pass +``` + +#### 7. API ya Mtiririko wa REST Asynchronous + +Moduli: `trustgraph-base/trustgraph/api/async_flow.py` (mpya) + +**Darasa za AsyncFlow na AsyncFlowInstance**: + +```python +class AsyncFlow: + """Asynchronous REST-based flow interface""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def list(self) -> List[Dict[str, Any]]: + """List all flows""" + pass + + async def get(self, id: str) -> Dict[str, Any]: + """Get flow definition""" + pass + + async def start(self, class_name: str, id: str, description: str, parameters: Dict) -> None: + """Start a flow""" + pass + + async def stop(self, id: str) -> None: + """Stop a flow""" + pass + + def id(self, flow_id: str) -> AsyncFlowInstance: + """Get async flow instance""" + return AsyncFlowInstance(self.url, self.timeout, self.token, flow_id) + + async def aclose(self) -> None: + """Close connection""" + pass + +class AsyncFlowInstance: + """Asynchronous REST flow instance""" + + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + **kwargs + ) -> Dict[str, Any]: + """Async agent execution""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + **kwargs + ) -> str: + """Async text completion""" + pass + + async def graph_rag( + self, + question: str, + user: str, + collection: str, + **kwargs + ) -> str: + """Async graph RAG""" + pass + + # ... all other FlowInstance methods as async versions +``` + +**Vipengele Muhimu**: +Matumizi ya HTTP ya asinkroniki kwa kutumia `aiohttp` au `httpx` +Sauti sawa za mbinu kama API ya REST ya taslimu +Hakuna utiririshaji (tumia `async_socket()` kwa utiririshaji) +Inafaa kwa programu za asinkroniki + +#### 8. API ya Vipimo + +Moduli: `trustgraph-base/trustgraph/api/metrics.py` (mpya) + +**Vipimo vya Taslimu**: + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +**Vipimo Visivyokuwa na Tatizo la Muda (Asynchronous)**: + +```python +class AsyncMetrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +#### 9. Aina Zilizoboreshwa + +Moduli: `trustgraph-base/trustgraph/api/types.py` (iliyorekebishwa) + +**Aina Mpya**: + +```python +from typing import Iterator, Union, Dict, Any +import dataclasses + +@dataclasses.dataclass +class StreamingChunk: + """Base class for streaming chunks""" + content: str + end_of_message: bool = False + +@dataclasses.dataclass +class AgentThought(StreamingChunk): + """Agent reasoning chunk""" + chunk_type: str = "thought" + +@dataclasses.dataclass +class AgentObservation(StreamingChunk): + """Agent tool observation chunk""" + chunk_type: str = "observation" + +@dataclasses.dataclass +class AgentAnswer(StreamingChunk): + """Agent final answer chunk""" + chunk_type: str = "final-answer" + end_of_dialog: bool = False + +@dataclasses.dataclass +class RAGChunk(StreamingChunk): + """RAG streaming chunk""" + end_of_stream: bool = False + error: Optional[Dict[str, str]] = None + +# Type aliases for clarity +AgentStream = Iterator[Union[AgentThought, AgentObservation, AgentAnswer]] +RAGStream = Iterator[RAGChunk] +CompletionStream = Iterator[str] +``` + +#### 6. API ya Vipimo + +Moduli: `trustgraph-base/trustgraph/api/metrics.py` (mpya) + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +### Mbinu ya Utendaji + +#### Awamu ya 1: Kuboresha API Kuu (Wiki ya 1) + +1. Ongeza mbinu za `socket()`, `bulk()`, na `metrics()` kwenye darasa la `Api` +2. Lenga utekelezaji wa lazima kwa wateja wa WebSocket na wa wingi +3. Ongeza usaidizi wa meneja wa muktadha (`__enter__`, `__exit__`) +4. Ongeza mbinu ya `close()` kwa usafi +5. Ongeza vipimo vya kitengo kwa maboresho ya darasa la API +6. Hakikisha utangamano wa nyuma + +**Utangamano wa Nyuma**: Hakuna mabadiliko ya kuvunja. Mbinu mpya tu. + +#### Awamu ya 2: Mteja wa WebSocket (Wiki ya 2-3) + +1. Lenga darasa la `SocketClient` na usimamizi wa muunganisho +2. Lenga `SocketFlowInstance` na maelezo sawa kama `FlowInstance` +3. Ongeza usaidizi wa uongezaji wa ombi ( hadi 15 sambamba) +4. Ongeza uchanganuzi wa jibu la utiririsho kwa aina tofauti za sehemu +5. Ongeza mantiki ya kuunganisha tena kiotomatiki +6. Ongeza vipimo na ujumuishaji +7. Andika mifumo ya matumizi ya WebSocket + +**Utangamano wa Nyuma**: Kiolesura kipya tu. Hakuna athari kwenye msimbo uliopo. + +#### Awamu ya 3: Usaidizi wa Utiririsho (Wiki ya 3-4) + +1. Ongeza darasa za aina ya sehemu ya utiririsho (`AgentThought`, `AgentObservation`, `AgentAnswer`, `RAGChunk`) +2. Lenga uchanganuzi wa jibu la utiririsho katika `SocketClient` +3. Ongeza parameter ya utiririsho kwa mbinu zote za LLM katika `SocketFlowInstance` +4. Shughulikia hali za hitilafu wakati wa utiririsho +5. Ongeza vipimo na ujumuishaji kwa utiririsho +6. Ongeza mifano ya utiririsho kwenye hati + +**Utangamano wa Nyuma**: Kiolesura kipya tu. API ya REST iliyopo haibadiliki. + +#### Awamu ya 4: Operesheni za Wingi (Wiki ya 4-5) + +1. Lenga darasa la `BulkClient` +2. Ongeza mbinu za uagizaji/uangavu wa wingi kwa triples, embeddings, muktadha, vitu +3. Lenga usindikaji unaotegemea iterator kwa kumbukumbu thabiti +4. Ongeza ufuatiliaji wa maendeleo (callback ya hiari) +5. Ongeza ushughulikiaji wa hitilafu na ripoti ya mafanikio ya sehemu +6. Ongeza vipimo na ujumuishaji +7. Ongeza mifano ya operesheni za wingi + +**Utangamano wa Nyuma**: Kiolesura kipya tu. Hakuna athari kwenye msimbo uliopo. + +#### Awamu ya 5: Ulinganishi wa Vipengele na Uboreshaji (Wiki ya 5) + +1. Ongeza `graph_embeddings_query()` kwa `FlowInstance` ya REST +2. Lenga darasa la `Metrics` +3. Ongeza vipimo vya ujumuishaji vya kina +4. Upimaji wa utendaji +5. Sasisha hati zote +6. Unda mwongozo wa uhamishaji + +**Utangamano wa Nyuma**: Mbinu mpya tu. Hakuna athari kwenye msimbo uliopo. + +### Mifano ya Data + +#### Uchaguzi wa Kiolesura + +```python +# Single API instance, same URL for all interfaces +api = Api(url="http://localhost:8088/") + +# Synchronous interfaces +rest_flow = api.flow().id("default") # Sync REST +socket_flow = api.socket().flow("default") # Sync WebSocket +bulk = api.bulk() # Sync bulk operations +metrics = api.metrics() # Sync metrics + +# Asynchronous interfaces +async_rest_flow = api.async_flow().id("default") # Async REST +async_socket_flow = api.async_socket().flow("default") # Async WebSocket +async_bulk = api.async_bulk() # Async bulk operations +async_metrics = api.async_metrics() # Async metrics +``` + +#### Aina za Majibu ya Utiririshaji + +**Utiririshaji wa Wakala:** + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - non-streaming (same signature) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - streaming (new) +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentThought): + print(f"Thinking: {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"Observed: {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"Answer: {chunk.content}") + if chunk.end_of_dialog: + break +``` + +**Utiririshaji wa RAG**: + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.graph_rag(question="What is Python?", user="user123", collection="default") +print(response) + +# WebSocket interface - streaming (new) +socket_flow = api.socket().flow("default") +for chunk in socket_flow.graph_rag( + question="What is Python?", + user="user123", + collection="default", + streaming=True +): + print(chunk.content, end="", flush=True) + if chunk.end_of_stream: + break +``` + +**Operesheni za Kiasi (Zinazofanya kazi kwa wakati mmoja):** + +```python +api = Api(url="http://localhost:8088/") + +# Bulk import triples +def triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Bulk export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +**Operesheni za Kiasi (Zisizo za Moja kwa Moja)**: + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async bulk import triples + async def async_triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + + # Async bulk export triples + async for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") + +asyncio.run(main()) +``` + +**Mfano wa REST Asynchronous**: + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST flow operations + flow = api.async_flow().id("default") + response = await flow.agent(question="What is ML?", user="user123") + print(response["response"]) + +asyncio.run(main()) +``` + +**Mfano wa Utiririshaji wa WebSocket Asynchronous**: + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async WebSocket streaming + socket = api.async_socket() + flow = socket.flow("default") + + async for chunk in flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) + if chunk.end_of_dialog: + break + +asyncio.run(main()) +``` + +### APIs + +#### New APIs + +1. **Darasa la API Kuu**: + **Synchronous (Moja kwa Moja)**: + `Api.socket()` - Pata mteja wa WebSocket moja kwa moja + `Api.bulk()` - Pata mteja wa shughuli kubwa moja kwa moja + `Api.metrics()` - Pata mteja wa metriki moja kwa moja + `Api.close()` - Funga miunganisho yote moja kwa moja + Usaidizi wa meneja wa muktadha (`__enter__`, `__exit__`) + **Asynchronous (Isiyo Moja kwa Moja)**: + `Api.async_flow()` - Pata mteja wa mtiririko wa REST isiyo moja kwa moja + `Api.async_socket()` - Pata mteja wa WebSocket isiyo moja kwa moja + `Api.async_bulk()` - Pata mteja wa shughuli kubwa isiyo moja kwa moja + `Api.async_metrics()` - Pata mteja wa metriki isiyo moja kwa moja + `Api.aclose()` - Funga miunganisho yote isiyo moja kwa moja + Usaidizi wa meneja wa muktadha isiyo moja kwa moja (`__aenter__`, `__aexit__`) + +2. **Mteja wa WebSocket Moja kwa Moja**: + `SocketClient.flow(flow_id)` - Pata mfano wa mtiririko wa WebSocket + `SocketFlowInstance.agent(..., streaming: bool = False)` - Wakala na utiririshaji wa hiari + `SocketFlowInstance.text_completion(..., streaming: bool = False)` - Kukamilisha maandishi na utiririshaji wa hiari + `SocketFlowInstance.graph_rag(..., streaming: bool = False)` - Graph RAG na utiririshaji wa hiari + `SocketFlowInstance.document_rag(..., streaming: bool = False)` - Document RAG na utiririshaji wa hiari + `SocketFlowInstance.prompt(..., streaming: bool = False)` - Ombi na utiririshaji wa hiari + `SocketFlowInstance.graph_embeddings_query()` - Uchunguzi wa embeddings ya grafu + Njia zingine zote za FlowInstance na saini sawa + +3. **Mteja wa WebSocket Isiyo Moja kwa Moja**: + `AsyncSocketClient.flow(flow_id)` - Pata mfano wa mtiririko wa WebSocket isiyo moja kwa moja + `AsyncSocketFlowInstance.agent(..., streaming: bool = False)` - Wakala isiyo moja kwa moja na utiririshaji wa hiari + `AsyncSocketFlowInstance.text_completion(..., streaming: bool = False)` - Kukamilisha maandishi isiyo moja kwa moja na utiririshaji wa hiari + `AsyncSocketFlowInstance.graph_rag(..., streaming: bool = False)` - Async graph RAG na utiririshaji wa hiari + `AsyncSocketFlowInstance.document_rag(..., streaming: bool = False)` - Async document RAG na utiririshaji wa hiari + `AsyncSocketFlowInstance.prompt(..., streaming: bool = False)` - Ombi isiyo moja kwa moja na utiririshaji wa hiari + `AsyncSocketFlowInstance.graph_embeddings_query()` - Uchunguzi wa embeddings ya grafu isiyo moja kwa moja + Njia zingine zote za FlowInstance kama matoleo isiyo moja kwa moja + +4. **Mteja wa Shughuli Kubwa Moja kwa Moja**: + `BulkClient.import_triples(flow, triples)` - Uingizaji wa triple kubwa + `BulkClient.export_triples(flow)` - Utoaji wa triple kubwa + `BulkClient.import_graph_embeddings(flow, embeddings)` - Uingizaji wa embeddings kubwa ya grafu + `BulkClient.export_graph_embeddings(flow)` - Utoaji wa embeddings kubwa ya grafu + `BulkClient.import_document_embeddings(flow, embeddings)` - Uingizaji wa embeddings kubwa za hati + `BulkClient.export_document_embeddings(flow)` - Utoaji wa embeddings kubwa za hati + `BulkClient.import_entity_contexts(flow, contexts)` - Uingizaji wa muktadha mkubwa wa vitu + `BulkClient.export_entity_contexts(flow)` - Utoaji wa muktadha mkubwa wa vitu + `BulkClient.import_objects(flow, objects)` - Uingizaji wa vitu kubwa + +5. **Mteja wa Shughuli Kubwa Isiyo Moja kwa Moja**: + `AsyncBulkClient.import_triples(flow, triples)` - Uingizaji wa triple kubwa isiyo moja kwa moja + `AsyncBulkClient.export_triples(flow)` - Utoaji wa triple kubwa isiyo moja kwa moja + `AsyncBulkClient.import_graph_embeddings(flow, embeddings)` - Uingizaji wa embeddings kubwa ya grafu isiyo moja kwa moja + `AsyncBulkClient.export_graph_embeddings(flow)` - Utoaji wa embeddings kubwa ya grafu isiyo moja kwa moja + `AsyncBulkClient.import_document_embeddings(flow, embeddings)` - Uingizaji wa embeddings kubwa za hati isiyo moja kwa moja + `AsyncBulkClient.export_document_embeddings(flow)` - Utoaji wa embeddings kubwa za hati isiyo moja kwa moja + `AsyncBulkClient.import_entity_contexts(flow, contexts)` - Uingizaji wa muktadha mkubwa wa vitu isiyo moja kwa moja + `AsyncBulkClient.export_entity_contexts(flow)` - Utoaji wa muktadha mkubwa wa vitu isiyo moja kwa moja + `AsyncBulkClient.import_objects(flow, objects)` - Uingizaji wa vitu kubwa isiyo moja kwa moja + +6. **Mteja wa Mtiririko wa REST Isiyo Moja kwa Moja**: + `AsyncFlow.list()` - Orodha ya mtiririko wote isiyo moja kwa moja + `AsyncFlow.get(id)` - Pata ufafanuzi wa mtiririko + `AsyncFlow.start(...)` - Anzisha mtiririko + `AsyncFlow.stop(id)` - Simamisha mtiririko + `AsyncFlow.id(flow_id)` - Pata mfano wa mtiririko + `AsyncFlowInstance.agent(...)` - Utendaji wa wakala + `AsyncFlowInstance.text_completion(...)` - Kukamilisha maandishi + `AsyncFlowInstance.graph_rag(...)` - Graph RAG + Njia zingine zote za FlowInstance kama matoleo isiyo moja kwa moja + +7. **Wateja wa Metriki**: + `Metrics.get()` - Metriki za Prometheus moja kwa moja + `AsyncMetrics.get()` - Metriki za Prometheus isiyo moja kwa moja + +8. **Uboreshaji wa API ya Mtiririko wa REST**: + `FlowInstance.graph_embeddings_query()` - Uchunguzi wa embeddings ya grafu (ufanano wa kipengele cha moja kwa moja) + `AsyncFlowInstance.graph_embeddings_query()` - Uchunguzi wa embeddings ya grafu (ufanano wa kipengele cha isiyo moja kwa moja) + +#### APIs Iliyorekebishwa + +1. **Mawasiliano** (uboreshaji mdogo): + ```python + Api(url: str, timeout: int = 60, token: Optional[str] = None) + ``` + Imeongezwa parameter `token` (hiari, kwa ajili ya uthibitishaji). + Ikiwa `None` (kiwango chachilia): Hakuna uthibitishaji unaotumika. + Ikiwa imeingizwa: Inatumika kama tokeni ya "bearer" kwa REST (`Authorization: Bearer `), parameter ya swali kwa WebSocket (`?token=`). + Hakuna mabadiliko mengine - inafaa kabisa na matoleo ya awali. + +2. **Hakuna Mabadiliko Yanayoweza Kusababisha Tatizo**: + Njia zote za API za REST zilizopo hazijabadilika. + Alama zote zilizopo zimehifadhiwa. + Aina zote za matokeo zilizopo zimehifadhiwa. + +### Maelezo ya Utendaji + +#### Usimamizi wa Madhira + +**Madhira ya Muunganisho wa WebSocket**: +```python +try: + api = Api(url="http://localhost:8088/") + socket = api.socket() + socket_flow = socket.flow("default") + response = socket_flow.agent(question="...", user="user123") +except ConnectionError as e: + print(f"WebSocket connection failed: {e}") + print("Hint: Ensure Gateway is running and WebSocket endpoint is accessible") +``` + +**Rudi Nyuma kwa Ufasaha**: +```python +api = Api(url="http://localhost:8088/") + +try: + # Try WebSocket streaming first + socket_flow = api.socket().flow("default") + for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk.content) +except ConnectionError: + # Fall back to REST non-streaming + print("WebSocket unavailable, falling back to REST") + rest_flow = api.flow().id("default") + response = rest_flow.agent(question="...", user="...") + print(response["response"]) +``` + +**Hitilafu za Uhamisho wa Takwimu:** +```python +api = Api(url="http://localhost:8088/") +socket_flow = api.socket().flow("default") + +accumulated = [] +try: + for chunk in socket_flow.graph_rag(question="...", streaming=True): + accumulated.append(chunk.content) + if chunk.error: + print(f"Error occurred: {chunk.error}") + print(f"Partial response: {''.join(accumulated)}") + break +except Exception as e: + print(f"Streaming error: {e}") + print(f"Partial response: {''.join(accumulated)}") +``` + +#### Usimamizi wa Rasilimali + +**Usaidizi wa Kidhibiti wa Mazingira:** +```python +# Automatic cleanup +with Api(url="http://localhost:8088/") as api: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +# All connections automatically closed + +# Manual cleanup +api = Api(url="http://localhost:8088/") +try: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +finally: + api.close() # Explicitly close all connections (WebSocket, bulk, etc.) +``` + +#### Uunganishaji na Uendeshaji Sambamba + +**Ulinzi wa Mfumo wa Uendeshaji (Thread Safety)**: +Kila mfano wa `Api` huendeleza muunganisho wake mwenyewe. +Usafirishaji wa WebSocket hutumia kufuli kwa ajili ya uunganishaji salama wa ombi. +Mitandao mingi inaweza kushiriki mfano wa `Api` kwa usalama. +Iterators za utiririshaji hazina ulinzi wa mfumo wa uendeshaji (zinatumika kutoka kwenye mtandao mmoja). + +**Usaidizi wa Async** (tazama baadaye): +```python +# Phase 2 enhancement (not in initial scope) +import asyncio + +async def main(): + api = await AsyncApi(url="ws://localhost:8088/") + flow = api.flow().id("default") + + async for chunk in flow.agent(question="...", streaming=True): + print(chunk.content) + + await api.close() + +asyncio.run(main()) +``` + +## Mambo ya Kuzingatia ya Usalama + +### Uthibitisho + +**Parameta ya Tokeni**: +```python +# No authentication (default) +api = Api(url="http://localhost:8088/") + +# With authentication +api = Api(url="http://localhost:8088/", token="mytoken") +``` + +**Usafirishaji (Transport) wa REST:** +Alama ya utambulisho (Bearer token) kupitia kichwa (header) cha `Authorization` +Inatumika kiotomatiki kwa ombi zote za REST +Muundo: `Authorization: Bearer ` + +**Usafirishaji (Transport) wa WebSocket:** +Alama ya utambulisho (Token) kupitia parameter ya swali (query parameter) iliyoongezwa kwenye URL ya WebSocket +Inatumika kiotomatiki wakati wa kuunganisha +Muundo: `ws://localhost:8088/api/v1/socket?token=` + +**Utekelezaji (Implementation):** +```python +class SocketClient: + def _connect(self) -> WebSocket: + # Construct WebSocket URL with optional token + ws_url = f"{self.url}/api/v1/socket" + if self.token: + ws_url = f"{ws_url}?token={self.token}" + # Connect to WebSocket + return websocket.connect(ws_url) +``` + +**Mfano**: +```python +# REST with auth +api = Api(url="http://localhost:8088/", token="mytoken") +flow = api.flow().id("default") +# All REST calls include: Authorization: Bearer mytoken + +# WebSocket with auth +socket = api.socket() +# Connects to: ws://localhost:8088/api/v1/socket?token=mytoken +``` + +### Mawasiliano Salama + +Inasaidia mifumo ya WS (WebSocket) na WSS (WebSocket Secure). +Uthibitisho wa cheti cha TLS kwa miunganisho ya WSS. +Uthibitisho wa cheti unaweza kuzimwa (hiari) kwa ajili ya maendeleo (na onyo). + +### Uthibitisho wa Data + +Uthibitisho wa aina za URL (http, https, ws, wss). +Uthibitisho wa thamani za vigezo vya usafirishaji. +Uthibitisho wa mchanganyiko wa vigezo vya utiririshaji. +Uthibitisho wa aina za data za uagizaji wa jumla. + +## Masuala ya Utendaji + +### Uboreshaji wa Ucheleweshaji + +**Operesheni za LLM za Utiririshaji**: +**Wakati wa tokeni ya kwanza**: ~500ms (dhidi ya ~30s bila utiririshaji) +**Uboreshaji**: Mara 60 haraka kuliko utendaji unaohisiwa. +**Inatumika kwa**: Wakala, Graph RAG, Document RAG, Kukamilisha Nakala, Ombi. + +**Miunganisho ya Kudumu**: +**Mzigo wa muunganisho**: Huondolewa kwa ombi zijazo. +**Utambulisho wa WebSocket**: Gharama ya mara moja (~100ms). +**Inatumika kwa**: Operesheni zote wakati wa kutumia usafirishaji wa WebSocket. + +### Uboreshaji wa Kiasi + +**Operesheni za Jumla**: +**Uagizaji wa triples**: ~10,000 triples/sekunde (dhidi ya ~100/sekunde na REST kwa kila kipengele). +**Uagizaji wa embeddings**: ~5,000 embeddings/sekunde (dhidi ya ~50/sekunde na REST kwa kila kipengele). +**Uboreshaji**: Mara 100 ya kasi kwa operesheni za jumla. + +**Uongezaji wa Maombi**: +**Maombi sambamba**: Hadi maombi 15 sambamba juu ya muunganisho mmoja. +**Matumizi ya muunganisho**: Hakuna mzigo wa muunganisho kwa operesheni sambamba. + +### Masuala ya Kumbukumbu + +**Majibu ya Utiririshaji**: +Matumizi ya kumbukumbu thabiti (prosesa vipande kadri wanavyofika). +Hakuna kuhifadhi kwa jibu kamili. +Inafaa kwa matokeo marefu sana (>1MB). + +**Operesheni za Jumla**: +Uchakataji wa msingi (matumizi ya kumbukumbu thabiti). +Hakuna kupakia kwa seti data yote kwenye kumbukumbu. +Inafaa kwa seti data zilizo na milioni ya vipengele. + +### Vipimo (Yanatarajiwa) + +| Operesheni | REST (ya sasa) | WebSocket (ya utiririshaji) | Uboreshaji | +|-----------|----------------|----------------------|-------------| +| Wakala (wakati wa tokeni ya kwanza) | 30s | 0.5s | 60x | +| Graph RAG (wakati wa tokeni ya kwanza) | 25s | 0.5s | 50x | +| Uagizaji wa triples 10K | 100s | 1s | 100x | +| Uagizaji wa triples 1M | 10,000s (2.7h) | 100s (1.6m) | 100x | +| Maombi madogo 10 sambamba | 5s (mfululizo) | 0.5s (sambamba) | 10x | + +## Mkakati wa Majaribio + +### Majaribio ya Kitengo + +**Safu ya Usafirishaji** (`test_transport.py`): +Jaribu ombi na majibu ya usafirishaji wa REST +Jaribu muunganisho wa usafirishaji wa WebSocket +Jaribu muunganisho wa upya wa usafirishaji wa WebSocket +Jaribu uunganishaji wa ombi +Jaribu uchanganuzi wa majibu ya utiririshaji +Unda seva bandia ya WebSocket kwa vipimo vya uhakika + +**Mbinu za API** (`test_flow.py`, `test_library.py`, n.k.): +Jaribu mbinu mpya ukitumia usafirishaji bandia +Jaribu usimamizi wa vigezo vya utiririshaji +Jaribu vichanganuzi vya operesheni za wingi +Jaribu usimamizi wa makosa + +**Aina** (`test_types.py`): +Jaribu aina mpya za vipande vya utiririshaji +Jaribu userikali/kusierikisha aina + +### Vipimo vya Uunganisho + +**REST Kamili** (`test_integration_rest.py`): +Jaribu operesheni zote dhidi ya Lango halisi (mode ya REST) +Hakikisha utangamano wa nyuma +Jaribu hali za makosa + +**WebSocket Kamili** (`test_integration_websocket.py`): +Jaribu operesheni zote dhidi ya Lango halisi (mode ya WebSocket) +Jaribu operesheni za utiririshaji +Jaribu operesheni za wingi +Jaribu ombi la wakati mmoja +Jaribu urejesho wa muunganisho + +**Huduma za Utiririshaji** (`test_streaming_integration.py`): +Jaribu utiririshaji wa wakala (mawazo, uchunguzi, majibu) +Jaribu utiririshaji wa RAG (vipande vya hatua kwa hatua) +Jaribu utiririshaji wa kukamilisha maandishi (token kwa token) +Jaribu utiririshaji wa ombi +Jaribu usimamizi wa makosa wakati wa utiririshaji + +**Operesheni za Wingi** (`test_bulk_integration.py`): +Jaribu uingizaji/utoaji wa wingi wa vitri (vitu 1K, 10K, 100K) +Jaribu uingizaji/utoaji wa wingi wa uainishaji +Jaribu matumizi ya kumbukumbu wakati wa operesheni za wingi +Jaribu ufuatiliaji wa maendeleo + +### Vipimo vya Utendaji + +**Viashiria vya Kuchelewesha** (`test_performance_latency.py`): +Pima muda wa tokeni ya kwanza (utiririshaji dhidi ya usio na utiririshaji) +Pima gharama ya muunganisho (REST dhidi ya WebSocket) +Linganisha na viashiria vya kutarajiwa + +**Viashiria vya Ufanisi** (`test_performance_throughput.py`): +Pima ufanisi wa uingizaji wa wingi +Pima ufanisi wa uunganishaji wa ombi +Linganisha na viashiria vya kutarajiwa + +### Vipimo vya Utangamano + +**Utangamano wa Nyuma** (`test_backward_compatibility.py`): +Endesha seti ya vipimo iliyopo dhidi ya API iliyobadilishwa +Hakikisha hakuna mabadiliko ya kuvunja utangamano +Jaribu njia ya uhamishaji kwa mifumo ya kawaida + +## Mpango wa Uhamishaji + +### Awamu ya 1: Uhamishaji Wazi (Chaguo-msingi) + +**Hakuna mabadiliko ya msimbo yanayohitajika**. Msimbo uliopo unaendelea kufanya kazi: + +```python +# Existing code works unchanged +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") +response = flow.agent(question="What is ML?", user="user123") +``` + +### Awamu ya 2: Uidhinishaji wa Utiririshaji (Rahisi) + +**Tumia kiolesura `api.socket()`** ili kuwezesha utiririshaji: + +```python +# Before: Non-streaming REST +api = Api(url="http://localhost:8088/") +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# After: Streaming WebSocket (same parameters!) +api = Api(url="http://localhost:8088/") # Same URL +socket_flow = api.socket().flow("default") + +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) +``` + +**Pointi Muhimu**: +URL sawa kwa REST na WebSocket. +Saini sawa za mbinu (rahisi kuhamisha). +Ongeza tu `.socket()` na `streaming=True`. + +### Awamu ya 3: Operesheni za Kiasi (Uwezo Mpya) + +**Tumia kiolesura cha `api.bulk()`** kwa data kubwa: + +```python +# Before: Inefficient per-item operations +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") + +for triple in my_large_triple_list: + # Slow per-item operations + # (no direct bulk insert in REST API) + pass + +# After: Efficient bulk loading +api = Api(url="http://localhost:8088/") # Same URL +bulk = api.bulk() + +# This is fast (10,000 triples/second) +bulk.import_triples(flow="default", triples=iter(my_large_triple_list)) +``` + +### Sasisho la Nyaraka + +1. **README.md**: Ongeza mifano ya utiririshaji na WebSocket +2. **Marejeleo ya API**: Andika mbinu na vigezo vyote vipya +3. **Mwongozo wa Uhamishaji**: Mwongozo wa hatua kwa hatua wa kuwezesha utiririshaji +4. **Mifano**: Ongeza skripti ya mfano kwa mifumo ya kawaida +5. **Mwongozo wa Utendaji**: Andika uboreshaji uliotarajiwa wa utendaji + +### Sera ya Kutolewa + +**Hakuna kutolewa**. API zote zilizopo zinaendelea kuungwa mkono. Hii ni uboreshaji safi. + +## Ratiba + +### Wiki ya 1: Msingi +Safu ya abstraction ya usafirishaji +Tengeneza upya msimbo wa REST uliopo +Vipimo vya kitengo kwa safu ya usafirishaji +Uthibitisho wa utangamano wa nyuma + +### Wiki ya 2: Usafirishaji wa WebSocket +Utendaji wa usafirishaji wa WebSocket +Usimamizi wa muunganisho na muunganisho upya +Ufuatiliaji wa ombi +Vipimo vya kitengo na ushirikiano + +### Wiki ya 3: Usaidizi wa Utiririshaji +Ongeza kiparamu cha utiririshaji kwa mbinu za LLM +Tengeneza utiririshaji wa jibu +Ongeza aina za vipande vya utiririshaji +Vipimo vya ushirikiano vya utiririshaji + +### Wiki ya 4: Operesheni za Kiasi +Ongeza mbinu za kuingiza/kutoa kwa wingi +Tengeneza operesheni zinazotegemea iterator +Upimaji wa utendaji +Vipimo vya ushirikiano vya operesheni za wingi + +### Wiki ya 5: Ulinganisho wa Vipengele na Nyaraka +Ongeza swali la uingizaji wa michoro +Ongeza API ya metriki +Nyaraka kamili +Mwongozo wa uhamishaji +Mfumo wa majaribio + +### Wiki ya 6: Toa +Vipimo vya mwisho vya ushirikiano +Upimaji wa utendaji +Nyaraka za kutolewa +Tangazo la jumuiya + +**Jumla ya Muda**: wiki 6 + +## Maswali ya Wazi + +### Maswali ya Ubunifu wa API + +1. **Usaidizi wa Async**: ✅ **IMEONGELEWA** - Usaidizi kamili wa async umejumuishwa katika toleo la awali + Interfeisi zote zina matoleo ya async: `async_flow()`, `async_socket()`, `async_bulk()`, `async_metrics()` + Hutoa usawa kamili kati ya API za sync na async + Muhimu kwa mifumo ya kisasa ya async (FastAPI, aiohttp) + +2. **Ufuatiliaji wa Maendeleo**: Je, operesheni za wingi zinapaswa kusaidia callbacks za maendeleo? + ```python + def progress_callback(processed: int, total: Optional[int]): + print(f"Processed {processed} items") + + bulk.import_triples(flow="default", triples=triples, on_progress=progress_callback) + ``` + **Pendekezo**: Ongezewe katika Hatua ya 2. Si muhimu kwa toleo la awali. + +3. **Mipangilio ya Muda wa Kitendo cha Uhamisho (Streaming)**: Je, tunapaswa kushughulikia vipi vipindi vya muda ambavyo vitatokea wakati wa vitendo vya uhamishaji? + **Pendekezo**: Tumia muda sawa kama vitendo visivyohusisha uhamishaji, lakini uweke upya kila wakati unapopokea sehemu (chunk). + +4. **Uwekaji Hifadhi wa Sehemu (Chunk Buffering)**: Je, tunapaswa kuweka sehemu katika hifadhi au kuzitoa mara moja? + **Pendekezo**: Zitoa mara moja ili kupunguza zaidi kuchelewesha. + +5. **Huduma za Kimataifa kupitia WebSocket**: Je, `api.socket()` inapaswa kusaidia huduma za kimataifa (maktaba, maarifa, mkusanyiko, usanidi) au tu huduma zinazohusiana na kila uhamishaji? + **Pendekezo**: Anza tu na huduma zinazohusiana na kila uhamishaji (ambapo uhamishaji una umuhimu). Ongeza huduma za kimataifa ikiwa ni lazima katika Hatua ya 2. + +### Maswali ya Utendaji + +1. **Maktaba ya WebSocket**: Je, tunapaswa kutumia `websockets`, `websocket-client`, au `aiohttp`? + **Pendekezo**: `websockets` (ya kisasa, iliyokamilika, na inayohudumiwa vizuri). Ifunike katika muundo wa kazi (synchronous) kwa kutumia `asyncio.run()`. + +2. **Uunganishaji wa Pamoja (Connection Pooling)**: Je, tunapaswa kusaidia mifano mingi ya `Api` inayoshiriki muunganisho mmoja? + **Pendekezo**: Acha hadi Hatua ya 2. Kila mfano wa `Api` una muunganisho wake mwenyewe mwanzo. + +3. **Matumizi ya Muunganisho**: Je, `SocketClient` na `BulkClient` zinapaswa kushiriki muunganisho mmoja wa WebSocket, au kutumia muunganisho tofauti? + **Pendekezo**: Muunganisho tofauti. Utendaji rahisi, upeo wa wazi. + +4. **Muunganisho wa Kwanza au wa Baadaye**: Je, muunganisho wa WebSocket unapaswa kuundwa katika `api.socket()` au wakati wa ombi la kwanza? + **Pendekezo**: Muunganisho wa baadaye (wakati wa ombi la kwanza). Inazuia gharama ya muunganisho ikiwa mtumiaji hutumia tu mbinu za REST. + +### Maswali ya Majaribio + +1. **Lango la Majaribio (Mock Gateway)**: Je, tunapaswa kuunda lango la majaribio (mock) ambalo ni rahisi kwa ajili ya majaribio, au tujaribu dhidi ya lango halisi? + **Pendekezo**: Zote. Tumia lango la majaribio kwa majaribio ya kitengo, na lango halisi kwa majaribio ya ujumuishaji. + +2. **Majaribio ya Utendaji (Performance Regression Tests)**: Je, tunapaswa kuongeza majaribio ya utendaji (performance) ya kiotomatiki katika mfumo wa CI (Continuous Integration)? + **Pendekezo**: Ndiyo, lakini na viwango vikubwa vya uvumilivu ili kuzingatia tofauti katika mazingira ya CI. + +## Marejeleo + +### Vipimo vya Teknolojia Vilivyohusiana +`docs/tech-specs/streaming-llm-responses.md` - Utaratibu wa utiririshaji katika lango. +`docs/tech-specs/rag-streaming-support.md` - Usaidizi wa utiririshaji wa RAG. + +### Faili za Utendaji +`trustgraph-base/trustgraph/api/` - Chanzo cha API ya Python. +`trustgraph-flow/trustgraph/gateway/` - Chanzo cha lango. +`trustgraph-flow/trustgraph/gateway/dispatch/mux.py` - Utaratibu wa marejeleo wa mchanganyiko wa WebSocket. + +### Nyaraka +`docs/apiSpecification.md` - Marejeleo kamili ya API. +`docs/api-status-summary.md` - Muhtasari wa hali ya API. +`README.websocket` - Nyaraka za itifaki ya WebSocket. +`STREAMING-IMPLEMENTATION-NOTES.txt` - Maelezo kuhusu utaratibu wa utiririshaji. + +### Maktabu ya Nje +`websockets` - Maktaba ya WebSocket ya Python (https://websockets.readthedocs.io/). +`requests` - Maktaba ya HTTP ya Python (ilipo tayari). diff --git a/docs/tech-specs/python-api-refactor.tr.md b/docs/tech-specs/python-api-refactor.tr.md new file mode 100644 index 00000000..10289965 --- /dev/null +++ b/docs/tech-specs/python-api-refactor.tr.md @@ -0,0 +1,1508 @@ +# Python API Yeniden Düzenleme Teknik Özellikleri + +## Genel Bakış + +Bu özellik, TrustGraph Python API istemci kitaplığının, API Gateway ile özellik uyumluluğu sağlamak ve modern gerçek zamanlı iletişim kalıplarına destek eklemek için kapsamlı bir şekilde yeniden düzenlenmesini açıklamaktadır. + +Bu yeniden düzenleme, dört birincil kullanım durumunu ele almaktadır: + +1. **Akışlı LLM Etkileşimleri**: LLM yanıtlarının (ajan, grafik RAG, belge RAG, metin tamamlama, istemler) gerçek zamanlı olarak akışını etkinleştirin ve ilk belirteç için ~60 kat daha düşük gecikme süresi sağlayın (30 saniye yerine 500 ms). +2. **Toplu Veri İşlemleri**: Büyük ölçekli bilgi grafiği yönetimi için üçlülerin, grafik gömülme ve belge gömülme verilerinin verimli toplu olarak aktarılmasını ve dışa aktarılmasını destekleyin. +3. **Özellik Uyumluluğu**: Her API Gateway uç noktasının, grafik gömülme sorgusu da dahil olmak üzere, karşılık gelen bir Python API yöntemine sahip olduğundan emin olun. +4. **Sürekli Bağlantılar**: Çoklu istekler ve azaltılmış bağlantı yükü için WebSocket tabanlı iletişimi etkinleştirin. + +## Hedefler + +**Özellik Uyumluluğu**: Her Gateway API hizmetinin karşılık gelen bir Python API yöntemi vardır. +**Akış Desteği**: Tüm akış özellikli hizmetler (ajan, RAG, metin tamamlama, istem), Python API'de akışı destekler. +**WebSocket Taşıyıcı Katmanı**: Kalıcı bağlantılar ve çoklama için isteğe bağlı bir WebSocket taşıyıcı katmanı ekleyin. +**Toplu İşlemler**: Üçlüler, grafik gömülme ve belge gömülme için verimli toplu aktarım/dışa aktarma ekleyin. +**Tam Asenkron Desteği**: Tüm arayüzler (REST, WebSocket, toplu işlemler, ölçümler) için eksiksiz asenkron/bekleme uygulaması. +**Geriye Dönük Uyumluluk**: Mevcut kod, herhangi bir değişiklik yapılmadan çalışmaya devam eder. +**Tip Güvenliği**: Veri sınıfları ve tip ipuçlarıyla tip güvenli arayüzleri koruyun. +**Aşamalı Geliştirme**: Akış ve asenkron, açık arayüz seçimi yoluyla isteğe bağlıdır. +**Performans**: Akış işlemlerinde 60 kat gecikme iyileştirmesi elde edin. +**Modern Python**: Maksimum esneklik için hem senkron hem de asenkron paradigmaları destekleyin. + +## Arka Plan + +### Mevcut Durum + +Python API'si (`trustgraph-base/trustgraph/api/`), aşağıdaki modüllere sahip REST tabanlı bir istemci kitaplığıdır: + +`flow.py`: Akış yönetimi ve akış kapsamlı hizmetler (50 yöntem) +`library.py`: Belge kitaplığı işlemleri (9 yöntem) +`knowledge.py`: KG çekirdek yönetimi (4 yöntem) +`collection.py`: Koleksiyon meta verileri (3 yöntem) +`config.py`: Yapılandırma yönetimi (6 yöntem) +`types.py`: Veri türü tanımları (5 veri sınıfı) + +**Toplam İşlem**: 50/59 (%85 kapsama) + +### Mevcut Sınırlamalar + +**Eksik İşlemler**: +Grafik gömülme sorgusu (grafik varlıkları üzerindeki semantik arama) +Üçlüler, grafik gömülme, belge gömülme, varlık bağlamları, nesneler için toplu aktarım/dışa aktarma +Ölçüm uç noktası + +**Eksik Yetenekler**: +LLM hizmetleri için akış desteği +WebSocket taşıyıcısı +Çoklu eşzamanlı istekler +Kalıcı bağlantılar + +**Performans Sorunları**: +LLM etkileşimleri için yüksek gecikme süresi (~30 saniye ilk belirteç) +Toplu veri aktarımı için verimsiz (her öğe için REST isteği) +Birden çok sıralı işlem için bağlantı yükü + +**Kullanıcı Deneyimi Sorunları**: +LLM oluşturma sırasında gerçek zamanlı geri bildirim yok +Uzun süren LLM işlemlerini iptal edememe +Toplu işlemler için zayıf ölçeklenebilirlik + +### Etki + +Kasım 2024'te Gateway API'ye yapılan akış geliştirmesi, LLM etkileşimleri için 60 kat gecikme iyileştirmesi (30 saniye yerine 500 ms ilk belirteç) sağladı, ancak Python API kullanıcıları bu yeteneği kullanamıyor. Bu, Python ve Python dışı kullanıcılar arasında önemli bir deneyim boşluğuna yol açmaktadır. + +## Teknik Tasarım + +### Mimari + +Yeniden düzenlenmiş Python API'si, farklı iletişim kalıpları için ayrı nesneler kullanan **modüler bir arayüz yaklaşımı** kullanır. Tüm arayüzler hem **senkron hem de asenkron** varyantlarda mevcuttur: + +1. **REST Arayüzü** (mevcut, geliştirilmiş) + **Senkron**: `api.flow()`, `api.library()`, `api.knowledge()`, `api.collection()`, `api.config()` + **Asenkron**: `api.async_flow()` + Senkron/asenkron istek/yanıt + Basit bağlantı modeli + Geriye dönük uyumluluk için varsayılan + +2. **WebSocket Arayüzü** (yeni) + **Senkron**: `api.socket()` + **Asenkron**: `api.async_socket()` + Kalıcı bağlantı + Çoklu istekler + Akış desteği + İşlevselliğin örtüştüğü yerlerde REST ile aynı yöntem imzaları + +3. **Toplu İşlemler Arayüzü** (yeni) + **Senkron**: `api.bulk()` + **Asenkron**: `api.async_bulk()` + Verimlilik için WebSocket tabanlı + Iterator/AsyncIterator tabanlı aktarım/dışa aktarma + Büyük veri kümelerini işler + +4. **Ölçüm Arayüzü** (yeni) + **Senkron**: `api.metrics()` + **Asenkron**: `api.async_metrics()` + Prometheus ölçümleri erişimi + +```python +import asyncio + +# Synchronous interfaces +api = Api(url="http://localhost:8088/") + +# REST (existing, unchanged) +flow = api.flow().id("default") +response = flow.agent(question="...", user="...") + +# WebSocket (new) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="...", user="...") +for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk) + +# Bulk operations (new) +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Asynchronous interfaces +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST (new) + flow = api.async_flow().id("default") + response = await flow.agent(question="...", user="...") + + # Async WebSocket (new) + socket_flow = api.async_socket().flow("default") + async for chunk in socket_flow.agent(question="...", streaming=True): + print(chunk) + + # Async bulk operations (new) + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + +asyncio.run(main()) +``` + +**Temel Tasarım Prensipleri**: +**Tüm arayüzler için aynı URL**: `Api(url="http://localhost:8088/")`, tüm arayüzler için geçerlidir. +**Senkron/Asenkron simetri**: Her arayüzün hem senkron hem de asenkron varyantları vardır ve yöntem imzaları aynıdır. +**Aynı imzalar**: İşlevsellik örtüşüyorsa, REST ve WebSocket, senkron ve asenkron arasında yöntem imzaları aynıdır. +**Aşamalı iyileştirme**: İhtiyaçlara göre arayüzü seçin (basit işlemler için REST, akış için WebSocket, büyük veri kümeleri için Bulk, modern çerçeveler için asenkron). +**Açık niyet**: `api.socket()`, WebSocket'i belirtir, `api.async_socket()`, asenkron WebSocket'i belirtir. +**Geriye uyumlu**: Mevcut kod değişmeden kalır. + +### Bileşenler + +#### 1. Temel API Sınıfı (Değiştirilmiş) + +Modül: `trustgraph-base/trustgraph/api/api.py` + +**Geliştirilmiş API Sınıfı**: + +```python +class Api: + def __init__(self, url: str, timeout: int = 60, token: Optional[str] = None): + self.url = url + self.timeout = timeout + self.token = token # Optional bearer token for REST, query param for WebSocket + self._socket_client = None + self._bulk_client = None + self._async_flow = None + self._async_socket_client = None + self._async_bulk_client = None + + # Existing synchronous methods (unchanged) + def flow(self) -> Flow: + """Synchronous REST-based flow interface""" + pass + + def library(self) -> Library: + """Synchronous REST-based library interface""" + pass + + def knowledge(self) -> Knowledge: + """Synchronous REST-based knowledge interface""" + pass + + def collection(self) -> Collection: + """Synchronous REST-based collection interface""" + pass + + def config(self) -> Config: + """Synchronous REST-based config interface""" + pass + + # New synchronous methods + def socket(self) -> SocketClient: + """Synchronous WebSocket-based interface for streaming operations""" + if self._socket_client is None: + self._socket_client = SocketClient(self.url, self.timeout, self.token) + return self._socket_client + + def bulk(self) -> BulkClient: + """Synchronous bulk operations interface for import/export""" + if self._bulk_client is None: + self._bulk_client = BulkClient(self.url, self.timeout, self.token) + return self._bulk_client + + def metrics(self) -> Metrics: + """Synchronous metrics interface""" + return Metrics(self.url, self.timeout, self.token) + + # New asynchronous methods + def async_flow(self) -> AsyncFlow: + """Asynchronous REST-based flow interface""" + if self._async_flow is None: + self._async_flow = AsyncFlow(self.url, self.timeout, self.token) + return self._async_flow + + def async_socket(self) -> AsyncSocketClient: + """Asynchronous WebSocket-based interface for streaming operations""" + if self._async_socket_client is None: + self._async_socket_client = AsyncSocketClient(self.url, self.timeout, self.token) + return self._async_socket_client + + def async_bulk(self) -> AsyncBulkClient: + """Asynchronous bulk operations interface for import/export""" + if self._async_bulk_client is None: + self._async_bulk_client = AsyncBulkClient(self.url, self.timeout, self.token) + return self._async_bulk_client + + def async_metrics(self) -> AsyncMetrics: + """Asynchronous metrics interface""" + return AsyncMetrics(self.url, self.timeout, self.token) + + # Resource management + def close(self) -> None: + """Close all synchronous connections""" + if self._socket_client: + self._socket_client.close() + if self._bulk_client: + self._bulk_client.close() + + async def aclose(self) -> None: + """Close all asynchronous connections""" + if self._async_socket_client: + await self._async_socket_client.aclose() + if self._async_bulk_client: + await self._async_bulk_client.aclose() + if self._async_flow: + await self._async_flow.aclose() + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + async def __aenter__(self): + return self + + async def __aexit__(self, *args): + await self.aclose() +``` + +#### 2. Senkron WebSocket İstemcisi + +Modül: `trustgraph-base/trustgraph/api/socket_client.py` (yeni) + +**SocketClient Sınıfı**: + +```python +class SocketClient: + """Synchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> SocketFlowInstance: + """Get flow instance for WebSocket operations""" + return SocketFlowInstance(self, flow_id) + + def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Uses asyncio.run() internally to wrap async websockets library + pass + + def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + # Synchronous wrapper around async WebSocket calls + pass + + def close(self) -> None: + """Close WebSocket connection""" + pass + +class SocketFlowInstance: + """Synchronous WebSocket flow instance with same interface as REST FlowInstance""" + def __init__(self, client: SocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance + def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, Iterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**Temel Özellikler**: +Tembel bağlantı (yalnızca ilk istek gönderildiğinde bağlantı kurulur) +İstek çoklama (en fazla 15 eşzamanlı) +Bağlantı kesildiğinde otomatik yeniden bağlanma +Akış yanıtı ayrıştırma +İş parçacığı güvenli çalışma +Asenkron WebSocket kütüphanesi için senkron sarmalayıcı + +#### 3. Asenkron WebSocket İstemcisi + +Modül: `trustgraph-base/trustgraph/api/async_socket_client.py` (yeni) + +**AsyncSocketClient Sınıfı**: + +```python +class AsyncSocketClient: + """Asynchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> AsyncSocketFlowInstance: + """Get async flow instance for WebSocket operations""" + return AsyncSocketFlowInstance(self, flow_id) + + async def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Native async websockets library + pass + + async def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + pass + + async def aclose(self) -> None: + """Close WebSocket connection""" + pass + +class AsyncSocketFlowInstance: + """Asynchronous WebSocket flow instance""" + def __init__(self, client: AsyncSocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance (but async) + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, AsyncIterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**Temel Özellikler**: +Yerleşik async/await desteği +Asenkron uygulamalar için verimli (FastAPI, aiohttp) +İş parçacığı engellemesi yok +Senkron sürümle aynı arayüz +Akış için AsyncIterator + +#### 4. Senkron Toplu İşlemler İstemcisi + +Modül: `trustgraph-base/trustgraph/api/bulk_client.py` (yeni) + +**BulkClient Sınıfı**: + +```python +class BulkClient: + """Synchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + def import_triples( + self, + flow: str, + triples: Iterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + def export_triples( + self, + flow: str, + **kwargs + ) -> Iterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + def import_graph_embeddings( + self, + flow: str, + embeddings: Iterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> Iterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + def close(self) -> None: + """Close connections""" + pass +``` + +**Temel Özellikler**: +Sabit bellek kullanımı için yineleyici tabanlı. +Her işlem için özel WebSocket bağlantıları. +İlerleme takibi (isteğe bağlı geri çağırma). +Kısmi başarı raporlamasıyla hata yönetimi. + +#### 5. Asenkron Toplu İşlemler İstemcisi + +Modül: `trustgraph-base/trustgraph/api/async_bulk_client.py` (yeni) + +**AsyncBulkClient Sınıfı**: + +```python +class AsyncBulkClient: + """Asynchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + async def import_triples( + self, + flow: str, + triples: AsyncIterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + async def export_triples( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + async def import_graph_embeddings( + self, + flow: str, + embeddings: AsyncIterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + async def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + async def aclose(self) -> None: + """Close connections""" + pass +``` + +**Temel Özellikler**: +Sabit bellek kullanımı için AsyncIterator tabanlı. +Asenkron uygulamalar için verimli. +Yerel asenkron/bekle destek. +Senkron sürümle aynı arayüz. + +#### 6. REST Akışı API'si (Senkron - Değişmedi) + +Modül: `trustgraph-base/trustgraph/api/flow.py` + +REST Akışı API'si, geriye dönük uyumluluk için **tamamen değişmeden** kalmıştır. Tüm mevcut yöntemler çalışmaya devam etmektedir: + +`Flow.list()`, `Flow.start()`, `Flow.stop()`, vb. +`FlowInstance.agent()`, `FlowInstance.text_completion()`, `FlowInstance.graph_rag()`, vb. +Tüm mevcut imzalar ve dönüş türleri korunmuştur. + +**Yeni**: Özellik uyumluluğu için `graph_embeddings_query()`'ı REST FlowInstance'a ekleyin: + +```python +class FlowInstance: + # All existing methods unchanged... + + # New: Graph embeddings query (REST) + def graph_embeddings_query( + self, + text: str, + user: str, + collection: str, + limit: int = 10, + **kwargs + ) -> List[Dict[str, Any]]: + """Query graph embeddings for semantic search""" + # Calls POST /api/v1/flow/{flow}/service/graph-embeddings + pass +``` + +#### 7. Asenkron REST Akışı API'si + +Modül: `trustgraph-base/trustgraph/api/async_flow.py` (yeni) + +**AsyncFlow ve AsyncFlowInstance Sınıfları:** + +```python +class AsyncFlow: + """Asynchronous REST-based flow interface""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def list(self) -> List[Dict[str, Any]]: + """List all flows""" + pass + + async def get(self, id: str) -> Dict[str, Any]: + """Get flow definition""" + pass + + async def start(self, class_name: str, id: str, description: str, parameters: Dict) -> None: + """Start a flow""" + pass + + async def stop(self, id: str) -> None: + """Stop a flow""" + pass + + def id(self, flow_id: str) -> AsyncFlowInstance: + """Get async flow instance""" + return AsyncFlowInstance(self.url, self.timeout, self.token, flow_id) + + async def aclose(self) -> None: + """Close connection""" + pass + +class AsyncFlowInstance: + """Asynchronous REST flow instance""" + + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + **kwargs + ) -> Dict[str, Any]: + """Async agent execution""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + **kwargs + ) -> str: + """Async text completion""" + pass + + async def graph_rag( + self, + question: str, + user: str, + collection: str, + **kwargs + ) -> str: + """Async graph RAG""" + pass + + # ... all other FlowInstance methods as async versions +``` + +**Temel Özellikler**: +`aiohttp` veya `httpx` kullanarak yerel asenkron HTTP +Senkron REST API'si ile aynı yöntem imzaları +Akış yok (akış için `async_socket()`'ı kullanın) +Asenkron uygulamalar için verimli + +#### 8. Ölçüm API'si + +Modül: `trustgraph-base/trustgraph/api/metrics.py` (yeni) + +**Senkron Ölçümler**: + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +**Asenkron Metrikler**: + +```python +class AsyncMetrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +#### 9. Gelişmiş Tipler + +Modül: `trustgraph-base/trustgraph/api/types.py` (değiştirildi) + +**Yeni Tipler**: + +```python +from typing import Iterator, Union, Dict, Any +import dataclasses + +@dataclasses.dataclass +class StreamingChunk: + """Base class for streaming chunks""" + content: str + end_of_message: bool = False + +@dataclasses.dataclass +class AgentThought(StreamingChunk): + """Agent reasoning chunk""" + chunk_type: str = "thought" + +@dataclasses.dataclass +class AgentObservation(StreamingChunk): + """Agent tool observation chunk""" + chunk_type: str = "observation" + +@dataclasses.dataclass +class AgentAnswer(StreamingChunk): + """Agent final answer chunk""" + chunk_type: str = "final-answer" + end_of_dialog: bool = False + +@dataclasses.dataclass +class RAGChunk(StreamingChunk): + """RAG streaming chunk""" + end_of_stream: bool = False + error: Optional[Dict[str, str]] = None + +# Type aliases for clarity +AgentStream = Iterator[Union[AgentThought, AgentObservation, AgentAnswer]] +RAGStream = Iterator[RAGChunk] +CompletionStream = Iterator[str] +``` + +#### 6. Metrik API + +Modül: `trustgraph-base/trustgraph/api/metrics.py` (yeni) + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +### Uygulama Yaklaşımı + +#### 1. Aşama: Temel API Geliştirmeleri (1. Hafta) + +1. `socket()`, `bulk()` ve `metrics()` yöntemlerini `Api` sınıfına ekleyin +2. WebSocket ve toplu iş yükleri için tembel başlatmayı uygulayın +3. Bağlam yöneticisi desteğini ekleyin (`__enter__`, `__exit__`) +4. Temizleme için `close()` yöntemini ekleyin +5. API sınıfı geliştirmeleri için birim testleri ekleyin +6. Geriye dönük uyumluluğu doğrulayın + +**Geriye Dönük Uyumluluk**: Herhangi bir uyumsuz değişiklik yok. Sadece yeni yöntemler. + +#### 2. Aşama: WebSocket İstemcisi (2-3. Haftalar) + +1. Bağlantı yönetimi için `SocketClient` sınıfını uygulayın +2. `SocketFlowInstance`'ı `FlowInstance` ile aynı yöntem imzalarına sahip olacak şekilde uygulayın +3. İstek çoklama desteğini ekleyin (en fazla 15 eşzamanlı) +4. Farklı parça türleri için akış yanıtı ayrıştırmasını ekleyin +5. Otomatik yeniden bağlantı mantığını ekleyin +6. Birim ve entegrasyon testlerini ekleyin +7. WebSocket kullanım kalıplarını belgeleyin + +**Geriye Dönük Uyumluluk**: Sadece yeni bir arayüz. Mevcut kod üzerinde hiçbir etkisi yok. + +#### 3. Aşama: Akış Desteği (3-4. Haftalar) + +1. Akış parça türü sınıflarını ekleyin (`AgentThought`, `AgentObservation`, `AgentAnswer`, `RAGChunk`) +2. `SocketClient` içinde akış yanıtı ayrıştırmasını uygulayın +3. `SocketFlowInstance` içindeki tüm LLM yöntemlerine akış parametresini ekleyin +4. Akış sırasında hata durumlarını işleyin +5. Akış için birim ve entegrasyon testlerini ekleyin +6. Belgelerdeki akış örneklerini ekleyin + +**Geriye Dönük Uyumluluk**: Sadece yeni bir arayüz. Mevcut REST API değişmedi. + +#### 4. Aşama: Toplu İşlemler (4-5. Haftalar) + +1. `BulkClient` sınıfını uygulayın +2. Üçlüler, gömülü veriler, bağlamlar, nesneler için toplu içe/dışa aktarma yöntemlerini ekleyin +3. Sabit bellek için yineleyici tabanlı işleme uygulayın +4. İlerleme takibini ekleyin (isteğe bağlı geri çağırma) +5. Kısmi başarı raporlamasıyla hata işleme ekleyin +6. Birim ve entegrasyon testlerini ekleyin +7. Toplu işlem örneklerini ekleyin + +**Geriye Dönük Uyumluluk**: Sadece yeni bir arayüz. Mevcut kod üzerinde hiçbir etkisi yok. + +#### 5. Aşama: Özellik Eşitliği ve İyileştirmeler (5. Hafta) + +1. REST `FlowInstance`'ine `graph_embeddings_query()`'ı ekleyin +2. `Metrics` sınıfını uygulayın +3. Kapsamlı entegrasyon testlerini ekleyin +4. Performans karşılaştırması +5. Tüm belgeleri güncelleyin +6. Geçiş kılavuzu oluşturun + +**Geriye Dönük Uyumluluk**: Sadece yeni yöntemler. Mevcut kod üzerinde hiçbir etkisi yok. + +### Veri Modelleri + +#### Arayüz Seçimi + +```python +# Single API instance, same URL for all interfaces +api = Api(url="http://localhost:8088/") + +# Synchronous interfaces +rest_flow = api.flow().id("default") # Sync REST +socket_flow = api.socket().flow("default") # Sync WebSocket +bulk = api.bulk() # Sync bulk operations +metrics = api.metrics() # Sync metrics + +# Asynchronous interfaces +async_rest_flow = api.async_flow().id("default") # Async REST +async_socket_flow = api.async_socket().flow("default") # Async WebSocket +async_bulk = api.async_bulk() # Async bulk operations +async_metrics = api.async_metrics() # Async metrics +``` + +#### Akış Yanıt Türleri + +**Ajan Akışı:** + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - non-streaming (same signature) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - streaming (new) +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentThought): + print(f"Thinking: {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"Observed: {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"Answer: {chunk.content}") + if chunk.end_of_dialog: + break +``` + +**RAG Akışı:** + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.graph_rag(question="What is Python?", user="user123", collection="default") +print(response) + +# WebSocket interface - streaming (new) +socket_flow = api.socket().flow("default") +for chunk in socket_flow.graph_rag( + question="What is Python?", + user="user123", + collection="default", + streaming=True +): + print(chunk.content, end="", flush=True) + if chunk.end_of_stream: + break +``` + +**Toplu İşlemler (Senkron)**: + +```python +api = Api(url="http://localhost:8088/") + +# Bulk import triples +def triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Bulk export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +**Toplu İşlemler (Asenkron)**: + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async bulk import triples + async def async_triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + + # Async bulk export triples + async for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") + +asyncio.run(main()) +``` + +**Asenkron REST Örneği**: + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST flow operations + flow = api.async_flow().id("default") + response = await flow.agent(question="What is ML?", user="user123") + print(response["response"]) + +asyncio.run(main()) +``` + +**Asenkron WebSocket Akışı Örneği**: + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async WebSocket streaming + socket = api.async_socket() + flow = socket.flow("default") + + async for chunk in flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) + if chunk.end_of_dialog: + break + +asyncio.run(main()) +``` + +### API'ler + +#### Yeni API'ler + +1. **Temel API Sınıfı**: + **Senkron**: + `Api.socket()` - Senkron WebSocket istemcisini al + `Api.bulk()` - Senkron toplu işlem istemcisini al + `Api.metrics()` - Senkron ölçüm istemcisini al + `Api.close()` - Tüm senkron bağlantıları kapat + Bağlam yöneticisi desteği (`__enter__`, `__exit__`) + **Asenkron**: + `Api.async_flow()` - Asenkron REST akışı istemcisini al + `Api.async_socket()` - Asenkron WebSocket istemcisini al + `Api.async_bulk()` - Asenkron toplu işlem istemcisini al + `Api.async_metrics()` - Asenkron ölçüm istemcisini al + `Api.aclose()` - Tüm asenkron bağlantıları kapat + Asenkron bağlam yöneticisi desteği (`__aenter__`, `__aexit__`) + +2. **Senkron WebSocket İstemcisi**: + `SocketClient.flow(flow_id)` - WebSocket akışı örneğini al + `SocketFlowInstance.agent(..., streaming: bool = False)` - İsteğe bağlı akışla birlikte aracı + `SocketFlowInstance.text_completion(..., streaming: bool = False)` - İsteğe bağlı akışla birlikte metin tamamlama + `SocketFlowInstance.graph_rag(..., streaming: bool = False)` - İsteğe bağlı akışla birlikte grafik RAG + `SocketFlowInstance.document_rag(..., streaming: bool = False)` - İsteğe bağlı akışla birlikte belge RAG + `SocketFlowInstance.prompt(..., streaming: bool = False)` - İsteğe bağlı akışla birlikte istem + `SocketFlowInstance.graph_embeddings_query()` - Grafik gömme sorgusu + Aynı imzaya sahip diğer tüm FlowInstance yöntemleri + +3. **Asenkron WebSocket İstemcisi**: + `AsyncSocketClient.flow(flow_id)` - Asenkron WebSocket akışı örneğini al + `AsyncSocketFlowInstance.agent(..., streaming: bool = False)` - İsteğe bağlı akışla birlikte asenkron aracı + `AsyncSocketFlowInstance.text_completion(..., streaming: bool = False)` - İsteğe bağlı akışla birlikte asenkron metin tamamlama + `AsyncSocketFlowInstance.graph_rag(..., streaming: bool = False)` - İsteğe bağlı akışla birlikte asenkron grafik RAG + `AsyncSocketFlowInstance.document_rag(..., streaming: bool = False)` - İsteğe bağlı akışla birlikte asenkron belge RAG + `AsyncSocketFlowInstance.prompt(..., streaming: bool = False)` - İsteğe bağlı akışla birlikte asenkron istem + `AsyncSocketFlowInstance.graph_embeddings_query()` - Asenkron grafik gömme sorgusu + Diğer tüm FlowInstance yöntemleri asenkron versiyonlardır + +4. **Senkron Toplu İşlem İstemcisi**: + `BulkClient.import_triples(flow, triples)` - Toplu üçlü içe aktarma + `BulkClient.export_triples(flow)` - Toplu üçlü dışa aktarma + `BulkClient.import_graph_embeddings(flow, embeddings)` - Toplu grafik gömme içe aktarma + `BulkClient.export_graph_embeddings(flow)` - Toplu grafik gömme dışa aktarma + `BulkClient.import_document_embeddings(flow, embeddings)` - Toplu belge gömme içe aktarma + `BulkClient.export_document_embeddings(flow)` - Toplu belge gömme dışa aktarma + `BulkClient.import_entity_contexts(flow, contexts)` - Toplu varlık bağlamları içe aktarma + `BulkClient.export_entity_contexts(flow)` - Toplu varlık bağlamları dışa aktarma + `BulkClient.import_objects(flow, objects)` - Toplu nesneler içe aktarma + +5. **Asenkron Toplu İşlem İstemcisi**: + `AsyncBulkClient.import_triples(flow, triples)` - Asenkron toplu üçlü içe aktarma + `AsyncBulkClient.export_triples(flow)` - Asenkron toplu üçlü dışa aktarma + `AsyncBulkClient.import_graph_embeddings(flow, embeddings)` - Asenkron toplu grafik gömme içe aktarma + `AsyncBulkClient.export_graph_embeddings(flow)` - Asenkron toplu grafik gömme dışa aktarma + `AsyncBulkClient.import_document_embeddings(flow, embeddings)` - Asenkron toplu belge gömme içe aktarma + `AsyncBulkClient.export_document_embeddings(flow)` - Asenkron toplu belge gömme dışa aktarma + `AsyncBulkClient.import_entity_contexts(flow, contexts)` - Asenkron toplu varlık bağlamları içe aktarma + `AsyncBulkClient.export_entity_contexts(flow)` - Asenkron toplu varlık bağlamları dışa aktarma + `AsyncBulkClient.import_objects(flow, objects)` - Asenkron toplu nesneler içe aktarma + +6. **Asenkron REST Akışı İstemcisi**: + `AsyncFlow.list()` - Tüm akışları listele (asenkron) + `AsyncFlow.get(id)` - Akış tanımını al (asenkron) + `AsyncFlow.start(...)` - Akışı başlat (asenkron) + `AsyncFlow.stop(id)` - Akışı durdur (asenkron) + `AsyncFlow.id(flow_id)` - Asenkron akış örneğini al + `AsyncFlowInstance.agent(...)` - Asenkron aracı yürütme + `AsyncFlowInstance.text_completion(...)` - Asenkron metin tamamlama + `AsyncFlowInstance.graph_rag(...)` - Asenkron grafik RAG + Diğer tüm FlowInstance yöntemleri asenkron versiyonlardır + +7. **Ölçüm İstemcileri**: + `Metrics.get()` - Senkron Prometheus ölçümleri + `AsyncMetrics.get()` - Asenkron Prometheus ölçümleri + +8. **REST Akışı API Geliştirmesi**: + `FlowInstance.graph_embeddings_query()` - Grafik gömme sorgusu (senkron özellik uyumluluğu) + `AsyncFlowInstance.graph_embeddings_query()` - Grafik gömme sorgusu (asenkron özellik uyumluluğu) + +#### Değiştirilen API'ler + +1. **Kurucu** (küçük bir iyileştirme): + ```python + Api(url: str, timeout: int = 60, token: Optional[str] = None) + ``` + `token` parametresi eklendi (isteğe bağlı, kimlik doğrulama için) + Eğer `None` belirtilmemişse (varsayılan): Kimlik doğrulama kullanılmıyor + Eğer belirtilmişse: REST için bearer token olarak kullanılır (`Authorization: Bearer `), WebSocket için sorgu parametresi olarak kullanılır (`?token=`) + Başka bir değişiklik yok - tamamen geriye dönük uyumlu + +2. **Kırıcı Değişiklikler Yok**: + Tüm mevcut REST API yöntemleri değişmedi + Tüm mevcut imzalar korunmuş + Tüm mevcut dönüş türleri korunmuş + +### Uygulama Detayları + +#### Hata Yönetimi + +**WebSocket Bağlantı Hataları**: +```python +try: + api = Api(url="http://localhost:8088/") + socket = api.socket() + socket_flow = socket.flow("default") + response = socket_flow.agent(question="...", user="user123") +except ConnectionError as e: + print(f"WebSocket connection failed: {e}") + print("Hint: Ensure Gateway is running and WebSocket endpoint is accessible") +``` + +**Zarif Yedekleme:** +```python +api = Api(url="http://localhost:8088/") + +try: + # Try WebSocket streaming first + socket_flow = api.socket().flow("default") + for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk.content) +except ConnectionError: + # Fall back to REST non-streaming + print("WebSocket unavailable, falling back to REST") + rest_flow = api.flow().id("default") + response = rest_flow.agent(question="...", user="...") + print(response["response"]) +``` + +**Kısmi Akış Hataları**: +```python +api = Api(url="http://localhost:8088/") +socket_flow = api.socket().flow("default") + +accumulated = [] +try: + for chunk in socket_flow.graph_rag(question="...", streaming=True): + accumulated.append(chunk.content) + if chunk.error: + print(f"Error occurred: {chunk.error}") + print(f"Partial response: {''.join(accumulated)}") + break +except Exception as e: + print(f"Streaming error: {e}") + print(f"Partial response: {''.join(accumulated)}") +``` + +#### Kaynak Yönetimi + +**Bağlam Yöneticisi Desteği**: +```python +# Automatic cleanup +with Api(url="http://localhost:8088/") as api: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +# All connections automatically closed + +# Manual cleanup +api = Api(url="http://localhost:8088/") +try: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +finally: + api.close() # Explicitly close all connections (WebSocket, bulk, etc.) +``` + +#### İş parçacığı ve Eşzamanlılık + +**İş Parçacığı Güvenliği**: +Her `Api` örneği kendi bağlantısını korur. +WebSocket taşıma katmanı, iş parçacığı güvenli istek çoklama için kilitler kullanır. +Birden fazla iş parçacığı, bir `Api` örneğini güvenli bir şekilde paylaşabilir. +Akış iteratörleri iş parçacığı güvenli değildir (tek iş parçacığından tüketilir). + +**Asenkron Destek** (gelecek planlar): +```python +# Phase 2 enhancement (not in initial scope) +import asyncio + +async def main(): + api = await AsyncApi(url="ws://localhost:8088/") + flow = api.flow().id("default") + + async for chunk in flow.agent(question="...", streaming=True): + print(chunk.content) + + await api.close() + +asyncio.run(main()) +``` + +## Güvenlik Hususları + +### Kimlik Doğrulama + +**Token Parametresi**: +```python +# No authentication (default) +api = Api(url="http://localhost:8088/") + +# With authentication +api = Api(url="http://localhost:8088/", token="mytoken") +``` + +**REST İletim Yöntemi**: +Taşıyıcı belirteci, `Authorization` başlığı aracılığıyla +Tüm REST isteklerine otomatik olarak uygulanır +Format: `Authorization: Bearer ` + +**WebSocket İletim Yöntemi**: +Belirteç, WebSocket URL'sine eklenen bir sorgu parametresi aracılığıyla +Bağlantı kurulması sırasında otomatik olarak uygulanır +Format: `ws://localhost:8088/api/v1/socket?token=` + +**Uygulama**: +```python +class SocketClient: + def _connect(self) -> WebSocket: + # Construct WebSocket URL with optional token + ws_url = f"{self.url}/api/v1/socket" + if self.token: + ws_url = f"{ws_url}?token={self.token}" + # Connect to WebSocket + return websocket.connect(ws_url) +``` + +**Örnek:** +```python +# REST with auth +api = Api(url="http://localhost:8088/", token="mytoken") +flow = api.flow().id("default") +# All REST calls include: Authorization: Bearer mytoken + +# WebSocket with auth +socket = api.socket() +# Connects to: ws://localhost:8088/api/v1/socket?token=mytoken +``` + +### Güvenli İletişim + +Hem WS (WebSocket) hem de WSS (WebSocket Secure) şemalarını destekler. +WSS bağlantıları için TLS sertifika doğrulaması. +Geliştirme için isteğe bağlı sertifika doğrulama devre dışı bırakma (uyarı ile). + +### Girdi Doğrulama + +URL şemalarını (http, https, ws, wss) doğrula. +Taşıma parametre değerlerini doğrula. +Akış parametre kombinasyonlarını doğrula. +Toplu veri türlerini doğrula. + +## Performans Hususları + +### Gecikme İyileştirmeleri + +**Akışlı LLM İşlemleri**: +**İlk token'a ulaşma süresi**: ~500ms (akışsız ise ~30 saniye) +**İyileşme**: Algılanan performansta 60 kat daha hızlı. +**Kullanım alanları**: Ajan, Grafik RAG, Belge RAG, Metin Tamamlama, İstek. + +**Sürekli Bağlantılar**: +**Bağlantı ek yükü**: Sonraki istekler için ortadan kaldırılmıştır. +**WebSocket el sıkışması**: Tek seferlik maliyet (~100ms). +**Kullanım alanları**: WebSocket taşıma yöntemini kullanırken tüm işlemler için geçerlidir. + +### Verim İyileştirmeleri + +**Toplu İşlemler**: +**Üçlü veri aktarımı**: ~10.000 üçlü/saniye (REST ile tek öğe için ~100/saniye) +**Gömme veri aktarımı**: ~5.000 gömme/saniye (REST ile tek öğe için ~50/saniye) +**İyileşme**: Toplu işlemler için 100 kat daha yüksek verim. + +**İstek Çoklama**: +**Eşzamanlı istekler**: Tek bağlantı üzerinden 15'e kadar eşzamanlı istek. +**Bağlantı yeniden kullanımı**: Eşzamanlı işlemler için bağlantı ek yükü yok. + +### Bellek Hususları + +**Akışlı Yanıtlar**: +Sabit bellek kullanımı (parçalar geldiği gibi işlenir). +Tam yanıtın tamponlanması yok. +Çok uzun çıktılar (>1MB) için uygundur. + +**Toplu İşlemler**: +Yineleyici tabanlı işleme (sabit bellek). +Tüm veri kümesinin belleğe yüklenmesi yok. +Milyonlarca öğeye sahip veri kümeleri için uygundur. + +### Karşılaştırmalar (Beklenen) + +| İşlem | REST (mevcut) | WebSocket (akışlı) | İyileşme | +|-----------|----------------|----------------------|-------------| +| Ajan (ilk token'a ulaşma süresi) | 30s | 0.5s | 60x | +| Grafik RAG (ilk token'a ulaşma süresi) | 25s | 0.5s | 50x | +| 10K üçlü aktarımı | 100s | 1s | 100x | +| 1M üçlü aktarımı | 10.000s (2.7h) | 100s (1.6m) | 100x | +| 10 eşzamanlı küçük istek | 5s (sıralı) | 0.5s (paralel) | 10x | + +## Test Stratejisi + +### Birim Testleri + +**Taşıma Katmanı** (`test_transport.py`): +REST taşıma isteklerini/yanıtlarını test et +WebSocket taşıma bağlantısını test et +WebSocket taşıma bağlantısının yeniden kurulmasını test et +İstek çoklama işlemini test et +Akış yanıtı ayrıştırmasını test et +Belirli testler için sahte WebSocket sunucusu oluştur + +**API Yöntemleri** (`test_flow.py`, `test_library.py`, vb.): +Sahte taşıma ile yeni yöntemleri test et +Akış parametrelerinin işlenmesini test et +Toplu işlem yineleyicilerini test et +Hata işleme işlemlerini test et + +**Türler** (`test_types.py`): +Yeni akış parçacık türlerini test et +Tür serileştirme/deserileştirme işlemlerini test et + +### Entegrasyon Testleri + +**Uçtan Uca REST** (`test_integration_rest.py`): +Tüm işlemleri gerçek Ağ geçidine karşı test et (REST modu) +Geriye dönük uyumluluğu doğrula +Hata koşullarını test et + +**Uçtan Uca WebSocket** (`test_integration_websocket.py`): +Tüm işlemleri gerçek Ağ geçidine karşı test et (WebSocket modu) +Akış işlemlerini test et +Toplu işlemleri test et +Eşzamanlı istekleri test et +Bağlantı kurtarma işlemlerini test et + +**Akış Hizmetleri** (`test_streaming_integration.py`): +Ajan akışını (düşünceler, gözlemler, yanıtlar) test et +RAG akışını (artımlı parçalar) test et +Metin tamamlama akışını (token-by-token) test et +İstem akışını test et +Akış sırasında hata işleme işlemlerini test et + +**Toplu İşlemler** (`test_bulk_integration.py`): +Üçlülerin toplu olarak aktarılmasını/dışa aktarılmasını test et (1K, 10K, 100K öğe) +Gömme verilerinin toplu olarak aktarılmasını/dışa aktarılmasını test et +Toplu işlemler sırasında bellek kullanımını test et +İlerleme takibini test et + +### Performans Testleri + +**Gecikme Ölçümleri** (`test_performance_latency.py`): +İlk tokene kadar geçen süreyi ölç (akışlı vs. akışsız) +Bağlantı ek yükünü ölç (REST vs WebSocket) +Beklenen ölçümlerle karşılaştır + +**Verim Ölçümleri** (`test_performance_throughput.py`): +Toplu aktarım verimini ölç +İstek çoklama verimliliğini ölç +Beklenen ölçümlerle karşılaştır + +### Uyumluluk Testleri + +**Geriye Dönük Uyumluluk** (`test_backward_compatibility.py`): +Mevcut test paketini yeniden düzenlenmiş API'ye karşı çalıştır +Herhangi bir uyumsuz değişikliğin olmadığını doğrulayın +Yaygın kalıplar için geçiş yolunu test edin + +## Geçiş Planı + +### 1. Aşama: Şeffaf Geçiş (Varsayılan) + +**Kodda herhangi bir değişiklik gerekli değil**. Mevcut kod çalışmaya devam ediyor: + +```python +# Existing code works unchanged +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") +response = flow.agent(question="What is ML?", user="user123") +``` + +### 2. Aşama: İsteğe Bağlı Yayın (Basit) + +**Yayınlamayı etkinleştirmek için `api.socket()` arayüzünü kullanın:** + +```python +# Before: Non-streaming REST +api = Api(url="http://localhost:8088/") +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# After: Streaming WebSocket (same parameters!) +api = Api(url="http://localhost:8088/") # Same URL +socket_flow = api.socket().flow("default") + +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) +``` + +**Önemli Noktalar**: +Hem REST hem de WebSocket için aynı URL +Aynı yöntem imzaları (kolay geçiş) +Sadece `.socket()` ve `streaming=True` ekleyin + +### 3. Aşama: Toplu İşlemler (Yeni Özellik) + +Büyük veri kümeleri için `api.bulk()` arayüzünü kullanın: + +```python +# Before: Inefficient per-item operations +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") + +for triple in my_large_triple_list: + # Slow per-item operations + # (no direct bulk insert in REST API) + pass + +# After: Efficient bulk loading +api = Api(url="http://localhost:8088/") # Same URL +bulk = api.bulk() + +# This is fast (10,000 triples/second) +bulk.import_triples(flow="default", triples=iter(my_large_triple_list)) +``` + +### Dokümantasyon Güncellemeleri + +1. **README.md**: Akış ve WebSocket örnekleri ekleyin +2. **API Referansı**: Tüm yeni yöntemleri ve parametreleri belgeleyin +3. **Yükseltme Kılavuzu**: Akışı etkinleştirmek için adım adım kılavuz +4. **Örnekler**: Yaygın kalıplar için örnek betikler ekleyin +5. **Performans Kılavuzu**: Beklenen performans iyileştirmelerini belgeleyin + +### Kullanımdan Kaldırma Politikası + +**Herhangi bir kullanımdan kaldırma yok**. Tüm mevcut API'ler desteklenmeye devam ediyor. Bu, yalnızca bir geliştirmedir. + +## Zaman Çizelgesi + +### 1. Hafta: Temel +Taşıma soyutlama katmanı +Mevcut REST kodunu yeniden düzenleyin +Taşıma katmanı için birim testleri +Geriye dönük uyumluluk doğrulaması + +### 2. Hafta: WebSocket Taşıyıcısı +WebSocket taşıyıcısı uygulaması +Bağlantı yönetimi ve yeniden bağlanma +İstek çoklama +Birim ve entegrasyon testleri + +### 3. Hafta: Akış Desteği +LLM yöntemlerine akış parametresi ekleyin +Akış yanıtı ayrıştırmasını uygulayın +Akış parçacığı türleri ekleyin +Akış entegrasyon testleri + +### 4. Hafta: Toplu İşlemler +Toplu içe/dışa aktarma yöntemleri ekleyin +Yineleyici tabanlı işlemleri uygulayın +Performans testi +Toplu işlem entegrasyon testleri + +### 5. Hafta: Özellik Eşdeğerliği ve Dokümantasyon +Grafik gömme sorgusu ekleyin +Ölçüm API'si ekleyin +Kapsamlı dokümantasyon +Yükseltme kılavuzu +Yayın adayı + +### 6. Hafta: Yayın +Son entegrasyon testleri +Performans karşılaştırması +Yayın dokümantasyonu +Topluluk duyurusu + +**Toplam Süre**: 6 hafta + +## Açık Sorular + +### API Tasarımı Soruları + +1. **Asenkron Destek**: ✅ **ÇÖZÜLDÜ** - Tam asenkron destek, ilk sürümde dahil edilmiştir + Tüm arayüzlerin asenkron varyantları vardır: `async_flow()`, `async_socket()`, `async_bulk()`, `async_metrics()` + Senkron ve asenkron API'ler arasında tam bir simetri sağlar + Modern asenkron çerçeveler (FastAPI, aiohttp) için gereklidir + +2. **İlerleme İzleme**: Toplu işlemler, ilerleme geri çağırmalarını desteklemeli mi? + ```python + def progress_callback(processed: int, total: Optional[int]): + print(f"Processed {processed} items") + + bulk.import_triples(flow="default", triples=triples, on_progress=progress_callback) + ``` + **Öneri**: 2. Faz'da ekleyin. İlk sürüm için kritik değil. + +3. **Akış Zaman Aşımı**: Akış işlemlerinde zaman aşımını nasıl ele almalıyız? + **Öneri**: Akış dışı işlemler için aynı zaman aşımını kullanın, ancak her parça alındığında sıfırlayın. + +4. **Parça Önbelleği**: Parçaları önbelleğe almalı mıyız yoksa hemen geri mi vermeliyiz? + **Öneri**: En düşük gecikme için hemen geri verin. + +5. **WebSocket Üzerinden Küresel Hizmetler**: `api.socket()`, küresel hizmetleri (kütüphane, bilgi, koleksiyon, yapılandırma) desteklemeli mi yoksa yalnızca akışla ilgili hizmetleri mi? + **Öneri**: Başlangıçta yalnızca akışla ilgili hizmetlerle başlayın (akışın önemli olduğu yerlerde). Gerekirse 2. Faz'da küresel hizmetleri ekleyin. + +### Uygulama Soruları + +1. **WebSocket Kütüphanesi**: `websockets`, `websocket-client` veya `aiohttp`'yi kullanmalı mıyız? + **Öneri**: `websockets` (asenkron, olgun, iyi bakılan). `asyncio.run()` kullanarak senkron bir arayüzle sarın. + +2. **Bağlantı Havuzu**: Birden çok eşzamanlı `Api` örneğinin bir bağlantı havuzunu paylaşmasına izin vermeli miyiz? + **Öneri**: 2. Faz'a bırakın. Her `Api` örneğinin başlangıçta kendi bağlantıları vardır. + +3. **Bağlantı Geri Dönüşümü**: `SocketClient` ve `BulkClient` aynı WebSocket bağlantısını mı kullanmalı, yoksa ayrı bağlantılar mı kullanmalı? + **Öneri**: Ayrı bağlantılar. Daha basit uygulama, daha net sorumluluk ayrımı. + +4. **Gecikmeli vs. Hızlı Bağlantı**: WebSocket bağlantısı `api.socket()` içinde mi yoksa ilk istekte mi kurulmalı? + **Öneri**: Gecikmeli (ilk istekte). Kullanıcı yalnızca REST yöntemlerini kullanıyorsa, bağlantı ek yükünden kaçının. + +### Test Soruları + +1. **Sahte Ağ Geçidi**: Test için hafif bir sahte Ağ Geçidi mi oluşturmalıyız, yoksa gerçek Ağ Geçidi üzerinde mi test yapmalıyız? + **Öneri**: Her ikisi de. Birim testleri için sahte nesneler kullanın, entegrasyon testleri için gerçek Ağ Geçidi'ni kullanın. + +2. **Performans Geri Dönüşüm Testleri**: Otomatik performans geri dönüşüm testlerini CI'a eklemeli miyiz? + **Öneri**: Evet, ancak CI ortamındaki değişkenliği hesaba katmak için cömert eşiklerle. + +## Referanslar + +### İlgili Teknik Özellikler +`docs/tech-specs/streaming-llm-responses.md` - Ağ Geçidi'ndeki akış uygulaması +`docs/tech-specs/rag-streaming-support.md` - RAG akış desteği + +### Uygulama Dosyaları +`trustgraph-base/trustgraph/api/` - Python API kaynağı +`trustgraph-flow/trustgraph/gateway/` - Ağ Geçidi kaynağı +`trustgraph-flow/trustgraph/gateway/dispatch/mux.py` - WebSocket çoklayıcı referans uygulaması + +### Belgeler +`docs/apiSpecification.md` - Tam API referansı +`docs/api-status-summary.md` - API durumu özeti +`README.websocket` - WebSocket protokolü belgeleri +`STREAMING-IMPLEMENTATION-NOTES.txt` - Akış uygulama notları + +### Harici Kütüphaneler +`websockets` - Python WebSocket kütüphanesi (https://websockets.readthedocs.io/) +`requests` - Python HTTP kütüphanesi (mevcut) diff --git a/docs/tech-specs/python-api-refactor.zh-cn.md b/docs/tech-specs/python-api-refactor.zh-cn.md new file mode 100644 index 00000000..4f5e2964 --- /dev/null +++ b/docs/tech-specs/python-api-refactor.zh-cn.md @@ -0,0 +1,1508 @@ +# Python API 重构技术规范 + +## 概述 + +本规范描述了 TrustGraph Python API 客户端库的全面重构,旨在实现与 API 网关的功能对齐,并添加对现代实时通信模式的支持。 + +该重构解决了四个主要用例: + +1. **流式 LLM 交互**: 启用 LLM 响应的实时流式传输(代理、图 RAG、文档 RAG、文本补全、提示),延迟降低约 60 倍(第一个 token 为 500 毫秒,而不是 30 秒)。 +2. **批量数据操作**: 支持高效的大规模知识图谱管理的 triples、图嵌入和文档嵌入的批量导入/导出。 +3. **功能对齐**: 确保每个 API 网关端点都有相应的 Python API 方法,包括图嵌入查询。 +4. **持久连接**: 启用基于 WebSocket 的通信,以实现多路复用请求和降低连接开销。 + +## 目标 + +**功能对齐**: 每个网关 API 服务都有相应的 Python API 方法。 +**流式支持**: 所有支持流式传输的服务(代理、RAG、文本补全、提示)在 Python API 中支持流式传输。 +**WebSocket 传输**: 添加可选的 WebSocket 传输层,用于持久连接和多路复用。 +**批量操作**: 添加 triples、图嵌入和文档嵌入的高效批量导入/导出功能。 +**完全异步支持**: 为所有接口(REST、WebSocket、批量操作、指标)实现完整的 async/await。 +**向后兼容性**: 现有代码无需修改即可继续工作。 +**类型安全**: 维护类型安全的接口,使用 dataclasses 和类型提示。 +**渐进式增强**: 流式传输和异步是可选的,通过显式接口选择启用。 +**性能**: 实现流式操作的 60 倍延迟改进。 +**现代 Python**: 支持同步和异步范式,以实现最大的灵活性。 + +## 背景 + +### 当前状态 + +Python API (`trustgraph-base/trustgraph/api/`) 是一个仅支持 REST 的客户端库,包含以下模块: + +`flow.py`: 流管理和流范围服务(50 个方法)。 +`library.py`: 文档库操作(9 个方法)。 +`knowledge.py`: KG 核心管理(4 个方法)。 +`collection.py`: 集合元数据(3 个方法)。 +`config.py`: 配置管理(6 个方法)。 +`types.py`: 数据类型定义(5 个 dataclasses)。 + +**总操作**: 50/59 (覆盖率 85%) + +### 当前限制 + +**缺失的操作**: +图嵌入查询(图实体上的语义搜索)。 +triples、图嵌入、文档嵌入、实体上下文、对象的批量导入/导出。 +指标端点。 + +**缺失的功能**: +LLM 服务的流式传输支持。 +WebSocket 传输。 +多路复用的并发请求。 +持久连接。 + +**性能问题**: +LLM 交互的延迟高(第一个 token 需要 30 秒)。 +批量数据传输效率低下(每个项目一个 REST 请求)。 +多个连续操作的连接开销。 + +**用户体验问题**: +LLM 生成过程中没有实时反馈。 +无法取消长时间运行的 LLM 操作。 +批量操作的可扩展性差。 + +### 影响 + +2024 年 11 月对网关 API 的流式增强,将 LLM 交互的延迟提高了 60 倍(第一个 token 为 500 毫秒,而不是 30 秒),但 Python API 用户无法利用此功能。 这在 Python 用户和非 Python 用户之间造成了显著的体验差距。 + +## 技术设计 + +### 架构 + +重构的 Python API 采用 **模块化接口方法**,具有用于不同通信模式的单独对象。 所有接口都提供 **同步和异步** 两种版本: + +1. **REST 接口** (现有,增强) + **同步**: `api.flow()`, `api.library()`, `api.knowledge()`, `api.collection()`, `api.config()` + **异步**: `api.async_flow()` + 同步/异步请求/响应。 + 简单的连接模型。 + 默认用于向后兼容。 + +2. **WebSocket 接口** (新) + **同步**: `api.socket()` + **异步**: `api.async_socket()` + 持久连接。 + 多路复用的请求。 + 流式传输支持。 + 功能重叠时,方法签名与 REST 相同。 + +3. **批量操作接口** (新) + **同步**: `api.bulk()` + **异步**: `api.async_bulk()` + 基于 WebSocket,提高效率。 + 基于 Iterator/AsyncIterator 的导入/导出。 + 处理大型数据集。 + +4. **指标接口** (新) + **同步**: `api.metrics()` + **异步**: `api.async_metrics()` + Prometheus 指标访问。 + +```python +import asyncio + +# Synchronous interfaces +api = Api(url="http://localhost:8088/") + +# REST (existing, unchanged) +flow = api.flow().id("default") +response = flow.agent(question="...", user="...") + +# WebSocket (new) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="...", user="...") +for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk) + +# Bulk operations (new) +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Asynchronous interfaces +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST (new) + flow = api.async_flow().id("default") + response = await flow.agent(question="...", user="...") + + # Async WebSocket (new) + socket_flow = api.async_socket().flow("default") + async for chunk in socket_flow.agent(question="...", streaming=True): + print(chunk) + + # Async bulk operations (new) + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + +asyncio.run(main()) +``` + +**关键设计原则**: +**所有接口使用相同的URL**: `Api(url="http://localhost:8088/")` 对所有接口都有效。 +**同步/异步对称**: 每个接口都具有同步和异步变体,方法签名相同。 +**相同的签名**: 当功能重叠时,REST 和 WebSocket 之间的同步和异步方法签名相同。 +**渐进式增强**: 根据需求选择接口(REST 用于简单操作,WebSocket 用于流式传输,Bulk 用于大型数据集,async 用于现代框架)。 +**明确意图**: `api.socket()` 表示 WebSocket,`api.async_socket()` 表示异步 WebSocket。 +**向后兼容**: 现有代码保持不变。 + +### 组件 + +#### 1. 核心 API 类 (修改版) + +模块: `trustgraph-base/trustgraph/api/api.py` + +**增强的 API 类**: + +```python +class Api: + def __init__(self, url: str, timeout: int = 60, token: Optional[str] = None): + self.url = url + self.timeout = timeout + self.token = token # Optional bearer token for REST, query param for WebSocket + self._socket_client = None + self._bulk_client = None + self._async_flow = None + self._async_socket_client = None + self._async_bulk_client = None + + # Existing synchronous methods (unchanged) + def flow(self) -> Flow: + """Synchronous REST-based flow interface""" + pass + + def library(self) -> Library: + """Synchronous REST-based library interface""" + pass + + def knowledge(self) -> Knowledge: + """Synchronous REST-based knowledge interface""" + pass + + def collection(self) -> Collection: + """Synchronous REST-based collection interface""" + pass + + def config(self) -> Config: + """Synchronous REST-based config interface""" + pass + + # New synchronous methods + def socket(self) -> SocketClient: + """Synchronous WebSocket-based interface for streaming operations""" + if self._socket_client is None: + self._socket_client = SocketClient(self.url, self.timeout, self.token) + return self._socket_client + + def bulk(self) -> BulkClient: + """Synchronous bulk operations interface for import/export""" + if self._bulk_client is None: + self._bulk_client = BulkClient(self.url, self.timeout, self.token) + return self._bulk_client + + def metrics(self) -> Metrics: + """Synchronous metrics interface""" + return Metrics(self.url, self.timeout, self.token) + + # New asynchronous methods + def async_flow(self) -> AsyncFlow: + """Asynchronous REST-based flow interface""" + if self._async_flow is None: + self._async_flow = AsyncFlow(self.url, self.timeout, self.token) + return self._async_flow + + def async_socket(self) -> AsyncSocketClient: + """Asynchronous WebSocket-based interface for streaming operations""" + if self._async_socket_client is None: + self._async_socket_client = AsyncSocketClient(self.url, self.timeout, self.token) + return self._async_socket_client + + def async_bulk(self) -> AsyncBulkClient: + """Asynchronous bulk operations interface for import/export""" + if self._async_bulk_client is None: + self._async_bulk_client = AsyncBulkClient(self.url, self.timeout, self.token) + return self._async_bulk_client + + def async_metrics(self) -> AsyncMetrics: + """Asynchronous metrics interface""" + return AsyncMetrics(self.url, self.timeout, self.token) + + # Resource management + def close(self) -> None: + """Close all synchronous connections""" + if self._socket_client: + self._socket_client.close() + if self._bulk_client: + self._bulk_client.close() + + async def aclose(self) -> None: + """Close all asynchronous connections""" + if self._async_socket_client: + await self._async_socket_client.aclose() + if self._async_bulk_client: + await self._async_bulk_client.aclose() + if self._async_flow: + await self._async_flow.aclose() + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + async def __aenter__(self): + return self + + async def __aexit__(self, *args): + await self.aclose() +``` + +#### 2. 同步 WebSocket 客户端 + +模块:`trustgraph-base/trustgraph/api/socket_client.py` (新) + +**SocketClient 类**: + +```python +class SocketClient: + """Synchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> SocketFlowInstance: + """Get flow instance for WebSocket operations""" + return SocketFlowInstance(self, flow_id) + + def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Uses asyncio.run() internally to wrap async websockets library + pass + + def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + # Synchronous wrapper around async WebSocket calls + pass + + def close(self) -> None: + """Close WebSocket connection""" + pass + +class SocketFlowInstance: + """Synchronous WebSocket flow instance with same interface as REST FlowInstance""" + def __init__(self, client: SocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance + def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], Iterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, Iterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**主要特性:** +延迟连接(仅在首次发送请求时建立连接) +请求复用(最多 15 个并发请求) +断开连接时自动重连 +流式响应解析 +线程安全操作 +异步 WebSocket 库的同步封装 + +#### 3. 异步 WebSocket 客户端 + +模块:`trustgraph-base/trustgraph/api/async_socket_client.py` (新) + +**AsyncSocketClient 类:** + +```python +class AsyncSocketClient: + """Asynchronous WebSocket client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + self._connection = None + self._request_counter = 0 + + def flow(self, flow_id: str) -> AsyncSocketFlowInstance: + """Get async flow instance for WebSocket operations""" + return AsyncSocketFlowInstance(self, flow_id) + + async def _connect(self) -> WebSocket: + """Establish WebSocket connection (lazy)""" + # Native async websockets library + pass + + async def _send_request( + self, + service: str, + flow: Optional[str], + request: Dict[str, Any], + streaming: bool = False + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Send request and handle response/streaming""" + pass + + async def aclose(self) -> None: + """Close WebSocket connection""" + pass + +class AsyncSocketFlowInstance: + """Asynchronous WebSocket flow instance""" + def __init__(self, client: AsyncSocketClient, flow_id: str): + self.client = client + self.flow_id = flow_id + + # Same method signatures as FlowInstance (but async) + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + streaming: bool = False, + **kwargs + ) -> Union[Dict[str, Any], AsyncIterator[Dict[str, Any]]]: + """Agent with optional streaming""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + streaming: bool = False, + **kwargs + ) -> Union[str, AsyncIterator[str]]: + """Text completion with optional streaming""" + pass + + # ... similar for graph_rag, document_rag, prompt, etc. +``` + +**主要特性:** +原生支持 async/await +适用于异步应用程序(FastAPI, aiohttp) +无线程阻塞 +与同步版本具有相同的接口 +AsyncIterator 用于流式传输 + +#### 4. 同步批量操作客户端 + +模块:`trustgraph-base/trustgraph/api/bulk_client.py` (新) + +**BulkClient 类:** + +```python +class BulkClient: + """Synchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + def import_triples( + self, + flow: str, + triples: Iterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + def export_triples( + self, + flow: str, + **kwargs + ) -> Iterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + def import_graph_embeddings( + self, + flow: str, + embeddings: Iterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> Iterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + def close(self) -> None: + """Close connections""" + pass +``` + +**主要特性:** +基于迭代器,内存占用恒定 +每个操作都使用专用的 WebSocket 连接 +进度跟踪(可选的回调函数) +错误处理,支持部分成功报告 + +#### 5. 异步批量操作客户端 + +模块:`trustgraph-base/trustgraph/api/async_bulk_client.py` (新) + +**AsyncBulkClient 类:** + +```python +class AsyncBulkClient: + """Asynchronous bulk operations client""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = self._convert_to_ws_url(url) + self.timeout = timeout + self.token = token + + async def import_triples( + self, + flow: str, + triples: AsyncIterator[Triple], + **kwargs + ) -> None: + """Bulk import triples via WebSocket""" + pass + + async def export_triples( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Triple]: + """Bulk export triples via WebSocket""" + pass + + async def import_graph_embeddings( + self, + flow: str, + embeddings: AsyncIterator[Dict[str, Any]], + **kwargs + ) -> None: + """Bulk import graph embeddings via WebSocket""" + pass + + async def export_graph_embeddings( + self, + flow: str, + **kwargs + ) -> AsyncIterator[Dict[str, Any]]: + """Bulk export graph embeddings via WebSocket""" + pass + + # ... similar for document embeddings, entity contexts, objects + + async def aclose(self) -> None: + """Close connections""" + pass +``` + +**主要特性:** +基于 AsyncIterator,内存占用恒定 +适用于异步应用程序,效率高 +原生支持 async/await +与同步版本具有相同的接口 + +#### 6. REST Flow API (同步 - 未改变) + +模块:`trustgraph-base/trustgraph/api/flow.py` + +REST Flow API 保持 **完全不变**,以确保向后兼容。所有现有方法均可继续使用: + +`Flow.list()`, `Flow.start()`, `Flow.stop()`, 等等。 +`FlowInstance.agent()`, `FlowInstance.text_completion()`, `FlowInstance.graph_rag()`, 等等。 +所有现有签名和返回类型均已保留 + +**新增:** 为了实现功能对等,向 REST FlowInstance 添加 `graph_embeddings_query()`: + +```python +class FlowInstance: + # All existing methods unchanged... + + # New: Graph embeddings query (REST) + def graph_embeddings_query( + self, + text: str, + user: str, + collection: str, + limit: int = 10, + **kwargs + ) -> List[Dict[str, Any]]: + """Query graph embeddings for semantic search""" + # Calls POST /api/v1/flow/{flow}/service/graph-embeddings + pass +``` + +#### 7. 异步 REST 流程 API + +模块:`trustgraph-base/trustgraph/api/async_flow.py` (新) + +**AsyncFlow 和 AsyncFlowInstance 类:** + +```python +class AsyncFlow: + """Asynchronous REST-based flow interface""" + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def list(self) -> List[Dict[str, Any]]: + """List all flows""" + pass + + async def get(self, id: str) -> Dict[str, Any]: + """Get flow definition""" + pass + + async def start(self, class_name: str, id: str, description: str, parameters: Dict) -> None: + """Start a flow""" + pass + + async def stop(self, id: str) -> None: + """Stop a flow""" + pass + + def id(self, flow_id: str) -> AsyncFlowInstance: + """Get async flow instance""" + return AsyncFlowInstance(self.url, self.timeout, self.token, flow_id) + + async def aclose(self) -> None: + """Close connection""" + pass + +class AsyncFlowInstance: + """Asynchronous REST flow instance""" + + async def agent( + self, + question: str, + user: str, + state: Optional[Dict[str, Any]] = None, + group: Optional[str] = None, + history: Optional[List[Dict[str, Any]]] = None, + **kwargs + ) -> Dict[str, Any]: + """Async agent execution""" + pass + + async def text_completion( + self, + system: str, + prompt: str, + **kwargs + ) -> str: + """Async text completion""" + pass + + async def graph_rag( + self, + question: str, + user: str, + collection: str, + **kwargs + ) -> str: + """Async graph RAG""" + pass + + # ... all other FlowInstance methods as async versions +``` + +**主要特性:** +使用 `aiohttp` 或 `httpx` 实现原生异步 HTTP。 +方法签名与同步 REST API 相同。 +不支持流式传输(使用 `async_socket()` 进行流式传输)。 +适用于异步应用程序。 + +#### 8. Metrics API + +模块:`trustgraph-base/trustgraph/api/metrics.py` (新) + +**同步 Metrics:** + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +**异步指标:** + +```python +class AsyncMetrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + async def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +#### 9. 增强的类型 + +模块:`trustgraph-base/trustgraph/api/types.py` (已修改) + +**新类型:** + +```python +from typing import Iterator, Union, Dict, Any +import dataclasses + +@dataclasses.dataclass +class StreamingChunk: + """Base class for streaming chunks""" + content: str + end_of_message: bool = False + +@dataclasses.dataclass +class AgentThought(StreamingChunk): + """Agent reasoning chunk""" + chunk_type: str = "thought" + +@dataclasses.dataclass +class AgentObservation(StreamingChunk): + """Agent tool observation chunk""" + chunk_type: str = "observation" + +@dataclasses.dataclass +class AgentAnswer(StreamingChunk): + """Agent final answer chunk""" + chunk_type: str = "final-answer" + end_of_dialog: bool = False + +@dataclasses.dataclass +class RAGChunk(StreamingChunk): + """RAG streaming chunk""" + end_of_stream: bool = False + error: Optional[Dict[str, str]] = None + +# Type aliases for clarity +AgentStream = Iterator[Union[AgentThought, AgentObservation, AgentAnswer]] +RAGStream = Iterator[RAGChunk] +CompletionStream = Iterator[str] +``` + +#### 6. 指标 API + +模块:`trustgraph-base/trustgraph/api/metrics.py` (新) + +```python +class Metrics: + def __init__(self, url: str, timeout: int, token: Optional[str]): + self.url = url + self.timeout = timeout + self.token = token + + def get(self) -> str: + """Get Prometheus metrics as text""" + # Call GET /api/metrics + pass +``` + +### 实现方案 + +#### 第一阶段:核心 API 增强 (第一周) + +1. 向 `Api` 类添加 `socket()`、`bulk()` 和 `metrics()` 方法 +2. 实现 WebSocket 和批量客户端的延迟初始化 +3. 添加上下文管理器支持 (`__enter__`, `__exit__`) +4. 添加 `close()` 方法进行清理 +5. 为 API 类增强添加单元测试 +6. 验证向后兼容性 + +**向后兼容性**: 没有破坏性更改。仅添加了新方法。 + +#### 第二阶段:WebSocket 客户端 (第二周 - 第三周) + +1. 实现 `SocketClient` 类,用于连接管理 +2. 实现 `SocketFlowInstance`,方法签名与 `FlowInstance` 相同 +3. 添加请求复用支持 (最多 15 个并发) +4. 添加流式响应解析,支持不同的分块类型 +5. 添加自动重连逻辑 +6. 添加单元和集成测试 +7. 记录 WebSocket 使用模式 + +**向后兼容性**: 仅为新接口。对现有代码没有影响。 + +#### 第三阶段:流式支持 (第三周 - 第四周) + +1. 添加流式分块类型类 (`AgentThought`, `AgentObservation`, `AgentAnswer`, `RAGChunk`) +2. 在 `SocketClient` 中实现流式响应解析 +3. 将流式参数添加到 `SocketFlowInstance` 中的所有 LLM 方法 +4. 处理流式过程中的错误情况 +5. 添加流式功能的单元和集成测试 +6. 在文档中添加流式示例 + +**向后兼容性**: 仅为新接口。现有 REST API 未改变。 + +#### 第四阶段:批量操作 (第四周 - 第五周) + +1. 实现 `BulkClient` 类 +2. 添加三元组、嵌入、上下文、对象的批量导入/导出方法 +3. 实现基于迭代器的处理,以实现恒定内存 +4. 添加进度跟踪 (可选的回调) +5. 添加错误处理,并报告部分成功 +6. 添加单元和集成测试 +7. 添加批量操作示例 + +**向后兼容性**: 仅为新接口。对现有代码没有影响。 + +#### 第五阶段:功能完善与优化 (第五周) + +1. 向 REST `FlowInstance` 添加 `graph_embeddings_query()` +2. 实现 `Metrics` 类 +3. 添加全面的集成测试 +4. 性能基准测试 +5. 更新所有文档 +6. 创建迁移指南 + +**向后兼容性**: 仅添加新方法。对现有代码没有影响。 + +### 数据模型 + +#### 接口选择 + +```python +# Single API instance, same URL for all interfaces +api = Api(url="http://localhost:8088/") + +# Synchronous interfaces +rest_flow = api.flow().id("default") # Sync REST +socket_flow = api.socket().flow("default") # Sync WebSocket +bulk = api.bulk() # Sync bulk operations +metrics = api.metrics() # Sync metrics + +# Asynchronous interfaces +async_rest_flow = api.async_flow().id("default") # Async REST +async_socket_flow = api.async_socket().flow("default") # Async WebSocket +async_bulk = api.async_bulk() # Async bulk operations +async_metrics = api.async_metrics() # Async metrics +``` + +#### 流式响应类型 + +**代理流式传输**: + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - non-streaming (same signature) +socket_flow = api.socket().flow("default") +response = socket_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# WebSocket interface - streaming (new) +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentThought): + print(f"Thinking: {chunk.content}") + elif isinstance(chunk, AgentObservation): + print(f"Observed: {chunk.content}") + elif isinstance(chunk, AgentAnswer): + print(f"Answer: {chunk.content}") + if chunk.end_of_dialog: + break +``` + +**RAG 流式传输**: + +```python +api = Api(url="http://localhost:8088/") + +# REST interface - non-streaming (existing) +rest_flow = api.flow().id("default") +response = rest_flow.graph_rag(question="What is Python?", user="user123", collection="default") +print(response) + +# WebSocket interface - streaming (new) +socket_flow = api.socket().flow("default") +for chunk in socket_flow.graph_rag( + question="What is Python?", + user="user123", + collection="default", + streaming=True +): + print(chunk.content, end="", flush=True) + if chunk.end_of_stream: + break +``` + +**批量操作 (同步)**: + +```python +api = Api(url="http://localhost:8088/") + +# Bulk import triples +def triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + +bulk = api.bulk() +bulk.import_triples(flow="default", triples=triple_generator()) + +# Bulk export triples +for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") +``` + +**批量操作(异步)**: + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async bulk import triples + async def async_triple_generator(): + yield Triple(s="http://ex.com/alice", p="http://ex.com/type", o="Person") + yield Triple(s="http://ex.com/alice", p="http://ex.com/name", o="Alice") + yield Triple(s="http://ex.com/bob", p="http://ex.com/type", o="Person") + + bulk = api.async_bulk() + await bulk.import_triples(flow="default", triples=async_triple_generator()) + + # Async bulk export triples + async for triple in bulk.export_triples(flow="default"): + print(f"{triple.s} -> {triple.p} -> {triple.o}") + +asyncio.run(main()) +``` + +**异步 REST 示例:** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async REST flow operations + flow = api.async_flow().id("default") + response = await flow.agent(question="What is ML?", user="user123") + print(response["response"]) + +asyncio.run(main()) +``` + +**异步 WebSocket 流式传输示例:** + +```python +import asyncio + +async def main(): + api = Api(url="http://localhost:8088/") + + # Async WebSocket streaming + socket = api.async_socket() + flow = socket.flow("default") + + async for chunk in flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) + if chunk.end_of_dialog: + break + +asyncio.run(main()) +``` + +### APIs + +#### New APIs + +1. **Core API Class**: + **Synchronous**: + `Api.socket()` - Get synchronous WebSocket client + `Api.bulk()` - Get synchronous bulk operations client + `Api.metrics()` - Get synchronous metrics client + `Api.close()` - Close all synchronous connections + Context manager support (`__enter__`, `__exit__`) + **Asynchronous**: + `Api.async_flow()` - Get asynchronous REST flow client + `Api.async_socket()` - Get asynchronous WebSocket client + `Api.async_bulk()` - Get asynchronous bulk operations client + `Api.async_metrics()` - Get asynchronous metrics client + `Api.aclose()` - Close all asynchronous connections + Async context manager support (`__aenter__`, `__aexit__`) + +2. **Synchronous WebSocket Client**: + `SocketClient.flow(flow_id)` - Get WebSocket flow instance + `SocketFlowInstance.agent(..., streaming: bool = False)` - Agent with optional streaming + `SocketFlowInstance.text_completion(..., streaming: bool = False)` - Text completion with optional streaming + `SocketFlowInstance.graph_rag(..., streaming: bool = False)` - Graph RAG with optional streaming + `SocketFlowInstance.document_rag(..., streaming: bool = False)` - Document RAG with optional streaming + `SocketFlowInstance.prompt(..., streaming: bool = False)` - Prompt with optional streaming + `SocketFlowInstance.graph_embeddings_query()` - Graph embeddings query + All other FlowInstance methods with identical signatures + +3. **Asynchronous WebSocket Client**: + `AsyncSocketClient.flow(flow_id)` - Get async WebSocket flow instance + `AsyncSocketFlowInstance.agent(..., streaming: bool = False)` - Async agent with optional streaming + `AsyncSocketFlowInstance.text_completion(..., streaming: bool = False)` - Async text completion with optional streaming + `AsyncSocketFlowInstance.graph_rag(..., streaming: bool = False)` - Async graph RAG with optional streaming + `AsyncSocketFlowInstance.document_rag(..., streaming: bool = False)` - Async document RAG with optional streaming + `AsyncSocketFlowInstance.prompt(..., streaming: bool = False)` - Async prompt with optional streaming + `AsyncSocketFlowInstance.graph_embeddings_query()` - Async graph embeddings query + All other FlowInstance methods as async versions + +4. **Synchronous Bulk Operations Client**: + `BulkClient.import_triples(flow, triples)` - Bulk triple import + `BulkClient.export_triples(flow)` - Bulk triple export + `BulkClient.import_graph_embeddings(flow, embeddings)` - Bulk graph embeddings import + `BulkClient.export_graph_embeddings(flow)` - Bulk graph embeddings export + `BulkClient.import_document_embeddings(flow, embeddings)` - Bulk document embeddings import + `BulkClient.export_document_embeddings(flow)` - Bulk document embeddings export + `BulkClient.import_entity_contexts(flow, contexts)` - Bulk entity contexts import + `BulkClient.export_entity_contexts(flow)` - Bulk entity contexts export + `BulkClient.import_objects(flow, objects)` - Bulk objects import + +5. **Asynchronous Bulk Operations Client**: + `AsyncBulkClient.import_triples(flow, triples)` - Async bulk triple import + `AsyncBulkClient.export_triples(flow)` - Async bulk triple export + `AsyncBulkClient.import_graph_embeddings(flow, embeddings)` - Async bulk graph embeddings import + `AsyncBulkClient.export_graph_embeddings(flow)` - Async bulk graph embeddings export + `AsyncBulkClient.import_document_embeddings(flow, embeddings)` - Async bulk document embeddings import + `AsyncBulkClient.export_document_embeddings(flow)` - Async bulk document embeddings export + `AsyncBulkClient.import_entity_contexts(flow, contexts)` - Async bulk entity contexts import + `AsyncBulkClient.export_entity_contexts(flow)` - Async bulk entity contexts export + `AsyncBulkClient.import_objects(flow, objects)` - Async bulk objects import + +6. **Asynchronous REST Flow Client**: + `AsyncFlow.list()` - Async list all flows + `AsyncFlow.get(id)` - Async get flow definition + `AsyncFlow.start(...)` - Async start flow + `AsyncFlow.stop(id)` - Async stop flow + `AsyncFlow.id(flow_id)` - Get async flow instance + `AsyncFlowInstance.agent(...)` - Async agent execution + `AsyncFlowInstance.text_completion(...)` - Async text completion + `AsyncFlowInstance.graph_rag(...)` - Async graph RAG + All other FlowInstance methods as async versions + +7. **Metrics Clients**: + `Metrics.get()` - Synchronous Prometheus metrics + `AsyncMetrics.get()` - Asynchronous Prometheus metrics + +8. **REST Flow API Enhancement**: + `FlowInstance.graph_embeddings_query()` - Graph embeddings query (sync feature parity) + `AsyncFlowInstance.graph_embeddings_query()` - Graph embeddings query (async feature parity) + +#### Modified APIs + +1. **Constructor** (minor enhancement): + ```python + Api(url: str, timeout: int = 60, token: Optional[str] = None) + ``` + 添加了 `token` 参数(可选,用于身份验证) + 如果未指定 `None`(默认):未使用身份验证 + 如果已指定:用作 REST 的 bearer token(`Authorization: Bearer `),用作 WebSocket 的查询参数(`?token=`) + 没有其他更改 - 完全向后兼容 + +2. **无破坏性更改:** + 所有现有的 REST API 方法未更改 + 所有现有的签名均保留 + 所有现有的返回类型均保留 + +### 实现细节 + +#### 错误处理 + +**WebSocket 连接错误:** +```python +try: + api = Api(url="http://localhost:8088/") + socket = api.socket() + socket_flow = socket.flow("default") + response = socket_flow.agent(question="...", user="user123") +except ConnectionError as e: + print(f"WebSocket connection failed: {e}") + print("Hint: Ensure Gateway is running and WebSocket endpoint is accessible") +``` + +**优雅的降级方案**: +```python +api = Api(url="http://localhost:8088/") + +try: + # Try WebSocket streaming first + socket_flow = api.socket().flow("default") + for chunk in socket_flow.agent(question="...", user="...", streaming=True): + print(chunk.content) +except ConnectionError: + # Fall back to REST non-streaming + print("WebSocket unavailable, falling back to REST") + rest_flow = api.flow().id("default") + response = rest_flow.agent(question="...", user="...") + print(response["response"]) +``` + +**部分流式错误:** +```python +api = Api(url="http://localhost:8088/") +socket_flow = api.socket().flow("default") + +accumulated = [] +try: + for chunk in socket_flow.graph_rag(question="...", streaming=True): + accumulated.append(chunk.content) + if chunk.error: + print(f"Error occurred: {chunk.error}") + print(f"Partial response: {''.join(accumulated)}") + break +except Exception as e: + print(f"Streaming error: {e}") + print(f"Partial response: {''.join(accumulated)}") +``` + +#### 资源管理 + +**上下文管理器支持:** +```python +# Automatic cleanup +with Api(url="http://localhost:8088/") as api: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +# All connections automatically closed + +# Manual cleanup +api = Api(url="http://localhost:8088/") +try: + socket_flow = api.socket().flow("default") + response = socket_flow.agent(question="...", user="user123") +finally: + api.close() # Explicitly close all connections (WebSocket, bulk, etc.) +``` + +#### 线程和并发 + +**线程安全**: +每个 `Api` 实例维护自己的连接。 +WebSocket 传输使用锁进行线程安全的请求复用。 +多个线程可以安全地共享一个 `Api` 实例。 +流式迭代器不具备线程安全特性(只能从单个线程消费)。 + +**异步支持**(未来考虑): +```python +# Phase 2 enhancement (not in initial scope) +import asyncio + +async def main(): + api = await AsyncApi(url="ws://localhost:8088/") + flow = api.flow().id("default") + + async for chunk in flow.agent(question="...", streaming=True): + print(chunk.content) + + await api.close() + +asyncio.run(main()) +``` + +## 安全注意事项 + +### 身份验证 + +**令牌参数**: +```python +# No authentication (default) +api = Api(url="http://localhost:8088/") + +# With authentication +api = Api(url="http://localhost:8088/", token="mytoken") +``` + +**REST 传输:** +通过 `Authorization` 头部传递认证令牌 +自动应用于所有 REST 请求 +格式:`Authorization: Bearer ` + +**WebSocket 传输:** +通过附加到 WebSocket URL 的查询参数传递认证令牌 +在连接建立期间自动应用 +格式:`ws://localhost:8088/api/v1/socket?token=` + +**实现:** +```python +class SocketClient: + def _connect(self) -> WebSocket: + # Construct WebSocket URL with optional token + ws_url = f"{self.url}/api/v1/socket" + if self.token: + ws_url = f"{ws_url}?token={self.token}" + # Connect to WebSocket + return websocket.connect(ws_url) +``` + +**示例:** +```python +# REST with auth +api = Api(url="http://localhost:8088/", token="mytoken") +flow = api.flow().id("default") +# All REST calls include: Authorization: Bearer mytoken + +# WebSocket with auth +socket = api.socket() +# Connects to: ws://localhost:8088/api/v1/socket?token=mytoken +``` + +### 安全通信 + +支持 WS (WebSocket) 和 WSS (WebSocket Secure) 两种协议。 +WSS 连接的 TLS 证书验证。 +可选的开发环境下的证书验证禁用(带有警告)。 + +### 输入验证 + +验证 URL 协议 (http, https, ws, wss)。 +验证传输参数值。 +验证流式传输参数组合。 +验证批量导入的数据类型。 + +## 性能考虑 + +### 延迟优化 + +**流式 LLM 操作**: +**首次 token 时间**: ~500 毫秒 (vs ~30 秒 非流式) +**改进**: 性能提升 60 倍 +**适用范围**: Agent, Graph RAG, Document RAG, 文本补全, Prompt + +**持久连接**: +**连接开销**: 后续请求消除连接开销 +**WebSocket 握手**: 一次性成本 (~100 毫秒) +**适用范围**: 使用 WebSocket 传输的所有操作 + +### 吞吐量优化 + +**批量操作**: +**三元组导入**: ~10,000 三元组/秒 (vs ~100/秒 使用 REST 单个项目) +**嵌入向量导入**: ~5,000 嵌入向量/秒 (vs ~50/秒 使用 REST 单个项目) +**改进**: 批量操作的吞吐量提升 100 倍 + +**请求复用**: +**并发请求**: 单个连接可支持最多 15 个并发请求 +**连接重用**: 并发操作无需连接开销 + +### 内存考虑 + +**流式响应**: +恒定内存使用 (按接收到的块处理) +不缓冲完整的响应 +适用于非常长的输出 (>1MB) + +**批量操作**: +基于迭代器的处理 (恒定内存) +不将整个数据集加载到内存中 +适用于包含数百万项的数据集 + +### 基准测试 (预期) + +| 操作 | REST (现有) | WebSocket (流式传输) | 改进 | +|-----------|----------------|----------------------|-------------| +| Agent (首次 token 时间) | 30 秒 | 0.5 秒 | 60 倍 | +| Graph RAG (首次 token 时间) | 25 秒 | 0.5 秒 | 50 倍 | +| 导入 10K 三元组 | 100 秒 | 1 秒 | 100 倍 | +| 导入 1M 三元组 | 10,000 秒 (2.7 小时) | 100 秒 (1.6 分钟) | 100 倍 | +| 10 个并发小请求 | 5 秒 (顺序) | 0.5 秒 (并行) | 10 倍 | + +## 测试策略 + +### 单元测试 + +**传输层** (`test_transport.py`): +测试 REST 传输的请求/响应 +测试 WebSocket 传输连接 +测试 WebSocket 传输重连 +测试请求复用 +测试流式响应解析 +模拟 WebSocket 服务器以进行确定性测试 + +**API 方法** (`test_flow.py`, `test_library.py`, 等): +使用模拟传输测试新方法 +测试流式参数处理 +测试批量操作迭代器 +测试错误处理 + +**类型** (`test_types.py`): +测试新的流式分块类型 +测试类型序列化/反序列化 + +### 集成测试 + +**端到端 REST** (`test_integration_rest.py`): +测试所有操作,针对真实的网关(REST 模式) +验证向后兼容性 +测试错误条件 + +**端到端 WebSocket** (`test_integration_websocket.py`): +测试所有操作,针对真实的网关(WebSocket 模式) +测试流式操作 +测试批量操作 +测试并发请求 +测试连接恢复 + +**流式服务** (`test_streaming_integration.py`): +测试代理流式传输(想法、观察、答案) +测试 RAG 流式传输(增量分块) +测试文本补全流式传输(逐个 token) +测试提示流式传输 +测试流式传输过程中的错误处理 + +**批量操作** (`test_bulk_integration.py`): +测试三元组的批量导入/导出(1K、10K、100K 个条目) +测试嵌入的批量导入/导出 +测试批量操作期间的内存使用情况 +测试进度跟踪 + +### 性能测试 + +**延迟基准测试** (`test_performance_latency.py`): +测量第一个 token 的时间(流式传输与非流式传输) +测量连接开销(REST 与 WebSocket) +与预期基准进行比较 + +**吞吐量基准测试** (`test_performance_throughput.py`): +测量批量导入吞吐量 +测量请求复用效率 +与预期基准进行比较 + +### 兼容性测试 + +**向后兼容性** (`test_backward_compatibility.py`): +运行现有测试套件,针对重构的 API +验证没有破坏性更改 +测试常见模式的迁移路径 + +## 迁移计划 + +### 第一阶段:透明迁移(默认) + +**无需任何代码更改**。 现有代码继续工作: + +```python +# Existing code works unchanged +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") +response = flow.agent(question="What is ML?", user="user123") +``` + +### 第二阶段:选择加入的流媒体(简单) + +**使用 `api.socket()` 接口** 启用流媒体: + +```python +# Before: Non-streaming REST +api = Api(url="http://localhost:8088/") +rest_flow = api.flow().id("default") +response = rest_flow.agent(question="What is ML?", user="user123") +print(response["response"]) + +# After: Streaming WebSocket (same parameters!) +api = Api(url="http://localhost:8088/") # Same URL +socket_flow = api.socket().flow("default") + +for chunk in socket_flow.agent(question="What is ML?", user="user123", streaming=True): + if isinstance(chunk, AgentAnswer): + print(chunk.content, end="", flush=True) +``` + +**关键点:** +REST 和 WebSocket 都使用相同的 URL +相同的函数签名(易于迁移) +只需要添加 `.socket()` 和 `streaming=True` + +### 第三阶段:批量操作(新功能) + +**使用 `api.bulk()` 接口** 处理大型数据集: + +```python +# Before: Inefficient per-item operations +api = Api(url="http://localhost:8088/") +flow = api.flow().id("default") + +for triple in my_large_triple_list: + # Slow per-item operations + # (no direct bulk insert in REST API) + pass + +# After: Efficient bulk loading +api = Api(url="http://localhost:8088/") # Same URL +bulk = api.bulk() + +# This is fast (10,000 triples/second) +bulk.import_triples(flow="default", triples=iter(my_large_triple_list)) +``` + +### 文档更新 + +1. **README.md**: 添加流式传输和 WebSocket 示例 +2. **API 参考**: 记录所有新的方法和参数 +3. **迁移指南**: 启用流式传输的分步指南 +4. **示例**: 添加常用模式的示例脚本 +5. **性能指南**: 记录预期的性能改进 + +### 弃用策略 + +**无弃用**. 所有现有的 API 均继续支持。 这是一个纯粹的增强。 + +## 时间线 + +### 第一周:基础 +传输抽象层 +重构现有的 REST 代码 +传输层的单元测试 +向后兼容性验证 + +### 第二周:WebSocket 传输 +WebSocket 传输实现 +连接管理和重连 +请求复用 +单元和集成测试 + +### 第三周:流式传输支持 +向 LLM 方法添加流式传输参数 +实现流式响应解析 +添加流式传输块类型 +流式传输集成测试 + +### 第四周:批量操作 +添加批量导入/导出方法 +实现基于迭代器的操作 +性能测试 +批量操作集成测试 + +### 第五周:功能对齐与文档 +添加图嵌入查询 +添加指标 API +综合文档 +迁移指南 +候选版本 + +### 第六周:发布 +最终集成测试 +性能基准测试 +发布文档 +社区公告 + +**总时长**: 6 周 + +## 开放问题 + +### API 设计问题 + +1. **异步支持**: ✅ **已解决** - 异步支持已包含在初始版本中 + 所有接口都具有异步变体:`async_flow()`, `async_socket()`, `async_bulk()`, `async_metrics()` + 为同步和异步 API 提供完全的对称性 + 对于现代异步框架(FastAPI, aiohttp)至关重要 + +2. **进度跟踪**: 批量操作是否应支持进度回调? + ```python + def progress_callback(processed: int, total: Optional[int]): + print(f"Processed {processed} items") + + bulk.import_triples(flow="default", triples=triples, on_progress=progress_callback) + ``` + **建议**: 在第二阶段添加。对于初始发布,这不是关键。 + +3. **流式传输超时**: 我们应该如何处理流式传输操作的超时? + **建议**: 使用与非流式传输相同的超时时间,但在接收每个数据块时重置。 + +4. **数据块缓冲**: 我们应该缓冲数据块,还是立即返回? + **建议**: 立即返回,以获得最低延迟。 + +5. **WebSocket 上的全局服务**: `api.socket()` 是否应该支持全局服务(库、知识、集合、配置),或者仅支持作用域服务? + **建议**: 仅从作用域服务开始(流式传输相关)。如果需要,可以在第二阶段添加全局服务。 + +### 实现问题 + +1. **WebSocket 库**: 我们应该使用 `websockets`、`websocket-client` 还是 `aiohttp`? + **建议**: `websockets` (异步,成熟,维护良好)。使用 `asyncio.run()` 包装成同步接口。 + +2. **连接池**: 我们是否应该支持多个并发的 `Api` 实例共享连接池? + **建议**: 延期到第二阶段。最初,每个 `Api` 实例都有自己的连接。 + +3. **连接重用**: `SocketClient` 和 `BulkClient` 是否应该共享同一个 WebSocket 连接,或者使用单独的连接? + **建议**: 使用单独的连接。实现更简单,职责分离更清晰。 + +4. **延迟连接 vs 立即连接**: WebSocket 连接是在 `api.socket()` 中建立,还是在首次请求时建立? + **建议**: 延迟到首次请求时建立。避免连接开销,如果用户仅使用 REST 方法。 + +### 测试问题 + +1. **模拟网关**: 我们是否应该创建一个轻量级的模拟网关进行测试,或者直接测试真实网关? + **建议**: 都应该。使用模拟进行单元测试,使用真实网关进行集成测试。 + +2. **性能回归测试**: 我们是否应该将自动化性能回归测试添加到 CI 中? + **建议**: 是的,但应设置宽松的阈值,以考虑 CI 环境的差异。 + +## 引用 + +### 相关技术规范 +`docs/tech-specs/streaming-llm-responses.md` - 网关中的流式传输实现 +`docs/tech-specs/rag-streaming-support.md` - RAG 流式传输支持 + +### 实现文件 +`trustgraph-base/trustgraph/api/` - Python API 源代码 +`trustgraph-flow/trustgraph/gateway/` - 网关源代码 +`trustgraph-flow/trustgraph/gateway/dispatch/mux.py` - WebSocket 多路复用参考实现 + +### 文档 +`docs/apiSpecification.md` - 完整的 API 参考 +`docs/api-status-summary.md` - API 状态摘要 +`README.websocket` - WebSocket 协议文档 +`STREAMING-IMPLEMENTATION-NOTES.txt` - 流式传输实现说明 + +### 外部库 +`websockets` - Python WebSocket 库 (https://websockets.readthedocs.io/) +`requests` - Python HTTP 库 (现有) diff --git a/docs/tech-specs/query-time-explainability.ar.md b/docs/tech-specs/query-time-explainability.ar.md new file mode 100644 index 00000000..6513ee90 --- /dev/null +++ b/docs/tech-specs/query-time-explainability.ar.md @@ -0,0 +1,263 @@ +# الشرح في وقت الاستعلام + +## الحالة + +تم التنفيذ + +## نظرة عامة + +يصف هذا المواصفات كيفية تسجيل GraphRAG وتوصيل بيانات الشرح أثناء تنفيذ الاستعلام. الهدف هو التتبع الكامل: من الإجابة النهائية إلى الحواف المحددة ثم إلى المستندات المصدر. + +يمثل الشرح في وقت الاستعلام ما قام به مسار عمل GraphRAG أثناء عملية الاستدلال. وهو مرتبط ببيانات المصدر التي تم تسجيلها في وقت الاستخراج، والتي تسجل أصل حقائق الرسم البياني المعرفي. + +## المصطلحات + +| المصطلح | التعريف | +|------|------------| +| **الشرح** | سجل لكيفية اشتقاق نتيجة | +| **الجلسة** | تنفيذ استعلام GraphRAG واحد | +| **اختيار الحواف** | اختيار الحواف ذات الصلة المدفوع بالنماذج اللغوية الكبيرة مع الاستدلال | +| **سلسلة المصدر** | مسار من الحافة → الجزء → الصفحة → المستند | + +## البنية + +### تدفق الشرح + +``` +GraphRAG Query + │ + ├─► Session Activity + │ └─► Query text, timestamp + │ + ├─► Retrieval Entity + │ └─► All edges retrieved from subgraph + │ + ├─► Selection Entity + │ └─► Selected edges with LLM reasoning + │ └─► Each edge links to extraction provenance + │ + └─► Answer Entity + └─► Reference to synthesized response (in librarian) +``` + +### خط أنابيب GraphRAG ثنائي المراحل + +1. **اختيار الحواف**: يقوم نموذج اللغة الكبيرة (LLM) باختيار الحواف ذات الصلة من الرسم البياني الفرعي، مع تقديم مبررات لكل حافة. +2. **التوليف**: يقوم نموذج اللغة الكبيرة (LLM) بإنشاء الإجابة من الحواف المحددة فقط. + +هذا الفصل يمكّن من إمكانية التفسير - نحن نعرف بالضبط أي الحواف ساهمت. + +### التخزين + +يتم تخزين ثلاثيات إمكانية التفسير في مجموعة قابلة للتكوين (افتراضي: `explainability`). +يستخدم علم الوجود PROV-O للعلاقات المتعلقة بالأصل. +إعادة تمثيل RDF-star للمراجع إلى الحواف. +يتم تخزين محتوى الإجابة في خدمة "المكتبار" (وليس مضمنًا - كبير جدًا). + +### البث في الوقت الفعلي + +يتم بث أحداث إمكانية التفسير إلى العميل أثناء تنفيذ الاستعلام: + +1. تم إنشاء جلسة → تم إرسال حدث. +2. تم استرداد الحواف → تم إرسال حدث. +3. تم تحديد الحواف مع التبرير → تم إرسال حدث. +4. تم توليف الإجابة → تم إرسال حدث. + +يتلقى العميل `explain_id` و `explain_collection` لاسترداد التفاصيل الكاملة. + +## هيكل URI + +تستخدم جميع عناوين URI مساحة الاسم `urn:trustgraph:` مع معرفات UUID: + +| الكيان | نمط URI | +|--------|-------------| +| الجلسة | `urn:trustgraph:session:{uuid}` | +| الاسترداد | `urn:trustgraph:prov:retrieval:{uuid}` | +| التحديد | `urn:trustgraph:prov:selection:{uuid}` | +| الإجابة | `urn:trustgraph:prov:answer:{uuid}` | +| تحديد الحواف | `urn:trustgraph:prov:edge:{uuid}:{index}` | + +## نموذج RDF (PROV-O) + +### نشاط الجلسة + +```turtle + a prov:Activity ; + rdfs:label "GraphRAG query session" ; + prov:startedAtTime "2024-01-15T10:30:00Z" ; + tg:query "What was the War on Terror?" . +``` + +### الكيان الخاص بالاسترجاع + +```turtle + a prov:Entity ; + rdfs:label "Retrieved edges" ; + prov:wasGeneratedBy ; + tg:edgeCount 50 . +``` + +### الكيان المحدد + +```turtle + a prov:Entity ; + rdfs:label "Selected edges" ; + prov:wasDerivedFrom ; + tg:selectedEdge ; + tg:selectedEdge . + + tg:edge <<

>> ; + tg:reasoning "This edge establishes the key relationship..." . +``` + +### إجابة الكيان + +```turtle + a prov:Entity ; + rdfs:label "GraphRAG answer" ; + prov:wasDerivedFrom ; + tg:document . +``` + +يشير الرمز `tg:document` إلى الإجابة المخزنة في خدمة أمين المكتبة. + +## ثوابت مساحة الاسم + +معرفة في `trustgraph-base/trustgraph/provenance/namespaces.py`: + +| الثابت | عنوان URI | +|----------|-----| +| `TG_QUERY` | `https://trustgraph.ai/ns/query` | +| `TG_EDGE_COUNT` | `https://trustgraph.ai/ns/edgeCount` | +| `TG_SELECTED_EDGE` | `https://trustgraph.ai/ns/selectedEdge` | +| `TG_EDGE` | `https://trustgraph.ai/ns/edge` | +| `TG_REASONING` | `https://trustgraph.ai/ns/reasoning` | +| `TG_CONTENT` | `https://trustgraph.ai/ns/content` | +| `TG_DOCUMENT` | `https://trustgraph.ai/ns/document` | + +## مخطط GraphRagResponse + +```python +@dataclass +class GraphRagResponse: + error: Error | None = None + response: str = "" + end_of_stream: bool = False + explain_id: str | None = None + explain_collection: str | None = None + message_type: str = "" # "chunk" or "explain" + end_of_session: bool = False +``` + +### أنواع الرسائل + +| نوع الرسالة | الغرض | +|--------------|---------| +| `chunk` | نص الاستجابة (متدفق أو نهائي) | +| `explain` | حدث قابل للتفسير مع مرجع IRI | + +### دورة حياة الجلسة + +1. رسائل `explain` متعددة (جلسة، استرجاع، اختيار، إجابة) +2. رسائل `chunk` متعددة (استجابة متدفقة) +3. رسالة `chunk` نهائية مع `end_of_session=True` + +## تنسيق اختيار الحافة + +يقوم نموذج اللغة الكبيرة بإرجاع JSONL مع الحواف المحددة: + +```jsonl +{"id": "edge-hash-1", "reasoning": "This edge shows the key relationship..."} +{"id": "edge-hash-2", "reasoning": "Provides supporting evidence..."} +``` + +الرمز `id` هو تجزئة لـ `(labeled_s, labeled_p, labeled_o)` تم حسابه بواسطة `edge_id()`. + +## الحفاظ على عنوان URI + +### المشكلة + +يعرض GraphRAG تسميات قابلة للقراءة للبشر لنظام LLM، ولكن الشفافية تتطلب عناوين URI أصلية لتتبع الأصل. + +### الحل + +`get_labelgraph()` يُرجع كلاً من: +`labeled_edges`: قائمة بـ `(label_s, label_p, label_o)` لنظام LLM +`uri_map`: قاموس يربط بين `edge_id(labels)` و `(uri_s, uri_p, uri_o)` + +عند تخزين بيانات الشفافية، تُستخدم عناوين URI من `uri_map`. + +## تتبع الأصل + +### من الحافة إلى المصدر + +يمكن تتبع الحواف المحددة إلى المستندات المصدر: + +1. الاستعلام عن الرسم البياني الفرعي الذي يحتوي عليها: `?subgraph tg:contains <>` +2. تتبع سلسلة `prov:wasDerivedFrom` إلى المستند الجذر +3. كل خطوة في السلسلة: جزء → صفحة → مستند + +### دعم ثلاثيات Cassandra المقتبسة + +يدعم خدمة استعلام Cassandra مطابقة ثلاثيات مقتبسة: + +```python +# In get_term_value(): +elif term.type == TRIPLE: + return serialize_triple(term.triple) +``` + +هذا يتيح إجراء استعلامات مثل: +``` +?subgraph tg:contains <> +``` + +## استخدام واجهة سطر الأوامر + +```bash +tg-invoke-graph-rag --explainable -q "What was the War on Terror?" +``` + +### تنسيق الإخراج + +``` +[session] urn:trustgraph:session:abc123 + +[retrieval] urn:trustgraph:prov:retrieval:abc123 + +[selection] urn:trustgraph:prov:selection:abc123 + Selected 12 edge(s) + Edge: (Guantanamo, definition, A detention facility...) + Reason: Directly connects Guantanamo to the War on Terror + Source: Chunk 1 → Page 2 → Beyond the Vigilant State + +[answer] urn:trustgraph:prov:answer:abc123 + +Based on the provided knowledge statements... +``` + +### الميزات + +أحداث تفسيرية في الوقت الفعلي أثناء الاستعلام. +حل التسميات للمكونات الطرفية عبر `rdfs:label`. +تتبع سلسلة المصدر عبر `prov:wasDerivedFrom`. +تخزين مؤقت للتسميات لتجنب الاستعلامات المتكررة. + +## الملفات المنفذة + +| الملف | الغرض | +|------|---------| +| `trustgraph-base/trustgraph/provenance/uris.py` | مولدات URI | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | ثوابت مساحة الاسم RDF | +| `trustgraph-base/trustgraph/provenance/triples.py` | أدوات بناء الثلاثيات | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | مخطط GraphRagResponse | +| `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` | GraphRAG الأساسي مع الحفاظ على URI | +| `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` | خدمة مع تكامل أمين المكتبة | +| `trustgraph-flow/trustgraph/query/triples/cassandra/service.py` | دعم الاستعلام عن الثلاثيات المقتبسة | +| `trustgraph-cli/trustgraph/cli/invoke_graph_rag.py` | واجهة سطر أوامر مع عرض التفسير | + +## المراجع + +PROV-O (علم الوجود W3C): https://www.w3.org/TR/prov-o/ +RDF-star: https://w3c.github.io/rdf-star/ +علم الوجود في وقت الاستخراج: `docs/tech-specs/extraction-time-provenance.md` diff --git a/docs/tech-specs/query-time-explainability.hi.md b/docs/tech-specs/query-time-explainability.hi.md new file mode 100644 index 00000000..19719adf --- /dev/null +++ b/docs/tech-specs/query-time-explainability.hi.md @@ -0,0 +1,263 @@ +# क्वेरी-टाइम एक्सप्लेनेबिलिटी (Query-Time Explainability) + +## स्थिति (Status) + +कार्यान्वित (Implemented) + +## अवलोकन (Overview) + +यह विनिर्देश बताता है कि GraphRAG क्वेरी निष्पादन के दौरान एक्सप्लेनेबिलिटी डेटा को कैसे रिकॉर्ड और संचारित करता है। इसका लक्ष्य पूर्ण पता लगाने की क्षमता है: अंतिम उत्तर से लेकर चयनित किनारों तक और फिर स्रोत दस्तावेजों तक। + +क्वेरी-टाइम एक्सप्लेनेबिलिटी यह कैप्चर करती है कि GraphRAG पाइपलाइन तर्क के दौरान क्या करती है। यह निष्कर्षण-समय के प्रमाण से जुड़ा है, जो रिकॉर्ड करता है कि ज्ञान ग्राफ तथ्यों की उत्पत्ति कहाँ से हुई। + +## शब्दावली (Terminology) + +| शब्द | परिभाषा | +|------|------------| +| **एक्सप्लेनेबिलिटी (Explainability)** | यह रिकॉर्ड है कि एक परिणाम कैसे प्राप्त किया गया | +| **सेशन (Session)** | एक एकल GraphRAG क्वेरी निष्पादन | +| **एज सिलेक्शन (Edge Selection)** | तर्क के साथ प्रासंगिक किनारों का LLM-संचालित चयन | +| **प्रूवेनेंस चेन (Provenance Chain)** | किनारे → चंक → पृष्ठ → दस्तावेज़ से पथ | + +## आर्किटेक्चर (Architecture) + +### एक्सप्लेनेबिलिटी फ्लो (Explainability Flow) + +``` +GraphRAG Query + │ + ├─► Session Activity + │ └─► Query text, timestamp + │ + ├─► Retrieval Entity + │ └─► All edges retrieved from subgraph + │ + ├─► Selection Entity + │ └─► Selected edges with LLM reasoning + │ └─► Each edge links to extraction provenance + │ + └─► Answer Entity + └─► Reference to synthesized response (in librarian) +``` + +### दो-चरणीय ग्राफआरएजी पाइपलाइन + +1. **एज चयन**: एलएलएम सबग्राफ से प्रासंगिक किनारों का चयन करता है, प्रत्येक के लिए तर्क प्रदान करता है। +2. **संश्लेषण**: एलएलएम केवल चयनित किनारों से उत्तर उत्पन्न करता है। + +यह अलगाव व्याख्यात्मकता को सक्षम बनाता है - हमें ठीक से पता है कि किन किनारों ने योगदान दिया। + +### भंडारण + +व्याख्यात्मकता ट्रिपल कॉन्फ़िगर करने योग्य संग्रह में संग्रहीत हैं (डिफ़ॉल्ट: `explainability`)। +यह स्रोत संबंधों के लिए प्रोवी-ओ ऑन्टोलॉजी का उपयोग करता है। +किनारे संदर्भों के लिए आरडीएफ-स्टार रीफिकेशन। +उत्तर सामग्री लाइब्रेरियन सेवा में संग्रहीत है (इनलाइन नहीं - बहुत बड़ा)। + +### वास्तविक समय स्ट्रीमिंग + +व्याख्यात्मकता घटनाएँ क्लाइंट को क्वेरी निष्पादित होने के दौरान स्ट्रीम की जाती हैं: + +1. सत्र बनाया गया → घटना उत्सर्जित। +2. किनारे पुनर्प्राप्त किए गए → घटना उत्सर्जित। +3. तर्क के साथ किनारे चुने गए → घटना उत्सर्जित। +4. उत्तर संश्लेषित → घटना उत्सर्जित। + +क्लाइंट को `explain_id` और `explain_collection` प्राप्त होते हैं ताकि पूर्ण विवरण प्राप्त किए जा सकें। + +## यूआरआई संरचना + +सभी यूआरआई `urn:trustgraph:` नेमस्पेस का उपयोग करते हैं जिसमें यूयूआईडी शामिल हैं: + +| इकाई | यूआरआई पैटर्न | +|--------|-------------| +| सत्र | `urn:trustgraph:session:{uuid}` | +| पुनर्प्राप्ति | `urn:trustgraph:prov:retrieval:{uuid}` | +| चयन | `urn:trustgraph:prov:selection:{uuid}` | +| उत्तर | `urn:trustgraph:prov:answer:{uuid}` | +| किनारे का चयन | `urn:trustgraph:prov:edge:{uuid}:{index}` | + +## आरडीएफ मॉडल (प्रोवी-ओ) + +### सत्र गतिविधि + +```turtle + a prov:Activity ; + rdfs:label "GraphRAG query session" ; + prov:startedAtTime "2024-01-15T10:30:00Z" ; + tg:query "What was the War on Terror?" . +``` + +### पुनर्प्राप्ति इकाई + +```turtle + a prov:Entity ; + rdfs:label "Retrieved edges" ; + prov:wasGeneratedBy ; + tg:edgeCount 50 . +``` + +### चयन इकाई + +```turtle + a prov:Entity ; + rdfs:label "Selected edges" ; + prov:wasDerivedFrom ; + tg:selectedEdge ; + tg:selectedEdge . + + tg:edge <<

>> ; + tg:reasoning "This edge establishes the key relationship..." . +``` + +### उत्तर इकाई + +```turtle + a prov:Entity ; + rdfs:label "GraphRAG answer" ; + prov:wasDerivedFrom ; + tg:document . +``` + +`tg:document` संदर्भ लाइब्रेरियन सेवा में संग्रहीत उत्तर को दर्शाता है। + +## नेमस्पेस स्थिरांक + +`trustgraph-base/trustgraph/provenance/namespaces.py` में परिभाषित: + +| स्थिरांक | यूआरआई | +|----------|-----| +| `TG_QUERY` | `https://trustgraph.ai/ns/query` | +| `TG_EDGE_COUNT` | `https://trustgraph.ai/ns/edgeCount` | +| `TG_SELECTED_EDGE` | `https://trustgraph.ai/ns/selectedEdge` | +| `TG_EDGE` | `https://trustgraph.ai/ns/edge` | +| `TG_REASONING` | `https://trustgraph.ai/ns/reasoning` | +| `TG_CONTENT` | `https://trustgraph.ai/ns/content` | +| `TG_DOCUMENT` | `https://trustgraph.ai/ns/document` | + +## GraphRagResponse स्कीमा + +```python +@dataclass +class GraphRagResponse: + error: Error | None = None + response: str = "" + end_of_stream: bool = False + explain_id: str | None = None + explain_collection: str | None = None + message_type: str = "" # "chunk" or "explain" + end_of_session: bool = False +``` + +### संदेश प्रकार + +| संदेश_प्रकार | उद्देश्य | +|--------------|---------| +| `chunk` | प्रतिक्रिया पाठ (स्ट्रीमिंग या अंतिम) | +| `explain` | आईआरआई संदर्भ के साथ व्याख्यात्मक घटना | + +### सत्र जीवनचक्र + +1. कई `explain` संदेश (सत्र, पुनर्प्राप्ति, चयन, उत्तर) +2. कई `chunk` संदेश (स्ट्रीमिंग प्रतिक्रिया) +3. `end_of_session=True` के साथ अंतिम `chunk` + +## एज चयन प्रारूप + +एलएलएम चयनित किनारों के साथ JSONL लौटाता है: + +```jsonl +{"id": "edge-hash-1", "reasoning": "This edge shows the key relationship..."} +{"id": "edge-hash-2", "reasoning": "Provides supporting evidence..."} +``` + +`id`, `(labeled_s, labeled_p, labeled_o)` का एक हैश है, जिसकी गणना `edge_id()` द्वारा की जाती है। + +## यूआरआई का संरक्षण + +### समस्या + +GraphRAG, एलएलएम को समझने योग्य लेबल प्रदर्शित करता है, लेकिन स्पष्टीकरण के लिए मूल यूआरआई की आवश्यकता होती है ताकि स्रोत का पता लगाया जा सके। + +### समाधान + +`get_labelgraph()` दोनों लौटाता है: +`labeled_edges`: एलएलएम के लिए `(label_s, label_p, label_o)` की सूची +`uri_map`: एक डिक्शनरी जो `edge_id(labels)` को `(uri_s, uri_p, uri_o)` से जोड़ती है। + +जब व्याख्यात्मक डेटा संग्रहीत किया जाता है, तो `uri_map` से यूआरआई का उपयोग किया जाता है। + +## उत्पत्ति अनुरेखण + +### किनारे से स्रोत तक + +चयनित किनारों को मूल दस्तावेजों तक वापस ट्रेस किया जा सकता है: + +1. समाहित उपग्राफ के लिए क्वेरी करें: `?subgraph tg:contains <>` +2. मूल दस्तावेज़ तक `prov:wasDerivedFrom` श्रृंखला का पालन करें +3. श्रृंखला में प्रत्येक चरण: खंड → पृष्ठ → दस्तावेज़ + +### कैसेंड्रा उद्धृत त्रिक समर्थन + +कैसेंड्रा क्वेरी सेवा उद्धृत त्रिकों के मिलान का समर्थन करती है: + +```python +# In get_term_value(): +elif term.type == TRIPLE: + return serialize_triple(term.triple) +``` + +यह इस तरह के प्रश्नों को सक्षम करता है: +``` +?subgraph tg:contains <> +``` + +## कमांड लाइन इंटरफेस (CLI) का उपयोग + +```bash +tg-invoke-graph-rag --explainable -q "What was the War on Terror?" +``` + +### आउटपुट प्रारूप + +``` +[session] urn:trustgraph:session:abc123 + +[retrieval] urn:trustgraph:prov:retrieval:abc123 + +[selection] urn:trustgraph:prov:selection:abc123 + Selected 12 edge(s) + Edge: (Guantanamo, definition, A detention facility...) + Reason: Directly connects Guantanamo to the War on Terror + Source: Chunk 1 → Page 2 → Beyond the Vigilant State + +[answer] urn:trustgraph:prov:answer:abc123 + +Based on the provided knowledge statements... +``` + +### विशेषताएं + +क्वेरी के दौरान वास्तविक समय में व्याख्यात्मक घटनाएं। +`rdfs:label` के माध्यम से एज घटकों के लिए लेबल समाधान। +`prov:wasDerivedFrom` के माध्यम से स्रोत श्रृंखला का पता लगाना। +बार-बार क्वेरी से बचने के लिए लेबल कैशिंग। + +## कार्यान्वित फाइलें + +| फ़ाइल | उद्देश्य | +|------|---------| +| `trustgraph-base/trustgraph/provenance/uris.py` | यूआरआई जनरेटर | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | आरडीएफ नेमस्पेस स्थिरांक | +| `trustgraph-base/trustgraph/provenance/triples.py` | ट्रिपल बिल्डर | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | GraphRagResponse स्कीमा | +| `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` | यूआरआई संरक्षण के साथ मुख्य GraphRAG | +| `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` | लाइब्रेरियन एकीकरण के साथ सेवा | +| `trustgraph-flow/trustgraph/query/triples/cassandra/service.py` | उद्धृत ट्रिपल क्वेरी समर्थन | +| `trustgraph-cli/trustgraph/cli/invoke_graph_rag.py` | व्याख्यात्मक प्रदर्शन के साथ सीएलआई | + +## संदर्भ + +PROV-O (डब्ल्यू3सी प्रोवेनेंस ऑन्टोलॉजी): https://www.w3.org/TR/prov-o/ +RDF-star: https://w3c.github.io/rdf-star/ +निष्कर्षण-समय प्रोवेनेंस: `docs/tech-specs/extraction-time-provenance.md` diff --git a/docs/tech-specs/query-time-explainability.pt.md b/docs/tech-specs/query-time-explainability.pt.md new file mode 100644 index 00000000..e2349e64 --- /dev/null +++ b/docs/tech-specs/query-time-explainability.pt.md @@ -0,0 +1,263 @@ +# Explicabilidade em Tempo de Consulta + +## Status + +Implementado + +## Visão Geral + +Esta especificação descreve como o GraphRAG registra e comunica dados de explicabilidade durante a execução da consulta. O objetivo é a rastreabilidade completa: desde a resposta final, passando pelas arestas selecionadas, até aos documentos de origem. + +A explicabilidade em tempo de consulta captura o que o pipeline do GraphRAG fez durante o raciocínio. Isso se conecta à rastreabilidade em tempo de extração, que registra a origem dos fatos do grafo de conhecimento. + +## Terminologia + +| Termo | Definição | +|------|------------| +| **Explicabilidade** | O registro de como um resultado foi derivado | +| **Sessão** | Uma única execução de consulta do GraphRAG | +| **Seleção de Arestas** | Seleção de arestas relevantes impulsionada por LLM, com raciocínio | +| **Cadeia de Rastreabilidade** | Caminho de aresta → trecho → página → documento | + +## Arquitetura + +### Fluxo de Explicabilidade + +``` +GraphRAG Query + │ + ├─► Session Activity + │ └─► Query text, timestamp + │ + ├─► Retrieval Entity + │ └─► All edges retrieved from subgraph + │ + ├─► Selection Entity + │ └─► Selected edges with LLM reasoning + │ └─► Each edge links to extraction provenance + │ + └─► Answer Entity + └─► Reference to synthesized response (in librarian) +``` + +### Pipeline de GraphRAG em Duas Etapas + +1. **Seleção de Arestas**: O LLM seleciona as arestas relevantes do subgrafo, fornecendo a justificativa para cada uma. +2. **Síntese**: O LLM gera a resposta a partir das arestas selecionadas. + +Essa separação permite a explicabilidade - sabemos exatamente quais arestas contribuíram. + +### Armazenamento + +Triplas de explicabilidade armazenadas em uma coleção configurável (padrão: `explainability`). +Utiliza a ontologia PROV-O para relações de procedência. +Reificação RDF-star para referências de arestas. +O conteúdo da resposta é armazenado no serviço de bibliotecário (não inline - muito grande). + +### Streaming em Tempo Real + +Os eventos de explicabilidade são transmitidos ao cliente enquanto a consulta é executada: + +1. Sessão criada → evento emitido. +2. Arestas recuperadas → evento emitido. +3. Arestas selecionadas com justificativa → evento emitido. +4. Resposta sintetizada → evento emitido. + +O cliente recebe `explain_id` e `explain_collection` para buscar detalhes completos. + +## Estrutura de URI + +Todos os URIs usam o namespace `urn:trustgraph:` com UUIDs: + +| Entidade | Padrão de URI | +|--------|-------------| +| Sessão | `urn:trustgraph:session:{uuid}` | +| Recuperação | `urn:trustgraph:prov:retrieval:{uuid}` | +| Seleção | `urn:trustgraph:prov:selection:{uuid}` | +| Resposta | `urn:trustgraph:prov:answer:{uuid}` | +| Seleção de Aresta | `urn:trustgraph:prov:edge:{uuid}:{index}` | + +## Modelo RDF (PROV-O) + +### Atividade da Sessão + +```turtle + a prov:Activity ; + rdfs:label "GraphRAG query session" ; + prov:startedAtTime "2024-01-15T10:30:00Z" ; + tg:query "What was the War on Terror?" . +``` + +### Entidade de Recuperação + +```turtle + a prov:Entity ; + rdfs:label "Retrieved edges" ; + prov:wasGeneratedBy ; + tg:edgeCount 50 . +``` + +### Entidade de Seleção + +```turtle + a prov:Entity ; + rdfs:label "Selected edges" ; + prov:wasDerivedFrom ; + tg:selectedEdge ; + tg:selectedEdge . + + tg:edge <<

>> ; + tg:reasoning "This edge establishes the key relationship..." . +``` + +### Entidade de Resposta + +```turtle + a prov:Entity ; + rdfs:label "GraphRAG answer" ; + prov:wasDerivedFrom ; + tg:document . +``` + +A `tg:document` referencia a resposta armazenada no serviço de bibliotecário. + +## Constantes do Namespace + +Definido em `trustgraph-base/trustgraph/provenance/namespaces.py`: + +| Constante | URI | +|----------|-----| +| `TG_QUERY` | `https://trustgraph.ai/ns/query` | +| `TG_EDGE_COUNT` | `https://trustgraph.ai/ns/edgeCount` | +| `TG_SELECTED_EDGE` | `https://trustgraph.ai/ns/selectedEdge` | +| `TG_EDGE` | `https://trustgraph.ai/ns/edge` | +| `TG_REASONING` | `https://trustgraph.ai/ns/reasoning` | +| `TG_CONTENT` | `https://trustgraph.ai/ns/content` | +| `TG_DOCUMENT` | `https://trustgraph.ai/ns/document` | + +## Esquema GraphRagResponse + +```python +@dataclass +class GraphRagResponse: + error: Error | None = None + response: str = "" + end_of_stream: bool = False + explain_id: str | None = None + explain_collection: str | None = None + message_type: str = "" # "chunk" or "explain" + end_of_session: bool = False +``` + +### Tipos de Mensagem + +| message_type | Propósito | +|--------------|---------| +| `chunk` | Texto de resposta (em fluxo ou final) | +| `explain` | Evento de explicabilidade com referência IRI | + +### Ciclo de Vida da Sessão + +1. Múltiplas mensagens `explain` (sessão, recuperação, seleção, resposta) +2. Múltiplas mensagens `chunk` (resposta em fluxo) +3. Mensagem `chunk` final com `end_of_session=True` + +## Formato de Seleção de Arestas + +O LLM retorna JSONL com as arestas selecionadas: + +```jsonl +{"id": "edge-hash-1", "reasoning": "This edge shows the key relationship..."} +{"id": "edge-hash-2", "reasoning": "Provides supporting evidence..."} +``` + +O `id` é um hash de `(labeled_s, labeled_p, labeled_o)` calculado por `edge_id()`. + +## Preservação de URIs + +### O Problema + +O GraphRAG exibe rótulos legíveis para humanos para o LLM, mas a explicabilidade precisa de URIs originais para rastreamento de origem. + +### Solução + +`get_labelgraph()` retorna ambos: +`labeled_edges`: Lista de `(label_s, label_p, label_o)` para o LLM +`uri_map`: Dicionário mapeando `edge_id(labels)` → `(uri_s, uri_p, uri_o)` + +Ao armazenar dados de explicabilidade, os URIs de `uri_map` são usados. + +## Rastreamento de Origem + +### Do Borda à Fonte + +As arestas selecionadas podem ser rastreadas de volta aos documentos de origem: + +1. Consulta para o subgrafo contendo: `?subgraph tg:contains <>` +2. Siga a cadeia `prov:wasDerivedFrom` até o documento raiz +3. Cada etapa na cadeia: chunk → página → documento + +### Suporte de Triplas Citadas do Cassandra + +O serviço de consulta do Cassandra suporta a correspondência de triplas citadas: + +```python +# In get_term_value(): +elif term.type == TRIPLE: + return serialize_triple(term.triple) +``` + +Isso permite consultas como: +``` +?subgraph tg:contains <> +``` + +## Uso da Interface de Linha de Comando (CLI) + +```bash +tg-invoke-graph-rag --explainable -q "What was the War on Terror?" +``` + +### Formato de Saída + +``` +[session] urn:trustgraph:session:abc123 + +[retrieval] urn:trustgraph:prov:retrieval:abc123 + +[selection] urn:trustgraph:prov:selection:abc123 + Selected 12 edge(s) + Edge: (Guantanamo, definition, A detention facility...) + Reason: Directly connects Guantanamo to the War on Terror + Source: Chunk 1 → Page 2 → Beyond the Vigilant State + +[answer] urn:trustgraph:prov:answer:abc123 + +Based on the provided knowledge statements... +``` + +### Recursos + +Eventos de explicabilidade em tempo real durante a consulta. +Resolução de rótulos para componentes de borda via `rdfs:label`. +Rastreamento da cadeia de origem via `prov:wasDerivedFrom`. +Cache de rótulos para evitar consultas repetidas. + +## Arquivos Implementados + +| Arquivo | Propósito | +|------|---------| +| `trustgraph-base/trustgraph/provenance/uris.py` | Geradores de URI | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | Constantes de namespace RDF | +| `trustgraph-base/trustgraph/provenance/triples.py` | Construtores de triplas | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | Esquema GraphRagResponse | +| `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` | Núcleo GraphRAG com preservação de URI | +| `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` | Serviço com integração de bibliotecário | +| `trustgraph-flow/trustgraph/query/triples/cassandra/service.py` | Suporte para consultas de triplas entre aspas | +| `trustgraph-cli/trustgraph/cli/invoke_graph_rag.py` | CLI com exibição de explicabilidade | + +## Referências + +PROV-O (Ontologia de Proveniência W3C): https://www.w3.org/TR/prov-o/ +RDF-star: https://w3c.github.io/rdf-star/ +Proveniência no momento da extração: `docs/tech-specs/extraction-time-provenance.md` diff --git a/docs/tech-specs/query-time-explainability.ru.md b/docs/tech-specs/query-time-explainability.ru.md new file mode 100644 index 00000000..1548db30 --- /dev/null +++ b/docs/tech-specs/query-time-explainability.ru.md @@ -0,0 +1,263 @@ +# Объяснимость во время выполнения запроса + +## Статус + +Реализовано + +## Обзор + +Эта спецификация описывает, как GraphRAG записывает и передает данные об объяснимости во время выполнения запроса. Цель - полная отслеживаемость: от окончательного ответа до выбранных ребер и исходных документов. + +Объяснимость во время выполнения запроса фиксирует действия, которые выполняет конвейер GraphRAG во время рассуждений. Она связана с информацией о происхождении, которая записывается во время извлечения и фиксирует, откуда взялись факты графа знаний. + +## Терминология + +| Термин | Определение | +|------|------------| +| **Объяснимость** | Запись о том, как был получен результат | +| **Сессия** | Одиночное выполнение запроса GraphRAG | +| **Выбор ребра** | Выбор релевантных ребер с использованием LLM и обоснованием | +| **Цепь происхождения** | Путь от ребра → фрагмента → страницы → документа | + +## Архитектура + +### Поток объяснимости + +``` +GraphRAG Query + │ + ├─► Session Activity + │ └─► Query text, timestamp + │ + ├─► Retrieval Entity + │ └─► All edges retrieved from subgraph + │ + ├─► Selection Entity + │ └─► Selected edges with LLM reasoning + │ └─► Each edge links to extraction provenance + │ + └─► Answer Entity + └─► Reference to synthesized response (in librarian) +``` + +### Двухэтапная конвейерная обработка GraphRAG + +1. **Выбор ребер**: LLM выбирает релевантные ребра из подграфа, предоставляя обоснование для каждого. +2. **Синтез**: LLM генерирует ответ, используя только выбранные ребра. + +Такое разделение обеспечивает объяснимость - мы точно знаем, какие ребра внесли вклад. + +### Хранилище + +Тройки, обеспечивающие объяснимость, хранятся в настраиваемой коллекции (по умолчанию: `explainability`). +Используется онтология PROV-O для отношений происхождения. +RDF-star для ссылок на ребра. +Содержимое ответа хранится в сервисе librarian (не встроено - слишком большой объем). + +### Потоковая передача в реальном времени + +События, обеспечивающие объяснимость, передаются клиенту в процессе выполнения запроса: + +1. Создание сессии → событие отправлено. +2. Получение ребер → событие отправлено. +3. Выбор ребер с обоснованием → событие отправлено. +4. Синтез ответа → событие отправлено. + +Клиент получает `explain_id` и `explain_collection` для получения полной информации. + +## Структура URI + +Все URI используют пространство имен `urn:trustgraph:` с UUID: + +| Сущность | Шаблон URI | +|--------|-------------| +| Сессия | `urn:trustgraph:session:{uuid}` | +| Получение | `urn:trustgraph:prov:retrieval:{uuid}` | +| Выбор | `urn:trustgraph:prov:selection:{uuid}` | +| Ответ | `urn:trustgraph:prov:answer:{uuid}` | +| Выбор ребра | `urn:trustgraph:prov:edge:{uuid}:{index}` | + +## Модель RDF (PROV-O) + +### Сессия активности + +```turtle + a prov:Activity ; + rdfs:label "GraphRAG query session" ; + prov:startedAtTime "2024-01-15T10:30:00Z" ; + tg:query "What was the War on Terror?" . +``` + +### Получение сущности + +```turtle + a prov:Entity ; + rdfs:label "Retrieved edges" ; + prov:wasGeneratedBy ; + tg:edgeCount 50 . +``` + +### Выбор сущности + +```turtle + a prov:Entity ; + rdfs:label "Selected edges" ; + prov:wasDerivedFrom ; + tg:selectedEdge ; + tg:selectedEdge . + + tg:edge <<

>> ; + tg:reasoning "This edge establishes the key relationship..." . +``` + +### Ответная сущность + +```turtle + a prov:Entity ; + rdfs:label "GraphRAG answer" ; + prov:wasDerivedFrom ; + tg:document . +``` + +`tg:document` ссылается на ответ, хранящийся в сервисе librarian. + +## Константы пространства имен + +Определены в `trustgraph-base/trustgraph/provenance/namespaces.py`: + +| Константа | URI | +|----------|-----| +| `TG_QUERY` | `https://trustgraph.ai/ns/query` | +| `TG_EDGE_COUNT` | `https://trustgraph.ai/ns/edgeCount` | +| `TG_SELECTED_EDGE` | `https://trustgraph.ai/ns/selectedEdge` | +| `TG_EDGE` | `https://trustgraph.ai/ns/edge` | +| `TG_REASONING` | `https://trustgraph.ai/ns/reasoning` | +| `TG_CONTENT` | `https://trustgraph.ai/ns/content` | +| `TG_DOCUMENT` | `https://trustgraph.ai/ns/document` | + +## Схема GraphRagResponse + +```python +@dataclass +class GraphRagResponse: + error: Error | None = None + response: str = "" + end_of_stream: bool = False + explain_id: str | None = None + explain_collection: str | None = None + message_type: str = "" # "chunk" or "explain" + end_of_session: bool = False +``` + +### Типы сообщений + +| message_type | Назначение | +|--------------|---------| +| `chunk` | Текстовый ответ (потоковый или окончательный) | +| `explain` | Событие, связанное с объяснимостью, с ссылкой IRI | + +### Жизненный цикл сессии + +1. Несколько сообщений `explain` (сессия, получение, выбор, ответ) +2. Несколько сообщений `chunk` (потоковый ответ) +3. Окончательное сообщение `chunk` с `end_of_session=True` + +## Формат выбора ребер + +LLM возвращает JSONL с выбранными ребрами: + +```jsonl +{"id": "edge-hash-1", "reasoning": "This edge shows the key relationship..."} +{"id": "edge-hash-2", "reasoning": "Provides supporting evidence..."} +``` + +`id` является хешем `(labeled_s, labeled_p, labeled_o)`, вычисленным с помощью `edge_id()`. + +## Сохранение URI + +### Проблема + +GraphRAG отображает для LLM удобочитаемые метки, но для отслеживания происхождения необходимы исходные URI. + +### Решение + +`get_labelgraph()` возвращает следующее: +`labeled_edges`: Список `(label_s, label_p, label_o)` для LLM +`uri_map`: Словарь, сопоставляющий `edge_id(labels)` → `(uri_s, uri_p, uri_o)` + +При хранении данных для объяснения используются URI из `uri_map`. + +## Отслеживание происхождения + +### От узла к источнику + +Выбранные узлы можно проследить до исходных документов: + +1. Запрос для получения содержащего подграфа: `?subgraph tg:contains <>` +2. Переход по цепочке `prov:wasDerivedFrom` к корневому документу +3. Каждый шаг в цепочке: фрагмент → страница → документ + +### Поддержка тройных наборов в Cassandra + +Сервис запросов Cassandra поддерживает сопоставление тройных наборов: + +```python +# In get_term_value(): +elif term.type == TRIPLE: + return serialize_triple(term.triple) +``` + +Это позволяет выполнять запросы, такие как: +``` +?subgraph tg:contains <> +``` + +## Использование интерфейса командной строки + +```bash +tg-invoke-graph-rag --explainable -q "What was the War on Terror?" +``` + +### Формат вывода + +``` +[session] urn:trustgraph:session:abc123 + +[retrieval] urn:trustgraph:prov:retrieval:abc123 + +[selection] urn:trustgraph:prov:selection:abc123 + Selected 12 edge(s) + Edge: (Guantanamo, definition, A detention facility...) + Reason: Directly connects Guantanamo to the War on Terror + Source: Chunk 1 → Page 2 → Beyond the Vigilant State + +[answer] urn:trustgraph:prov:answer:abc123 + +Based on the provided knowledge statements... +``` + +### Особенности + +События объяснения в реальном времени во время запроса. +Разрешение меток для компонентов ребер с помощью `rdfs:label`. +Отслеживание цепочки источников с помощью `prov:wasDerivedFrom`. +Кэширование меток для предотвращения повторных запросов. + +## Реализованные файлы + +| Файл | Назначение | +|------|---------| +| `trustgraph-base/trustgraph/provenance/uris.py` | Генераторы URI | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | Константы пространства имен RDF | +| `trustgraph-base/trustgraph/provenance/triples.py` | Конструкторы троек | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | Схема GraphRagResponse | +| `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` | Основной GraphRAG с сохранением URI | +| `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` | Сервис с интеграцией с библиотекарем | +| `trustgraph-flow/trustgraph/query/triples/cassandra/service.py` | Поддержка запросов троек в кавычках | +| `trustgraph-cli/trustgraph/cli/invoke_graph_rag.py` | CLI с отображением объяснений | + +## Ссылки + +PROV-O (W3C Provenance Ontology): https://www.w3.org/TR/prov-o/ +RDF-star: https://w3c.github.io/rdf-star/ +Происхождение во время извлечения: `docs/tech-specs/extraction-time-provenance.md` diff --git a/docs/tech-specs/query-time-explainability.sw.md b/docs/tech-specs/query-time-explainability.sw.md new file mode 100644 index 00000000..804a541b --- /dev/null +++ b/docs/tech-specs/query-time-explainability.sw.md @@ -0,0 +1,263 @@ +# Ufafanuzi wa Wakati wa Uchunguzi + +## Hali + +Imetekelezwa + +## Muhtasari + +Maelekezo haya yanaelezea jinsi GraphRAG inavyorekodi na kuwasilisha data ya ufafanuzi wakati wa utekelezaji wa uchunguzi. Lengo ni ufuatiliaji kamili: kutoka kwa jibu la mwisho, kiasi kupitia miunganisho iliyochaguliwa, hadi kwa nyaraka za asili. + +Ufafanuzi wa wakati wa uchunguzi unaeleza kile ambacho mstari wa GraphRAG ulifanya wakati wa utaratibu. Inahusiana na uhifadhi wa wakati wa uchimbaji ambao unarekodi mahali ambapo ukweli wa grafu ya maarifa ulitoka. + +## Dhana + +| Neno | Ufafanuzi | +|------|------------| +| **Ufafanuzi** | Rekodi ya jinsi matokeo yalivyopatikana | +| **Kipindi** | Utendaji mmoja wa GraphRAG | +| **Uchaguzi wa Miunganisho** | Uchaguzi wa miunganisho inayofaa inayodumishwa na LLM pamoja na utaratibu | +| **Mnyororo wa Uhifadhi** | Njia kutoka kwa miunganisho → kipande → ukurasa → nyaraka | + +## Muundo + +### Mtiririko wa Ufafanuzi + +``` +GraphRAG Query + │ + ├─► Session Activity + │ └─► Query text, timestamp + │ + ├─► Retrieval Entity + │ └─► All edges retrieved from subgraph + │ + ├─► Selection Entity + │ └─► Selected edges with LLM reasoning + │ └─► Each edge links to extraction provenance + │ + └─► Answer Entity + └─► Reference to synthesized response (in librarian) +``` + +### Mfumo wa Hatua Mbili wa GraphRAG + +1. **Uchaguzi wa Njia (Edge)**: LLM huangalia njia muhimu kutoka kwenye sehemu ndogo ya grafu, hutoa maelezo kwa kila moja. +2. **Uunganisho (Synthesis)**: LLM huunda jibu kutoka kwa njia zilizochaguliwa pekee. + +Tofauti hii inaruhusu uelewaji - tunajua hasa ni njia zipi zilizochangia. + +### Uhifadhi + +Matriki ya uelewaji yaliyohifadhiwa katika mkusanyiko unaoweza kusanidiwa (kiwango chake: `explainability`) +Hutumia ontolojia ya PROV-O kwa uhusiano wa asili. +Ufafanuzi wa RDF-star kwa marejeleo ya njia. +Yaliyomo ya jibu yamehifadhiwa katika huduma ya "librarian" (hayapo ndani - ni makubwa). + +### Uhamishaji wa Muda Halisi + +Matukio ya uelewaji huhamishwa kwa mteja wakati swali linapojibiwa: + +1. Kipindi kimeanzishwa → tukio limehamishwa +2. Njia zimepatikana → tukio limehamishwa +3. Njia zimechaguliwa pamoja na maelezo → tukio limehamishwa +4. Jibu limeunganishwa → tukio limehamishwa + +Mteja hupokea `explain_id` na `explain_collection` ili kupata maelezo kamili. + +## Muundo wa URI + +URI zote hutumia nafasi ya `urn:trustgraph:` pamoja na UUIDs: + +| Kitu | Muundo wa URI | +|--------|-------------| +| Kipindi | `urn:trustgraph:session:{uuid}` | +| Kupata | `urn:trustgraph:prov:retrieval:{uuid}` | +| Uchaguzi | `urn:trustgraph:prov:selection:{uuid}` | +| Jibu | `urn:trustgraph:prov:answer:{uuid}` | +| Uchaguzi wa Njia | `urn:trustgraph:prov:edge:{uuid}:{index}` | + +## Mfumo wa RDF (PROV-O) + +### Shughuli ya Kipindi + +```turtle + a prov:Activity ; + rdfs:label "GraphRAG query session" ; + prov:startedAtTime "2024-01-15T10:30:00Z" ; + tg:query "What was the War on Terror?" . +``` + +### Kitengo cha Upatikanaji + +```turtle + a prov:Entity ; + rdfs:label "Retrieved edges" ; + prov:wasGeneratedBy ; + tg:edgeCount 50 . +``` + +### Kitengo cha Uchaguzi + +```turtle + a prov:Entity ; + rdfs:label "Selected edges" ; + prov:wasDerivedFrom ; + tg:selectedEdge ; + tg:selectedEdge . + + tg:edge <<

>> ; + tg:reasoning "This edge establishes the key relationship..." . +``` + +### Jibu la Kitu + +```turtle + a prov:Entity ; + rdfs:label "GraphRAG answer" ; + prov:wasDerivedFrom ; + tg:document . +``` + +`tg:document` inarejelea jibu lililohifadhiwa katika huduma ya msimamizi. + +## Mara kwa Mara za Nafasi + +Zimefafumiwa katika `trustgraph-base/trustgraph/provenance/namespaces.py`: + +| Mara kwa Mara | URI | +|----------|-----| +| `TG_QUERY` | `https://trustgraph.ai/ns/query` | +| `TG_EDGE_COUNT` | `https://trustgraph.ai/ns/edgeCount` | +| `TG_SELECTED_EDGE` | `https://trustgraph.ai/ns/selectedEdge` | +| `TG_EDGE` | `https://trustgraph.ai/ns/edge` | +| `TG_REASONING` | `https://trustgraph.ai/ns/reasoning` | +| `TG_CONTENT` | `https://trustgraph.ai/ns/content` | +| `TG_DOCUMENT` | `https://trustgraph.ai/ns/document` | + +## Muundo wa GraphRagResponse + +```python +@dataclass +class GraphRagResponse: + error: Error | None = None + response: str = "" + end_of_stream: bool = False + explain_id: str | None = None + explain_collection: str | None = None + message_type: str = "" # "chunk" or "explain" + end_of_session: bool = False +``` + +### Aina za Ujumbe + +| aina_ya_ujumbe | Madhumuni | +|--------------|---------| +| `chunk` | Nakala ya majibu (ya mtiririko au ya mwisho) | +| `explain` | Tukio la kufafanua na rejea ya IRI | + +### Mzunguko wa Kisesheni + +1. Ujumbe mwingi wa `explain` (kisesheni, upataji, uchaguzi, jibu) +2. Ujumbe mwingi wa `chunk` (jibu la mtiririko) +3. `chunk` ya mwisho na `end_of_session=True` + +## Muundo wa Uchaguzi wa Njia + +LLM hurudisha JSONL na njia zilizochaguliwa: + +```jsonl +{"id": "edge-hash-1", "reasoning": "This edge shows the key relationship..."} +{"id": "edge-hash-2", "reasoning": "Provides supporting evidence..."} +``` + +`id` ni hash ya `(labeled_s, labeled_p, labeled_o)` iliyohesabiwa na `edge_id()`. + +## Uhifadhi wa URI + +### Tatizo + +GraphRAG huonyesha lebo zinazoweza kusomwa na binadamu kwa LLM, lakini uelewaji unahitaji URI za asili kwa ajili ya kufuatilia asili. + +### Suluhisho + +`get_labelgraph()` hurudisha vitu viwili: +`labeled_edges`: Orodha ya `(label_s, label_p, label_o)` kwa ajili ya LLM +`uri_map`: Kamusi inayoeleanisha `edge_id(labels)` → `(uri_s, uri_p, uri_o)` + +Wakati wa kuhifadhi data ya uelewaji, URI kutoka `uri_map` hutumiwa. + +## Kufuatilia Asili + +### Kutoka Kwenye Njia hadi Chanzo + +Njia zilizochaguliwa zinaweza kufuatiliwa hadi kwenye hati za asili: + +1. Tafuta subgraph inayoyajumuisha: `?subgraph tg:contains <>` +2. Fuata mnyororo wa `prov:wasDerivedFrom` hadi kwenye hati ya msingi +3. Kila hatua katika mnyororo: kipande → ukurasa → hati + +### Usaidizi wa Triple Zilizotiwa Nukuu wa Cassandra + +Huduma ya utafutaji ya Cassandra inasaidia kulinganisha triple zilizotiwa nukuu: + +```python +# In get_term_value(): +elif term.type == TRIPLE: + return serialize_triple(term.triple) +``` + +Hii inawezesha maswali kama vile: +``` +?subgraph tg:contains <> +``` + +## Matumizi ya Kifaa Kikuu (CLI) + +```bash +tg-invoke-graph-rag --explainable -q "What was the War on Terror?" +``` + +### Muundo wa Matokeo + +``` +[session] urn:trustgraph:session:abc123 + +[retrieval] urn:trustgraph:prov:retrieval:abc123 + +[selection] urn:trustgraph:prov:selection:abc123 + Selected 12 edge(s) + Edge: (Guantanamo, definition, A detention facility...) + Reason: Directly connects Guantanamo to the War on Terror + Source: Chunk 1 → Page 2 → Beyond the Vigilant State + +[answer] urn:trustgraph:prov:answer:abc123 + +Based on the provided knowledge statements... +``` + +### Vipengele + +Matukio ya uwazi wa matendo kwa wakati halisi wakati wa swali. +Utatuzi wa lebo kwa vipengele vya pembe kupitia `rdfs:label` +Ufuatiliaji wa mnyororo wa chanzo kupitia `prov:wasDerivedFrom` +Kumbukumbu ya lebo ili kuepuka maswali yanayorudiwa. + +## Faili Zilizotumiwa + +| Faili | Madhumuni | +|------|---------| +| `trustgraph-base/trustgraph/provenance/uris.py` | Vitu vya kuunda URI | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | Mara kwa mara ya nafasi ya RDF | +| `trustgraph-base/trustgraph/provenance/triples.py` | Vitu vya kuunda triple | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | Mpango wa GraphRagResponse | +| `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` | GraphRAG ya msingi na uhifadhi wa URI | +| `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` | Huduma na ujumuishaji wa msimamizi | +| `trustgraph-flow/trustgraph/query/triples/cassandra/service.py` | Usaidizi wa swali la triple lililotiwa nukuu | +| `trustgraph-cli/trustgraph/cli/invoke_graph_rag.py` | CLI na onyesho la uwazi | + +## Marejeleo + +PROV-O (Ontolojia ya Asili ya W3C): https://www.w3.org/TR/prov-o/ +RDF-star: https://w3c.github.io/rdf-star/ +Asili ya wakati wa uondoaji: `docs/tech-specs/extraction-time-provenance.md` diff --git a/docs/tech-specs/query-time-explainability.tr.md b/docs/tech-specs/query-time-explainability.tr.md new file mode 100644 index 00000000..ea0b05ea --- /dev/null +++ b/docs/tech-specs/query-time-explainability.tr.md @@ -0,0 +1,263 @@ +# Sorgu Zamanı Açıklanabilirlik + +## Durum + +Uygulandı + +## Genel Bakış + +Bu özellik, GraphRAG'ın sorgu yürütülmesi sırasında açıklanabilirlik verilerini nasıl kaydettiğini ve ilettiğini açıklamaktadır. Amaç, nihai cevaptan başlayarak, seçilen kenarlara ve kaynak belgelere kadar tam bir izlenebilirlik sağlamaktır. + +Sorgu zamanı açıklanabilirliği, GraphRAG boru hattının akıl yürütme sırasında neler yaptığını yakalar. Bu, bilginin nereden geldiğini kaydeden, çıkarma zamanı köken bilgilerine bağlanır. + +## Terminoloji + +| Terim | Tanım | +|------|------------| +| **Açıklanabilirlik** | Bir sonucun nasıl elde edildiğinin kaydı | +| **Oturum** | Tek bir GraphRAG sorgu yürütmesi | +| **Kenar Seçimi** | Akıl yürütmeyle ilgili kenarların LLM tarafından seçilmesi | +| **Köken Zinciri** | Kenar → parça → sayfa → belge yolu | + +## Mimari + +### Açıklanabilirlik Akışı + +``` +GraphRAG Query + │ + ├─► Session Activity + │ └─► Query text, timestamp + │ + ├─► Retrieval Entity + │ └─► All edges retrieved from subgraph + │ + ├─► Selection Entity + │ └─► Selected edges with LLM reasoning + │ └─► Each edge links to extraction provenance + │ + └─► Answer Entity + └─► Reference to synthesized response (in librarian) +``` + +### İki Aşamalı GraphRAG İşlem Hattı + +1. **Kenar Seçimi**: LLM, alt grafikten ilgili kenarları seçer ve her biri için bir gerekçe sunar. +2. **Sentez**: LLM, yalnızca seçilen kenarlardan cevap oluşturur. + +Bu ayrım, açıklanabilirliği sağlar - hangi kenarların katkıda bulunduğunu tam olarak biliyoruz. + +### Depolama + +Açıklanabilirlik üçlüleri, yapılandırılabilir bir koleksiyonda saklanır (varsayılan: `explainability`). +Kaynak ilişkileri için PROV-O ontolojisi kullanılır. +Kenar referansları için RDF-star yeniden tanımlaması. +Cevap içeriği, kütüphaneci hizmetinde saklanır (satır içi değil - çok büyük). + +### Gerçek Zamanlı Akış + +Açıklanabilirlik olayları, sorgu yürütüldüğü sırada istemciye akış olarak gönderilir: + +1. Oturum oluşturuldu → olay gönderildi. +2. Kenarlar alındı → olay gönderildi. +3. Gerekçeyle birlikte kenarlar seçildi → olay gönderildi. +4. Cevap oluşturuldu → olay gönderildi. + +İstemci, `explain_id` ve `explain_collection`'i tam ayrıntıları almak için kullanır. + +## URI Yapısı + +Tüm URI'ler, UUID'lerle birlikte `urn:trustgraph:` ad alanını kullanır: + +| Varlık | URI Kalıbı | +|--------|-------------| +| Oturum | `urn:trustgraph:session:{uuid}` | +| Alma | `urn:trustgraph:prov:retrieval:{uuid}` | +| Seçim | `urn:trustgraph:prov:selection:{uuid}` | +| Cevap | `urn:trustgraph:prov:answer:{uuid}` | +| Kenar Seçimi | `urn:trustgraph:prov:edge:{uuid}:{index}` | + +## RDF Modeli (PROV-O) + +### Oturum Etkinliği + +```turtle + a prov:Activity ; + rdfs:label "GraphRAG query session" ; + prov:startedAtTime "2024-01-15T10:30:00Z" ; + tg:query "What was the War on Terror?" . +``` + +### Veri Alma Varlığı + +```turtle + a prov:Entity ; + rdfs:label "Retrieved edges" ; + prov:wasGeneratedBy ; + tg:edgeCount 50 . +``` + +### Seçim Varlığı + +```turtle + a prov:Entity ; + rdfs:label "Selected edges" ; + prov:wasDerivedFrom ; + tg:selectedEdge ; + tg:selectedEdge . + + tg:edge <<

>> ; + tg:reasoning "This edge establishes the key relationship..." . +``` + +### Cevap Varlığı + +```turtle + a prov:Entity ; + rdfs:label "GraphRAG answer" ; + prov:wasDerivedFrom ; + tg:document . +``` + +`tg:document`, kütüphaneci hizmetinde saklanan cevabı referans alır. + +## Ad Alanı Sabitleri + +`trustgraph-base/trustgraph/provenance/namespaces.py` içinde tanımlanmıştır: + +| Sabit | URI | +|----------|-----| +| `TG_QUERY` | `https://trustgraph.ai/ns/query` | +| `TG_EDGE_COUNT` | `https://trustgraph.ai/ns/edgeCount` | +| `TG_SELECTED_EDGE` | `https://trustgraph.ai/ns/selectedEdge` | +| `TG_EDGE` | `https://trustgraph.ai/ns/edge` | +| `TG_REASONING` | `https://trustgraph.ai/ns/reasoning` | +| `TG_CONTENT` | `https://trustgraph.ai/ns/content` | +| `TG_DOCUMENT` | `https://trustgraph.ai/ns/document` | + +## GraphRagResponse Şeması + +```python +@dataclass +class GraphRagResponse: + error: Error | None = None + response: str = "" + end_of_stream: bool = False + explain_id: str | None = None + explain_collection: str | None = None + message_type: str = "" # "chunk" or "explain" + end_of_session: bool = False +``` + +### Mesaj Türleri + +| mesaj_türü | Amaç | +|--------------|---------| +| `chunk` | Yanıt metni (akış veya son) | +| `explain` | IRI referansıyla açıklanabilirlik olayı | + +### Oturum Yaşam Döngüsü + +1. Birden fazla `explain` mesajı (oturum, alma, seçim, yanıt) +2. Birden fazla `chunk` mesajı (akış yanıtı) +3. `end_of_session=True` ile birlikte son `chunk` + +## Kenar Seçim Formatı + +LLM, seçilen kenarlarla birlikte JSONL döndürür: + +```jsonl +{"id": "edge-hash-1", "reasoning": "This edge shows the key relationship..."} +{"id": "edge-hash-2", "reasoning": "Provides supporting evidence..."} +``` + +`id`, `(labeled_s, labeled_p, labeled_o)`'nin `edge_id()` tarafından hesaplanan bir karma değeridir. + +## URI'nin Korunması + +### Sorun + +GraphRAG, LLM'ye okunabilir etiketler gösterir, ancak açıklanabilirlik, köken takibi için orijinal URI'lere ihtiyaç duyar. + +### Çözüm + +`get_labelgraph()`, şunları döndürür: +`labeled_edges`: LLM için `(label_s, label_p, label_o)` listesi +`uri_map`: `edge_id(labels)` → `(uri_s, uri_p, uri_o)` eşlemesini içeren sözlük + +Açıklanabilirlik verilerini saklarken, `uri_map`'dan gelen URI'ler kullanılır. + +## Köken Takibi + +### Kaynaktan Kenara + +Seçilen kenarlar, kaynak belgelere kadar izlenebilir: + +1. İçeren alt grafiği sorgulayın: `?subgraph tg:contains <>` +2. Kök belgeye kadar `prov:wasDerivedFrom` zincirini izleyin +3. Zincirdeki her adım: parça → sayfa → belge + +### Cassandra Tırnaklı Üçlü Desteği + +Cassandra sorgu hizmeti, tırnaklı üçlüleri eşleştirmeyi destekler: + +```python +# In get_term_value(): +elif term.type == TRIPLE: + return serialize_triple(term.triple) +``` + +Bu, şu tür sorguları mümkün kılar: +``` +?subgraph tg:contains <> +``` + +## CLI Kullanımı + +```bash +tg-invoke-graph-rag --explainable -q "What was the War on Terror?" +``` + +### Çıktı Formatı + +``` +[session] urn:trustgraph:session:abc123 + +[retrieval] urn:trustgraph:prov:retrieval:abc123 + +[selection] urn:trustgraph:prov:selection:abc123 + Selected 12 edge(s) + Edge: (Guantanamo, definition, A detention facility...) + Reason: Directly connects Guantanamo to the War on Terror + Source: Chunk 1 → Page 2 → Beyond the Vigilant State + +[answer] urn:trustgraph:prov:answer:abc123 + +Based on the provided knowledge statements... +``` + +### Özellikler + +Sorgu sırasında gerçek zamanlı açıklanabilirlik olayları +`rdfs:label` aracılığıyla kenar bileşenleri için etiket çözümü +`prov:wasDerivedFrom` aracılığıyla kaynak zinciri takibi +Tekrarlanan sorguları önlemek için etiket önbelleği + +## Uygulanan Dosyalar + +| Dosya | Amaç | +|------|---------| +| `trustgraph-base/trustgraph/provenance/uris.py` | URI oluşturucular | +| `trustgraph-base/trustgraph/provenance/namespaces.py` | RDF ad alanı sabitleri | +| `trustgraph-base/trustgraph/provenance/triples.py` | Üçlü oluşturucular | +| `trustgraph-base/trustgraph/schema/services/retrieval.py` | GraphRagResponse şeması | +| `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` | URI korumasıyla temel GraphRAG | +| `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` | Kütüphaneci entegrasyonlu hizmet | +| `trustgraph-flow/trustgraph/query/triples/cassandra/service.py` | Tırnaklı üçlü sorgu desteği | +| `trustgraph-cli/trustgraph/cli/invoke_graph_rag.py` | Açıklanabilirlik gösterimiyle CLI | + +## Referanslar + +PROV-O (W3C Provenance Ontology): https://www.w3.org/TR/prov-o/ +RDF-star: https://w3c.github.io/rdf-star/ +Çıkarma zamanı kökeni: `docs/tech-specs/extraction-time-provenance.md` diff --git a/docs/tech-specs/rag-streaming-support.hi.md b/docs/tech-specs/rag-streaming-support.hi.md new file mode 100644 index 00000000..d296fd02 --- /dev/null +++ b/docs/tech-specs/rag-streaming-support.hi.md @@ -0,0 +1,288 @@ +# RAG स्ट्रीमिंग सपोर्ट तकनीकी विनिर्देश + +## अवलोकन + +यह विनिर्देश ग्राफआरएजी और डॉक्यूमेंटआरएजी सेवाओं में स्ट्रीमिंग सपोर्ट जोड़ने का वर्णन करता है, जो नॉलेज ग्राफ और डॉक्यूमेंट रिट्रीवल क्वेरी के लिए वास्तविक समय में टोकन-दर-टोकन प्रतिक्रियाएं सक्षम करता है। यह एलएलएम टेक्स्ट-कंप्लीशन, प्रॉम्प्ट और एजेंट सेवाओं के लिए पहले से लागू किए गए मौजूदा स्ट्रीमिंग आर्किटेक्चर का विस्तार करता है। + +## लक्ष्य + +**संगत स्ट्रीमिंग यूएक्स**: सभी ट्रस्टग्राफ सेवाओं में समान स्ट्रीमिंग अनुभव प्रदान करें। +**न्यूनतम एपीआई परिवर्तन**: एक ही `streaming` फ़्लैग के साथ स्ट्रीमिंग सपोर्ट जोड़ें, स्थापित पैटर्न का पालन करें। +**पिछड़ा संगतता**: मौजूदा गैर-स्ट्रीमिंग व्यवहार को डिफ़ॉल्ट के रूप में बनाए रखें। +**मौजूदा बुनियादी ढांचे का पुन: उपयोग**: पहले से लागू प्रॉम्प्टक्लाइंट स्ट्रीमिंग का लाभ उठाएं। +**गेटवे सपोर्ट**: क्लाइंट एप्लिकेशन के लिए वेबसॉकेट गेटवे के माध्यम से स्ट्रीमिंग सक्षम करें। + +## पृष्ठभूमि + +वर्तमान में लागू की गई स्ट्रीमिंग सेवाएं: +**एलएलएम टेक्स्ट-कंप्लीशन सेवा**: चरण 1 - एलएलएम प्रदाताओं से स्ट्रीमिंग। +**प्रॉम्प्ट सेवा**: चरण 2 - प्रॉम्प्ट टेम्प्लेट के माध्यम से स्ट्रीमिंग। +**एजेंट सेवा**: चरण 3-4 - इंक्रीमेंटल थॉट/ऑब्जर्वेशन/एन्सर चंक्स के साथ रीएक्ट प्रतिक्रियाओं को स्ट्रीमिंग करना। + +आरएजी सेवाओं के लिए वर्तमान सीमाएं: +ग्राफआरएजी और डॉक्यूमेंटआरएजी केवल ब्लॉकिंग प्रतिक्रियाओं का समर्थन करते हैं। +उपयोगकर्ताओं को किसी भी आउटपुट को देखने से पहले एलएलएम प्रतिक्रिया पूरी होने तक इंतजार करना होगा। +नॉलेज ग्राफ या डॉक्यूमेंट क्वेरी से लंबी प्रतिक्रियाओं के लिए खराब यूएक्स। +अन्य ट्रस्टग्राफ सेवाओं की तुलना में असंगत अनुभव। + +यह विनिर्देश ग्राफआरएजी और डॉक्यूमेंटआरएजी में स्ट्रीमिंग सपोर्ट जोड़कर इन कमियों को दूर करता है। टोकन-दर-टोकन प्रतिक्रियाओं को सक्षम करके, ट्रस्टग्राफ: +सभी क्वेरी प्रकारों में संगत स्ट्रीमिंग यूएक्स प्रदान कर सकता है। +आरएजी क्वेरी के लिए कथित विलंबता को कम कर सकता है। +लंबी अवधि की क्वेरी के लिए बेहतर प्रगति प्रतिक्रिया प्रदान कर सकता है। +क्लाइंट एप्लिकेशन में वास्तविक समय प्रदर्शन का समर्थन कर सकता है। + +## तकनीकी डिजाइन + +### आर्किटेक्चर + +आरएजी स्ट्रीमिंग कार्यान्वयन मौजूदा बुनियादी ढांचे का लाभ उठाता है: + +1. **प्रॉम्प्टक्लाइंट स्ट्रीमिंग** (पहले से लागू) + `kg_prompt()` और `document_prompt()` पहले से ही `streaming` और `chunk_callback` पैरामीटर स्वीकार करते हैं। + ये आंतरिक रूप से स्ट्रीमिंग सपोर्ट के साथ `prompt()` को कॉल करते हैं। + प्रॉम्प्टक्लाइंट में कोई बदलाव आवश्यक नहीं है। + + मॉड्यूल: `trustgraph-base/trustgraph/base/prompt_client.py` + +2. **ग्राफआरएजी सेवा** (स्ट्रीमिंग पैरामीटर पास-थ्रू की आवश्यकता है) + `query()` विधि में `streaming` पैरामीटर जोड़ें। + `prompt_client.kg_prompt()` और कॉलबैक को `prompt_client.kg_prompt()` में पास करें। + ग्राफआरैग रिक्वेस्ट स्कीमा में `streaming` फ़ील्ड की आवश्यकता है। + + मॉड्यूल: + `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` + `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (प्रोसेसर) + `trustgraph-base/trustgraph/schema/graph_rag.py` (रिक्वेस्ट स्कीमा) + `trustgraph-flow/trustgraph/gateway/dispatch/graph_rag.py` (गेटवे) + +3. **डॉक्यूमेंटआरएजी सेवा** (स्ट्रीमिंग पैरामीटर पास-थ्रू की आवश्यकता है) + `query()` विधि में `streaming` पैरामीटर जोड़ें। + `prompt_client.document_prompt()` और कॉलबैक को `prompt_client.document_prompt()` में पास करें। + डॉक्यूमेंटआरैग रिक्वेस्ट स्कीमा में `streaming` फ़ील्ड की आवश्यकता है। + + मॉड्यूल: + `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` + `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` (प्रोसेसर) + `trustgraph-base/trustgraph/schema/document_rag.py` (रिक्वेस्ट स्कीमा) + `trustgraph-flow/trustgraph/gateway/dispatch/document_rag.py` (गेटवे) + +### डेटा फ्लो + +**गैर-स्ट्रीमिंग (वर्तमान)**: +``` +Client → Gateway → RAG Service → PromptClient.kg_prompt(streaming=False) + ↓ + Prompt Service → LLM + ↓ + Complete response + ↓ +Client ← Gateway ← RAG Service ← Response +``` + +**स्ट्रीमिंग (प्रस्तावित):** +``` +Client → Gateway → RAG Service → PromptClient.kg_prompt(streaming=True, chunk_callback=cb) + ↓ + Prompt Service → LLM (streaming) + ↓ + Chunk → callback → RAG Response (chunk) + ↓ ↓ +Client ← Gateway ← ────────────────────────────────── Response stream +``` + +### एपीआई (APIs) + +**ग्राफआरएजी (GraphRAG) में बदलाव**: + +1. **GraphRag.query()** - स्ट्रीमिंग पैरामीटर जोड़े गए। +```python +async def query( + self, query, user, collection, + verbose=False, streaming=False, chunk_callback=None # NEW +): + # ... existing entity/triple retrieval ... + + if streaming and chunk_callback: + resp = await self.prompt_client.kg_prompt( + query, kg, + streaming=True, + chunk_callback=chunk_callback + ) + else: + resp = await self.prompt_client.kg_prompt(query, kg) + + return resp +``` + +2. **ग्राफराग रिक्वेस्ट स्कीमा** - स्ट्रीमिंग फ़ील्ड जोड़ें। +```python +class GraphRagRequest(Record): + query = String() + user = String() + collection = String() + streaming = Boolean() # NEW +``` + +3. **ग्राफराग रिस्पांस स्कीमा** - स्ट्रीमिंग फ़ील्ड जोड़ें (एजेंट पैटर्न का पालन करें)। +```python +class GraphRagResponse(Record): + response = String() # Legacy: complete response + chunk = String() # NEW: streaming chunk + end_of_stream = Boolean() # NEW: indicates last chunk +``` + +4. **प्रोसेसर** - डेटा को लगातार प्रवाहित करें। +```python +async def handle(self, msg): + # ... existing code ... + + async def send_chunk(chunk): + await self.respond(GraphRagResponse( + chunk=chunk, + end_of_stream=False, + response=None + )) + + if request.streaming: + full_response = await self.rag.query( + query=request.query, + user=request.user, + collection=request.collection, + streaming=True, + chunk_callback=send_chunk + ) + # Send final message + await self.respond(GraphRagResponse( + chunk=None, + end_of_stream=True, + response=full_response + )) + else: + # Existing non-streaming path + response = await self.rag.query(...) + await self.respond(GraphRagResponse(response=response)) +``` + +**डॉक्यूमेंटआरएजी में परिवर्तन**: + +ग्राफआरएजी के समान पैटर्न: +1. `streaming` और `chunk_callback` पैरामीटर को `DocumentRag.query()` में जोड़ें। +2. `streaming` फ़ील्ड को `DocumentRagRequest` में जोड़ें। +3. `chunk` और `end_of_stream` फ़ील्ड को `DocumentRagResponse` में जोड़ें। +4. प्रोसेसर को कॉलबैक के साथ स्ट्रीमिंग को संभालने के लिए अपडेट करें। + +**गेटवे में परिवर्तन**: + +गेटवे/डिस्पैच में `graph_rag.py` और `document_rag.py` दोनों को वेबसॉकेट पर स्ट्रीमिंग चंक्स को अग्रेषित करने के लिए अपडेट की आवश्यकता है: + +```python +async def handle(self, message, session, websocket): + # ... existing code ... + + if request.streaming: + async def recipient(resp): + if resp.chunk: + await websocket.send(json.dumps({ + "id": message["id"], + "response": {"chunk": resp.chunk}, + "complete": resp.end_of_stream + })) + return resp.end_of_stream + + await self.rag_client.request(request, recipient=recipient) + else: + # Existing non-streaming path + resp = await self.rag_client.request(request) + await websocket.send(...) +``` + +### कार्यान्वयन विवरण + +**कार्यान्वयन क्रम**: +1. स्कीमा फ़ील्ड जोड़ें (RAG सेवाओं दोनों के लिए अनुरोध + प्रतिक्रिया) +2. GraphRag.query() और DocumentRag.query() विधियों को अपडेट करें +3. प्रोसेसर को स्ट्रीमिंग को संभालने के लिए अपडेट करें +4. गेटवे डिस्पैच हैंडलर को अपडेट करें +5. `--no-streaming` ध्वज `tg-invoke-graph-rag` और `tg-invoke-document-rag` में जोड़ें (डिफ़ॉल्ट रूप से स्ट्रीमिंग सक्षम, एजेंट CLI पैटर्न का अनुसरण करते हुए) + +**कॉलबैक पैटर्न**: +एजेंट स्ट्रीमिंग में स्थापित समान एसिंक्रोनस कॉल बैक पैटर्न का पालन करें: +प्रोसेसर `async def send_chunk(chunk)` कॉल बैक को परिभाषित करता है +कॉल बैक को RAG सेवा को पास करता है +RAG सेवा कॉल बैक को PromptClient को पास करती है +PromptClient प्रत्येक LLM टुकड़े के लिए कॉल बैक को लागू करता है +प्रोसेसर प्रत्येक टुकड़े के लिए स्ट्रीमिंग प्रतिक्रिया संदेश भेजता है + +**त्रुटि प्रबंधन**: +स्ट्रीमिंग के दौरान होने वाली त्रुटियों को `end_of_stream=True` के साथ त्रुटि प्रतिक्रिया भेजनी चाहिए +एजेंट स्ट्रीमिंग से मौजूदा त्रुटि प्रसार पैटर्न का पालन करें + +## सुरक्षा संबंधी विचार + +मौजूदा RAG सेवाओं से परे कोई नया सुरक्षा संबंधी विचार नहीं: +स्ट्रीमिंग प्रतिक्रियाएं समान उपयोगकर्ता/संग्रह अलगाव का उपयोग करती हैं +प्रमाणीकरण या प्राधिकरण में कोई बदलाव नहीं +टुकड़े की सीमाएं संवेदनशील डेटा को उजागर नहीं करती हैं + +## प्रदर्शन संबंधी विचार + +**लाभ**: +कथित विलंबता में कमी (पहले टोकन तेजी से आते हैं) +लंबे उत्तरों के लिए बेहतर UX +कम मेमोरी उपयोग (पूरे उत्तर को बफर करने की आवश्यकता नहीं है) + +**संभावित चिंताएं**: +स्ट्रीमिंग प्रतिक्रियाओं के लिए अधिक Pulsar संदेश +टुकड़ा करने/कॉल बैक ओवरहेड के लिए थोड़ा अधिक CPU +स्ट्रीमिंग वैकल्पिक है, डिफ़ॉल्ट गैर-स्ट्रीमिंग रहता है, जिससे इसे कम किया जा सकता है + +**परीक्षण संबंधी विचार**: +बड़ी नॉलेज ग्राफ (कई त्रिगुण) के साथ परीक्षण करें +कई पुनर्प्राप्त दस्तावेज़ों के साथ परीक्षण करें +स्ट्रीमिंग बनाम गैर-स्ट्रीमिंग के ओवरहेड को मापें + +## परीक्षण रणनीति + +**इकाई परीक्षण**: +streaming=True/False के साथ GraphRag.query() का परीक्षण करें +streaming=True/False के साथ DocumentRag.query() का परीक्षण करें +कॉल बैक कार्यान्वयन को सत्यापित करने के लिए PromptClient को मॉक करें + +**एकीकरण परीक्षण**: +पूर्ण GraphRAG स्ट्रीमिंग प्रवाह का परीक्षण करें (मौजूदा एजेंट स्ट्रीमिंग परीक्षणों के समान) +पूर्ण DocumentRAG स्ट्रीमिंग प्रवाह का परीक्षण करें +गेटवे स्ट्रीमिंग अग्रेषण का परीक्षण करें +CLI स्ट्रीमिंग आउटपुट का परीक्षण करें + +**मैन्युअल परीक्षण**: +`tg-invoke-graph-rag -q "What is machine learning?"` (डिफ़ॉल्ट रूप से स्ट्रीमिंग) +`tg-invoke-document-rag -q "Summarize the documents about AI"` (डिफ़ॉल्ट रूप से स्ट्रीमिंग) +`tg-invoke-graph-rag --no-streaming -q "..."` (गैर-स्ट्रीमिंग मोड का परीक्षण करें) +सत्यापित करें कि स्ट्रीमिंग मोड में वृद्धिशील आउटपुट दिखाई दे रहा है + +## माइग्रेशन योजना + +माइग्रेशन की आवश्यकता नहीं: +`streaming` पैरामीटर (डिफ़ॉल्ट रूप से False) के माध्यम से स्ट्रीमिंग वैकल्पिक है +मौजूदा क्लाइंट अपरिवर्तित रहते हैं +नए क्लाइंट स्ट्रीमिंग को अपना सकते हैं + +## समयरेखा + +अनुमानित कार्यान्वयन: 4-6 घंटे +चरण 1 (2 घंटे): GraphRAG स्ट्रीमिंग समर्थन +चरण 2 (2 घंटे): DocumentRAG स्ट्रीमिंग समर्थन +चरण 3 (1-2 घंटे): गेटवे अपडेट और CLI ध्वज +परीक्षण: प्रत्येक चरण में शामिल + +## खुले प्रश्न + +क्या हमें NLP क्वेरी सेवा में भी स्ट्रीमिंग समर्थन जोड़ना चाहिए? +क्या हम केवल LLM आउटपुट या मध्यवर्ती चरणों (जैसे, "इकाइयों को पुनर्प्राप्त करना...", "ग्राफ को क्वेरी करना...") को स्ट्रीम करना चाहते हैं? +क्या GraphRAG/DocumentRAG प्रतिक्रियाओं में टुकड़े मेटाडेटा (जैसे, टुकड़े संख्या, कुल अपेक्षित) शामिल होना चाहिए? + +## संदर्भ + +मौजूदा कार्यान्वयन: `docs/tech-specs/streaming-llm-responses.md` +एजेंट स्ट्रीमिंग: `trustgraph-flow/trustgraph/agent/react/agent_manager.py` +PromptClient स्ट्रीमिंग: `trustgraph-base/trustgraph/base/prompt_client.py` diff --git a/docs/tech-specs/rag-streaming-support.pt.md b/docs/tech-specs/rag-streaming-support.pt.md new file mode 100644 index 00000000..427811eb --- /dev/null +++ b/docs/tech-specs/rag-streaming-support.pt.md @@ -0,0 +1,288 @@ +# Especificação Técnica de Suporte a Streaming RAG + +## Visão Geral + +Esta especificação descreve a adição de suporte a streaming aos serviços GraphRAG e DocumentRAG, permitindo respostas em tempo real, token por token, para consultas de grafos de conhecimento e recuperação de documentos. Isso estende a arquitetura de streaming existente já implementada para serviços de preenchimento de texto, prompt e agente LLM. + +## Objetivos + +**Experiência de streaming consistente**: Fornecer a mesma experiência de streaming em todos os serviços TrustGraph. +**Alterações mínimas na API**: Adicionar suporte a streaming com um único sinalizador `streaming`, seguindo padrões estabelecidos. +**Compatibilidade com versões anteriores**: Manter o comportamento padrão existente sem streaming. +**Reutilizar infraestrutura existente**: Aproveitar o streaming do PromptClient já implementado. +**Suporte a gateway**: Permitir o streaming através do gateway WebSocket para aplicativos cliente. + +## Contexto + +Serviços de streaming atualmente implementados: +**Serviço de preenchimento de texto LLM**: Fase 1 - streaming de provedores LLM. +**Serviço de prompt**: Fase 2 - streaming através de modelos de prompt. +**Serviço de agente**: Fase 3-4 - streaming de respostas ReAct com fragmentos incrementais de pensamento/observação/resposta. + +Limitações atuais para serviços RAG: +GraphRAG e DocumentRAG suportam apenas respostas bloqueadas. +Os usuários devem esperar pela resposta completa do LLM antes de ver qualquer saída. +Má experiência do usuário para respostas longas de grafos de conhecimento ou consultas de documentos. +Experiência inconsistente em comparação com outros serviços TrustGraph. + +Esta especificação aborda essas lacunas adicionando suporte a streaming ao GraphRAG e ao DocumentRAG. Ao permitir respostas token por token, o TrustGraph pode: +Fornecer uma experiência de streaming consistente em todos os tipos de consulta. +Reduzir a latência percebida para consultas RAG. +Permitir um melhor feedback de progresso para consultas de longa duração. +Suportar a exibição em tempo real em aplicativos cliente. + +## Design Técnico + +### Arquitetura + +A implementação de streaming RAG aproveita a infraestrutura existente: + +1. **Streaming do PromptClient** (Já implementado) + `kg_prompt()` e `document_prompt()` já aceitam parâmetros `streaming` e `chunk_callback`. + Isso chama `prompt()` internamente com suporte a streaming. + Não são necessárias alterações no PromptClient. + + Módulo: `trustgraph-base/trustgraph/base/prompt_client.py` + +2. **Serviço GraphRAG** (Precisa de passagem de parâmetro de streaming) + Adicionar parâmetro `streaming` ao método `query()`. + Passar o sinalizador de streaming e os callbacks para `prompt_client.kg_prompt()`. + O esquema GraphRagRequest precisa do campo `streaming`. + + Módulos: + `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` + `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (Processador) + `trustgraph-base/trustgraph/schema/graph_rag.py` (Esquema de solicitação) + `trustgraph-flow/trustgraph/gateway/dispatch/graph_rag.py` (Gateway) + +3. **Serviço DocumentRAG** (Precisa de passagem de parâmetro de streaming) + Adicionar parâmetro `streaming` ao método `query()`. + Passar o sinalizador de streaming e os callbacks para `prompt_client.document_prompt()`. + O esquema DocumentRagRequest precisa do campo `streaming`. + + Módulos: + `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` + `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` (Processador) + `trustgraph-base/trustgraph/schema/document_rag.py` (Esquema de solicitação) + `trustgraph-flow/trustgraph/gateway/dispatch/document_rag.py` (Gateway) + +### Fluxo de Dados + +**Não streaming (atual)**: +``` +Client → Gateway → RAG Service → PromptClient.kg_prompt(streaming=False) + ↓ + Prompt Service → LLM + ↓ + Complete response + ↓ +Client ← Gateway ← RAG Service ← Response +``` + +**Streaming (proposto):** +``` +Client → Gateway → RAG Service → PromptClient.kg_prompt(streaming=True, chunk_callback=cb) + ↓ + Prompt Service → LLM (streaming) + ↓ + Chunk → callback → RAG Response (chunk) + ↓ ↓ +Client ← Gateway ← ────────────────────────────────── Response stream +``` + +### APIs + +**Alterações no GraphRAG**: + +1. **GraphRag.query()** - Adicionar parâmetros de streaming +```python +async def query( + self, query, user, collection, + verbose=False, streaming=False, chunk_callback=None # NEW +): + # ... existing entity/triple retrieval ... + + if streaming and chunk_callback: + resp = await self.prompt_client.kg_prompt( + query, kg, + streaming=True, + chunk_callback=chunk_callback + ) + else: + resp = await self.prompt_client.kg_prompt(query, kg) + + return resp +``` + +2. **Esquema GraphRagRequest** - Adicionar campo de streaming. +```python +class GraphRagRequest(Record): + query = String() + user = String() + collection = String() + streaming = Boolean() # NEW +``` + +3. **Esquema GraphRagResponse** - Adicionar campos de streaming (seguir o padrão do Agente). +```python +class GraphRagResponse(Record): + response = String() # Legacy: complete response + chunk = String() # NEW: streaming chunk + end_of_stream = Boolean() # NEW: indicates last chunk +``` + +4. **Processador** - Permitir a passagem de dados em fluxo contínuo. +```python +async def handle(self, msg): + # ... existing code ... + + async def send_chunk(chunk): + await self.respond(GraphRagResponse( + chunk=chunk, + end_of_stream=False, + response=None + )) + + if request.streaming: + full_response = await self.rag.query( + query=request.query, + user=request.user, + collection=request.collection, + streaming=True, + chunk_callback=send_chunk + ) + # Send final message + await self.respond(GraphRagResponse( + chunk=None, + end_of_stream=True, + response=full_response + )) + else: + # Existing non-streaming path + response = await self.rag.query(...) + await self.respond(GraphRagResponse(response=response)) +``` + +**Alterações no DocumentRAG:** + +Padrão idêntico ao GraphRAG: +1. Adicionar parâmetros `streaming` e `chunk_callback` a `DocumentRag.query()` +2. Adicionar campo `streaming` a `DocumentRagRequest` +3. Adicionar campos `chunk` e `end_of_stream` a `DocumentRagResponse` +4. Atualizar o Processador para lidar com streaming com callbacks + +**Alterações no Gateway:** + +Tanto `graph_rag.py` quanto `document_rag.py` no gateway/dispatch precisam de atualizações para encaminhar trechos de streaming para o websocket: + +```python +async def handle(self, message, session, websocket): + # ... existing code ... + + if request.streaming: + async def recipient(resp): + if resp.chunk: + await websocket.send(json.dumps({ + "id": message["id"], + "response": {"chunk": resp.chunk}, + "complete": resp.end_of_stream + })) + return resp.end_of_stream + + await self.rag_client.request(request, recipient=recipient) + else: + # Existing non-streaming path + resp = await self.rag_client.request(request) + await websocket.send(...) +``` + +### Detalhes de Implementação + +**Ordem de implementação**: +1. Adicionar campos de esquema (Request + Response para ambos os serviços RAG) +2. Atualizar os métodos GraphRag.query() e DocumentRag.query() +3. Atualizar Processadores para lidar com streaming +4. Atualizar manipuladores de despacho do Gateway +5. Adicionar `--no-streaming` flags a `tg-invoke-graph-rag` e `tg-invoke-document-rag` (streaming habilitado por padrão, seguindo o padrão da CLI do agente) + +**Padrão de callback**: +Seguir o mesmo padrão de callback assíncrono estabelecido no streaming do Agente: +O Processador define o `async def send_chunk(chunk)` callback +Passa o callback para o serviço RAG +O serviço RAG passa o callback para o PromptClient +O PromptClient invoca o callback para cada chunk do LLM +O Processador envia uma mensagem de resposta de streaming para cada chunk + +**Tratamento de erros**: +Erros durante o streaming devem enviar uma resposta de erro com `end_of_stream=True` +Seguir os padrões existentes de propagação de erros do streaming do Agente + +## Considerações de Segurança + +Não há novas considerações de segurança além dos serviços RAG existentes: +As respostas de streaming usam o mesmo isolamento de usuário/coleção +Não há alterações na autenticação ou autorização +Os limites de chunk não expõem dados sensíveis + +## Considerações de Desempenho + +**Benefícios**: +Latência percebida reduzida (os primeiros tokens chegam mais rápido) +Melhor experiência do usuário para respostas longas +Menor uso de memória (não é necessário armazenar em buffer a resposta completa) + +**Preocupações potenciais**: +Mais mensagens Pulsar para respostas de streaming +Ligeiramente maior uso de CPU para a sobrecarga de chunking/callback +Mitigado por: o streaming é opcional, o padrão permanece não-streaming + +**Considerações de teste**: +Testar com grafos de conhecimento grandes (muitos triplos) +Testar com muitos documentos recuperados +Medir a sobrecarga do streaming versus não-streaming + +## Estratégia de Teste + +**Testes unitários**: +Testar GraphRag.query() com streaming=True/False +Testar DocumentRag.query() com streaming=True/False +Simular o PromptClient para verificar as invocações de callback + +**Testes de integração**: +Testar o fluxo completo de streaming do GraphRAG (semelhante aos testes existentes de streaming do agente) +Testar o fluxo completo de streaming do DocumentRAG +Testar o encaminhamento de streaming do Gateway +Testar a saída de streaming da CLI + +**Testes manuais**: +`tg-invoke-graph-rag -q "What is machine learning?"` (streaming por padrão) +`tg-invoke-document-rag -q "Summarize the documents about AI"` (streaming por padrão) +`tg-invoke-graph-rag --no-streaming -q "..."` (testar o modo não-streaming) +Verificar se a saída incremental aparece no modo de streaming + +## Plano de Migração + +Nenhuma migração necessária: +O streaming é opcional por meio do parâmetro `streaming` (o padrão é Falso) +Os clientes existentes continuam a funcionar sem alterações +Novos clientes podem optar por usar o streaming + +## Cronograma + +Tempo estimado de implementação: 4-6 horas +Fase 1 (2 horas): suporte de streaming do GraphRAG +Fase 2 (2 horas): suporte de streaming do DocumentRAG +Fase 3 (1-2 horas): atualizações do Gateway e flags da CLI +Testes: integrados em cada fase + +## Perguntas Abertas + +Devemos adicionar suporte de streaming ao serviço de consulta NLP também? +Queremos transmitir etapas intermediárias (por exemplo, "Recuperando entidades...", "Consultando o grafo...") ou apenas a saída do LLM? +As respostas do GraphRAG/DocumentRAG devem incluir metadados do chunk (por exemplo, número do chunk, total esperado)? + +## Referências + +Implementação existente: `docs/tech-specs/streaming-llm-responses.md` +Streaming do Agente: `trustgraph-flow/trustgraph/agent/react/agent_manager.py` +Streaming do PromptClient: `trustgraph-base/trustgraph/base/prompt_client.py` diff --git a/docs/tech-specs/rag-streaming-support.sw.md b/docs/tech-specs/rag-streaming-support.sw.md new file mode 100644 index 00000000..7adb3a94 --- /dev/null +++ b/docs/tech-specs/rag-streaming-support.sw.md @@ -0,0 +1,288 @@ +# Vigezo vya Ufundi kwa Usaidizi wa Utiririshaji (Streaming) + +## Muhtasari + +Vigezo hivi vinaelezea kuongeza usaidizi wa utiririshaji kwa huduma za GraphRAG na DocumentRAG, na hivyo kuruhusu majibu ya wakati halisi, token kwa token, kwa maswali ya chati ya maarifa na utafutaji wa nyaraka. Hii inaongeza usanifu uliopo wa utiririshaji ambao tayari umetumiwa kwa huduma za kukamilisha maandishi, matamshi, na wakala (agent) za LLM. + +## Lengo + +**Uzoefu sawa wa utiririshaji**: Kutoa uzoefu sawa wa utiririshaji katika huduma zote za TrustGraph. +**Mabadiliko madogo ya API**: Kuongeza usaidizi wa utiririshaji kwa bendera moja `streaming`, kufuata mifumo iliyopo. +**Ulinganifu na matumizi ya awali**: Kuhifadhi tabia ya sasa isiyo ya utiririshaji kama chaguo-msingi. +**Kutumia miundombinu iliyopo**: Kutumia utiririshaji wa PromptClient ambao tayari umetumiwa. +**Usaidizi wa lango (gateway)**: Kuruhusu utiririshaji kupitia lango la websocket kwa programu za wateja. + +## Asili + +Huduma za utiririshaji zilizotumiwa kwa sasa: +**Huduma ya kukamilisha maandishi ya LLM**: Awamu ya 1 - utiririshaji kutoka kwa watoa huduma wa LLM. +**Huduma ya matamshi**: Awamu ya 2 - utiririshaji kupitia vipatacho vya matamshi. +**Huduma ya wakala**: Awamu ya 3-4 - utiririshaji wa majibu ya ReAct kwa vipande vya hatua/angalifu/jibu. + +Mapungufu ya sasa kwa huduma za RAG: +GraphRAG na DocumentRAG zinaunga mkono tu majibu ya kukomesha. +Watumiaji lazima wasubiri majibu kamili ya LLM kabla ya kuona matokeo yoyote. +Uzoefu mbaya kwa majibu marefu kutoka kwa chati ya maarifa au maswali ya nyaraka. +Uzoefu usio sawa na huduma zingine za TrustGraph. + +Vigezo hivi vinashughulikia pengo hizi kwa kuongeza usaidizi wa utiririshaji kwa GraphRAG na DocumentRAG. Kwa kuruhusu majibu ya token kwa token, TrustGraph inaweza: +Kutoa uzoefu sawa wa utiririshaji kwa aina zote za maswali. +Kupunguza muda uliodhaniwa wa maswali ya RAG. +Kuruhusu maoni bora ya maendeleo kwa maswali yanayoendelea. +Kusaidia onyesho la wakati halisi katika programu za wateja. + +## Muundo wa Ufundi + +### Usanifu + +Utumiaji wa utiririshaji wa RAG hutumia miundombinu iliyopo: + +1. **Utiririshaji wa PromptClient** (Tayari umetumiwa) + `kg_prompt()` na `document_prompt()` tayari hupokea vigezo vya `streaming` na `chunk_callback`. + Haya huita `prompt()` ndani na usaidizi wa utiririshaji. + Hakuna mabadiliko yanayohitajika kwa PromptClient. + + Moduli: `trustgraph-base/trustgraph/base/prompt_client.py` + +2. **Huduma ya GraphRAG** (Inahitaji kupitisha parameter ya utiririshaji) + Ongeza parameter ya `streaming` kwa njia ya `query()`. + Pasa bendera ya utiririshaji na vipengele vya kurudisha (callbacks) kwa `prompt_client.kg_prompt()`. + Schema ya GraphRagRequest inahitaji sehemu ya `streaming`. + + Moduli: + `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` + `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (Mchakato) + `trustgraph-base/trustgraph/schema/graph_rag.py` (Schema ya ombi) + `trustgraph-flow/trustgraph/gateway/dispatch/graph_rag.py` (Lango) + +3. **Huduma ya DocumentRAG** (Inahitaji kupitisha parameter ya utiririshaji) + Ongeza parameter ya `streaming` kwa njia ya `query()`. + Pasa bendera ya utiririshaji na vipengele vya kurudisha (callbacks) kwa `prompt_client.document_prompt()`. + Schema ya DocumentRagRequest inahitaji sehemu ya `streaming`. + + Moduli: + `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` + `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` (Mchakato) + `trustgraph-base/trustgraph/schema/document_rag.py` (Schema ya ombi) + `trustgraph-flow/trustgraph/gateway/dispatch/document_rag.py` (Lango) + +### Mtiririko wa Data + +**Usiokuwa na utiririshaji (sasa)**: +``` +Client → Gateway → RAG Service → PromptClient.kg_prompt(streaming=False) + ↓ + Prompt Service → LLM + ↓ + Complete response + ↓ +Client ← Gateway ← RAG Service ← Response +``` + +**Utiririshaji (kupendekezwa):** +``` +Client → Gateway → RAG Service → PromptClient.kg_prompt(streaming=True, chunk_callback=cb) + ↓ + Prompt Service → LLM (streaming) + ↓ + Chunk → callback → RAG Response (chunk) + ↓ ↓ +Client ← Gateway ← ────────────────────────────────── Response stream +``` + +### API + +**Mabadiliko ya GraphRAG**: + +1. **GraphRag.query()** - Ongeza vigezo vya utiririshaji +```python +async def query( + self, query, user, collection, + verbose=False, streaming=False, chunk_callback=None # NEW +): + # ... existing entity/triple retrieval ... + + if streaming and chunk_callback: + resp = await self.prompt_client.kg_prompt( + query, kg, + streaming=True, + chunk_callback=chunk_callback + ) + else: + resp = await self.prompt_client.kg_prompt(query, kg) + + return resp +``` + +2. **Muundo wa GraphRagRequest** - Ongeza sehemu ya utiririshaji. +```python +class GraphRagRequest(Record): + query = String() + user = String() + collection = String() + streaming = Boolean() # NEW +``` + +3. **Muundo wa GraphRagResponse** - Ongeza sehemu za utiririshaji (fuata mfumo wa Wakala). +```python +class GraphRagResponse(Record): + response = String() # Legacy: complete response + chunk = String() # NEW: streaming chunk + end_of_stream = Boolean() # NEW: indicates last chunk +``` + +4. **Mchakato** - Ruhusu mtiririko kupita. +```python +async def handle(self, msg): + # ... existing code ... + + async def send_chunk(chunk): + await self.respond(GraphRagResponse( + chunk=chunk, + end_of_stream=False, + response=None + )) + + if request.streaming: + full_response = await self.rag.query( + query=request.query, + user=request.user, + collection=request.collection, + streaming=True, + chunk_callback=send_chunk + ) + # Send final message + await self.respond(GraphRagResponse( + chunk=None, + end_of_stream=True, + response=full_response + )) + else: + # Existing non-streaming path + response = await self.rag.query(...) + await self.respond(GraphRagResponse(response=response)) +``` + +**Mabadiliko ya DocumentRAG**: + +Muundo sawa na GraphRAG: +1. Ongeza vigezo `streaming` na `chunk_callback` kwenye `DocumentRag.query()` +2. Ongeza sehemu `streaming` kwenye `DocumentRagRequest` +3. Ongeza sehemu `chunk` na `end_of_stream` kwenye `DocumentRagResponse` +4. Sasisha Processor ili kushughulikia utiririshaji pamoja na arifa + +**Mabadiliko ya Gateway**: + +Zote `graph_rag.py` na `document_rag.py` katika gateway/dispatch zinahitaji sasisho ili kusambaza vipande vya utiririshaji hadi kwenye websocket: + +```python +async def handle(self, message, session, websocket): + # ... existing code ... + + if request.streaming: + async def recipient(resp): + if resp.chunk: + await websocket.send(json.dumps({ + "id": message["id"], + "response": {"chunk": resp.chunk}, + "complete": resp.end_of_stream + })) + return resp.end_of_stream + + await self.rag_client.request(request, recipient=recipient) + else: + # Existing non-streaming path + resp = await self.rag_client.request(request) + await websocket.send(...) +``` + +### Maelekezo ya Utendaji + +**Utaratibu wa utendaji**: +1. Ongeza sehemu za schema (Ombi + Jibu kwa huduma zote za RAG) +2. Sasisha mbinu za GraphRag.query() na DocumentRag.query() +3. Sasisha Wasindikaji ili kushughulikia utiririshaji +4. Sasisha vichakavu vya usambazaji +5. Ongeza `--no-streaming` bendera kwenye `tg-invoke-graph-rag` na `tg-invoke-document-rag` (utiririshaji umeanzishwa kwa chaguizi, kufuatia mtindo wa CLI ya wakala) + +**Mfumo wa kurudisha matokeo**: +Fuata mfumo sawa wa kurudisha matokeo wa async uliopo katika utiririshaji wa Wakala: +Wasindikaji hufafanua `async def send_chunk(chunk)` kurudisha matokeo +Hutuma kurudisha matokeo kwa huduma ya RAG +Huduma ya RAG hutuma kurudisha matokeo kwa PromptClient +PromptClient huita kurudisha matokeo kwa kila kipande cha LLM +Wasindikaji hutuma ujumbe wa utiririshaji wa jibu kwa kila kipande + +**Usimamizi wa makosa**: +Makosa wakati wa utiririshaji yanapaswa kutuma jibu la makosa na `end_of_stream=True` +Fuata mifumo iliyopo ya usambazaji wa makosa kutoka kwa utiririshaji wa Wakala + +## Masuala ya Usalama + +Hakuna masuala mapya ya usalama zaidi ya huduma zilizopo za RAG: +Majibu ya utiririshaji hutumia kutengwa sawa kwa mtumiaji/mkusanyiko +Hakuna mabadiliko ya uthibitishaji au idhini +Hifadhi za vipande hazifichui data nyeti + +## Masuala ya Utendaji + +**Faida**: +Kupunguza latensi iliyohisiwa (vipande vya kwanza vinakuja haraka) +Uzoefu bora wa mtumiaji kwa majibu marefu +Matumizi ya chini ya kumbukumbu (hakuna haja ya kuhifadhi jibu kamili) + +**Masuala yanayoweza kutokea**: +Ujumbe zaidi wa Pulsar kwa majibu ya utiririshaji +CPU kidogo ya juu kwa gharama ya vipande/kurudisha matokeo +Imepunguzwa na: utiririshaji ni chaguo, chaguo-msingi inabaki bila utiririshaji + +**Masuala ya upimaji**: +Pima na vielelezo vikubwa vya maarifa (triple nyingi) +Pima na hati nyingi zilizopatikana +Pima gharama ya utiririshaji dhidi ya utiririshaji usio na utiririshaji + +## Mkakati wa Upimaji + +**Majaribio ya kitengo**: +Pima GraphRag.query() na streaming=True/False +Pima DocumentRag.query() na streaming=True/False +Fanya PromptClient kuwa bandia ili kuhakikisha utendaji wa kurudisha matokeo + +**Majaribio ya ujumuu**: +Pima mtiririko kamili wa GraphRAG wa utiririshaji (sawa na majaribio ya sasa ya utiririshaji wa wakala) +Pima mtiririko kamili wa DocumentRAG wa utiririshaji +Pima usambazaji wa utiririshaji wa Gateway +Pima pato la utiririshaji la CLI + +**Upimaji wa mwongozo**: +`tg-invoke-graph-rag -q "What is machine learning?"` (utiririshaji kwa chaguizi) +`tg-invoke-document-rag -q "Summarize the documents about AI"` (utiririshaji kwa chaguizi) +`tg-invoke-graph-rag --no-streaming -q "..."` (pima hali ya utiririshaji usio na utiririshaji) +Hakikisha pato linaloongezwa linaonekana katika hali ya utiririshaji + +## Mpango wa Uhamisho + +Hakuna uhamishaji unaohitajika: +Utiririshaji ni chaguo kupitia parameter ya `streaming` (ina chaguizi kuwa Fele) +Wateja wenyewe wanaendelea kufanya kazi bila mabadiliko +Wateja wapya wanaweza kuchagua utiririshaji + +## Muda + +Muda uliokadiriwa wa utekelezaji: saa 4-6 +Awamu ya 1 (saa 2): Usaidizi wa utiririshaji wa GraphRAG +Awamu ya 2 (saa 2): Usaidizi wa utiririshaji wa DocumentRAG +Awamu ya 3 (saa 1-2): Madaisho ya Gateway na bendera za CLI +Upimaji: Umejumuishwa katika kila awamu + +## Maswali yaliyofunguliwa + +Je, tunapaswa kuongeza usaidizi wa utiririshaji kwa huduma ya NLP Query pia? +Je, tunataka kuonyesha hatua za kati (k.m., "Kupata vyombo vya habari...", "Kusahihisha grafu...") au tu pato la LLM? +Je, majibu ya GraphRAG/DocumentRAG yanapaswa kujumuisha metadata ya kipande (k.m., nambari ya kipande, jumla inayotarajiwa)? + +## Marejeleo + +Utekelezaji uliopo: `docs/tech-specs/streaming-llm-responses.md` +Utiririshaji wa Wakala: `trustgraph-flow/trustgraph/agent/react/agent_manager.py` +PromptClient utiririshaji: `trustgraph-base/trustgraph/base/prompt_client.py` diff --git a/docs/tech-specs/rag-streaming-support.tr.md b/docs/tech-specs/rag-streaming-support.tr.md new file mode 100644 index 00000000..cacb5d38 --- /dev/null +++ b/docs/tech-specs/rag-streaming-support.tr.md @@ -0,0 +1,288 @@ +# RAG Akış Desteği Teknik Özellikleri + +## Genel Bakış + +Bu özellik, GraphRAG ve DocumentRAG hizmetlerine akış desteği eklemeyi tanımlar. Bu, bilgi grafiği ve belge sorguları için gerçek zamanlı, token bazlı yanıtlar sağlar. Bu, LLM metin tamamlama, istem ve ajan hizmetleri için zaten uygulanan mevcut akış mimarisini genişletir. + +## Hedefler + +**Tutarlı akış kullanıcı deneyimi**: Tüm TrustGraph hizmetlerinde aynı akış deneyimini sağlayın. +**Minimum API değişiklikleri**: Akış desteğini, yerleşik kalıpları izleyerek tek bir `streaming` bayrağıyla ekleyin. +**Geriye dönük uyumluluk**: Mevcut, akış olmayan davranışı varsayılan olarak koruyun. +**Mevcut altyapıyı yeniden kullanın**: Zaten uygulanan PromptClient akışını kullanın. +**Gateway desteği**: İstemci uygulamaları için websocket gateway üzerinden akışı etkinleştirin. + +## Arka Plan + +Şu anda uygulanan akış hizmetleri: +**LLM metin tamamlama hizmeti**: 1. Aşama - LLM sağlayıcılardan akış. +**İstem hizmeti**: 2. Aşama - istem şablonları aracılığıyla akış. +**Ajan hizmeti**: 3.-4. Aşama - ReAct yanıtlarını, artımlı düşünce/gözlem/cevap parçalarıyla akış. + +RAG hizmetleri için mevcut sınırlamalar: +GraphRAG ve DocumentRAG yalnızca engellenen yanıtları destekler. +Kullanıcılar, herhangi bir çıktı görmeden önce LLM'den gelen tamamlanmış yanıtı beklemelidir. +Bilgi grafiği veya belge sorgularından gelen uzun yanıtlar için kötü kullanıcı deneyimi. +Diğer TrustGraph hizmetlerine kıyasla tutarsız deneyim. + +Bu özellik, GraphRAG ve DocumentRAG'a akış desteği ekleyerek bu boşlukları giderir. Token bazlı yanıtları etkinleştirerek, TrustGraph şunları yapabilir: +Tüm sorgu türleri için tutarlı bir akış kullanıcı deneyimi sağlayın. +RAG sorguları için algılanan gecikmeyi azaltın. +Uzun süren sorgular için daha iyi ilerleme geri bildirimi sağlayın. +İstemci uygulamalarında gerçek zamanlı görüntülemeyi destekleyin. + +## Teknik Tasarım + +### Mimari + +RAG akış uygulaması, mevcut altyapıyı kullanır: + +1. **PromptClient Akışı** (Zaten uygulandı) + `kg_prompt()` ve `document_prompt()` zaten `streaming` ve `chunk_callback` parametrelerini kabul eder. + Bunlar dahili olarak akış desteğiyle `prompt()`'ı çağırır. + PromptClient'ta herhangi bir değişiklik yapılmasına gerek yoktur. + + Modül: `trustgraph-base/trustgraph/base/prompt_client.py` + +2. **GraphRAG Hizmeti** (Akış parametresi geçişi gereklidir) + `query()` yöntemine `streaming` parametresini ekleyin. + Akış bayrağını ve geri çağırmaları `prompt_client.kg_prompt()`'a geçirin. + GraphRagRequest şemasının `streaming` alanına ihtiyacı vardır. + + Modüller: + `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` + `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (İşlemci) + `trustgraph-base/trustgraph/schema/graph_rag.py` (İstek şeması) + `trustgraph-flow/trustgraph/gateway/dispatch/graph_rag.py` (Gateway) + +3. **DocumentRAG Hizmeti** (Akış parametresi geçişi gereklidir) + `query()` yöntemine `streaming` parametresini ekleyin. + Akış bayrağını ve geri çağırmaları `prompt_client.document_prompt()`'a geçirin. + DocumentRagRequest şemasının `streaming` alanına ihtiyacı vardır. + + Modüller: + `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` + `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` (İşlemci) + `trustgraph-base/trustgraph/schema/document_rag.py` (İstek şeması) + `trustgraph-flow/trustgraph/gateway/dispatch/document_rag.py` (Gateway) + +### Veri Akışı + +**Engellenmeyen (mevcut)**: +``` +Client → Gateway → RAG Service → PromptClient.kg_prompt(streaming=False) + ↓ + Prompt Service → LLM + ↓ + Complete response + ↓ +Client ← Gateway ← RAG Service ← Response +``` + +**Akış (önerilen)**: +``` +Client → Gateway → RAG Service → PromptClient.kg_prompt(streaming=True, chunk_callback=cb) + ↓ + Prompt Service → LLM (streaming) + ↓ + Chunk → callback → RAG Response (chunk) + ↓ ↓ +Client ← Gateway ← ────────────────────────────────── Response stream +``` + +### API'ler + +**GraphRAG Değişiklikleri**: + +1. **GraphRag.query()** - Akış parametreleri eklendi. +```python +async def query( + self, query, user, collection, + verbose=False, streaming=False, chunk_callback=None # NEW +): + # ... existing entity/triple retrieval ... + + if streaming and chunk_callback: + resp = await self.prompt_client.kg_prompt( + query, kg, + streaming=True, + chunk_callback=chunk_callback + ) + else: + resp = await self.prompt_client.kg_prompt(query, kg) + + return resp +``` + +2. **GraphRagRequest şeması** - Akış alanı ekleyin. +```python +class GraphRagRequest(Record): + query = String() + user = String() + collection = String() + streaming = Boolean() # NEW +``` + +3. **GraphRagResponse şeması** - Akış alanlarını ekleyin (Agent modelini takip edin). +```python +class GraphRagResponse(Record): + response = String() # Legacy: complete response + chunk = String() # NEW: streaming chunk + end_of_stream = Boolean() # NEW: indicates last chunk +``` + +4. **İşlemci** - Veriyi sürekli akış halinde ilet. +```python +async def handle(self, msg): + # ... existing code ... + + async def send_chunk(chunk): + await self.respond(GraphRagResponse( + chunk=chunk, + end_of_stream=False, + response=None + )) + + if request.streaming: + full_response = await self.rag.query( + query=request.query, + user=request.user, + collection=request.collection, + streaming=True, + chunk_callback=send_chunk + ) + # Send final message + await self.respond(GraphRagResponse( + chunk=None, + end_of_stream=True, + response=full_response + )) + else: + # Existing non-streaming path + response = await self.rag.query(...) + await self.respond(GraphRagResponse(response=response)) +``` + +**DocumentRAG Değişiklikleri**: + +GraphRAG ile aynı yapı: +1. `streaming` ve `chunk_callback` parametrelerini `DocumentRag.query()`'ye ekleyin. +2. `streaming` alanını `DocumentRagRequest`'e ekleyin. +3. `chunk` ve `end_of_stream` alanlarını `DocumentRagResponse`'ye ekleyin. +4. İşlemciyi, geri çağırmalarla akışı işleyebilecek şekilde güncelleyin. + +**Gateway Değişiklikleri**: + +Hem `graph_rag.py` hem de `document_rag.py`, gateway/dispatch içinde, akış parçacıklarını websocket'e iletebilmesi için güncellenmelidir: + +```python +async def handle(self, message, session, websocket): + # ... existing code ... + + if request.streaming: + async def recipient(resp): + if resp.chunk: + await websocket.send(json.dumps({ + "id": message["id"], + "response": {"chunk": resp.chunk}, + "complete": resp.end_of_stream + })) + return resp.end_of_stream + + await self.rag_client.request(request, recipient=recipient) + else: + # Existing non-streaming path + resp = await self.rag_client.request(request) + await websocket.send(...) +``` + +### Uygulama Detayları + +**Uygulama sırası**: +1. Şema alanlarını ekleyin (Hem RAG hizmetleri için İstek + Yanıt) +2. GraphRag.query() ve DocumentRag.query() yöntemlerini güncelleyin +3. Akışı işlemek için İşleyicileri güncelleyin +4. Ağ geçidi yönlendirme işleyicilerini güncelleyin +5. `--no-streaming` bayraklarını `tg-invoke-graph-rag` ve `tg-invoke-document-rag`'ye ekleyin (akış varsayılan olarak etkindir, ajan CLI kalıbını takip eder) + +**Geri çağırma kalıbı**: +Ajan akışında oluşturulan aynı asenkron geri çağırma kalıbını izleyin: +İşleyici, `async def send_chunk(chunk)` geri çağrısını tanımlar +Geri çağrıyı RAG hizmetine iletir +RAG hizmeti, geri çağrıyı PromptClient'a iletir +PromptClient, her LLM parçası için geri çağrıyı çağırır +İşleyici, her parça için akış yanıt mesajını gönderir + +**Hata işleme**: +Akış sırasında oluşan hatalar, `end_of_stream=True` ile hata yanıtı göndermelidir +Ajan akışından mevcut hata yayılım kalıplarını izleyin + +## Güvenlik Hususları + +Mevcut RAG hizmetlerinin ötesinde yeni güvenlik hususları yoktur: +Akış yanıtları, aynı kullanıcı/toplam izolasyonunu kullanır +Kimlik doğrulama veya yetkilendirmede herhangi bir değişiklik yoktur +Parça sınırları, hassas verileri ortaya çıkarmaz + +## Performans Hususları + +**Faydaları**: +Algılanan gecikmenin azaltılması (ilk belirteçler daha hızlı gelir) +Uzun yanıtlar için daha iyi kullanıcı deneyimi +Daha düşük bellek kullanımı (tam yanıtı tamponlamaya gerek yoktur) + +**Olası endişeler**: +Akış yanıtları için daha fazla Pulsar mesajı +Parçalama/geri çağırma ek yükü için biraz daha yüksek CPU +Akış, isteğe bağlıdır, varsayılan olarak akış etkin değildir, bu nedenle bu sorunlar hafifletilmiştir + +**Test hususları**: +Çok sayıda üçlü içeren büyük bilgi grafikleriyle test edin +Çok sayıda alınmış belgeyle test edin +Akışın ve akış dışı durumun ek yükünü ölçün + +## Test Stratejisi + +**Birim testleri**: +GraphRag.query()'yi streaming=True/False ile test edin +DocumentRag.query()'yi streaming=True/False ile test edin +Geri çağırma çağrılarını doğrulamak için PromptClient'ı taklit edin + +**Entegrasyon testleri**: +Tam GraphRAG akışını test edin (mevcut ajan akış testlerine benzer) +Tam DocumentRAG akışını test edin +Ağ geçidi akış yönlendirmesini test edin +CLI akış çıktısını test edin + +**Manuel testler**: +`tg-invoke-graph-rag -q "What is machine learning?"` (akış varsayılan olarak etkindir) +`tg-invoke-document-rag -q "Summarize the documents about AI"` (akış varsayılan olarak etkindir) +`tg-invoke-graph-rag --no-streaming -q "..."` (akış dışı modu test edin) +Akış modunda kademeli çıktının göründüğünü doğrulayın + +## Geçiş Planı + +Herhangi bir geçişe gerek yoktur: +Akış, `streaming` parametresi aracılığıyla isteğe bağlıdır (varsayılan olarak False) +Mevcut istemciler, herhangi bir değişiklik olmadan çalışmaya devam eder +Yeni istemciler, akışı kullanabilir + +## Zaman Çizelgesi + +Tahmini uygulama süresi: 4-6 saat +1. Aşama (2 saat): GraphRAG akış desteği +2. Aşama (2 saat): DocumentRAG akış desteği +3. Aşama (1-2 saat): Ağ geçidi güncellemeleri ve CLI bayrakları +Test: Her aşamaya entegre edilmiştir + +## Açık Sorular + +NLP Sorgu hizmetine de akış desteği eklemeli miyiz? +Ara adımları (örneğin, "Varlıkların alınması...", "Grafiğin sorgulanması...") mi yoksa sadece LLM çıktısını mı akışa vermeliyiz? +GraphRAG/DocumentRAG yanıtları, parça meta verilerini (örneğin, parça numarası, toplam beklenen) içermeli mi? + +## Referanslar + +Mevcut uygulama: `docs/tech-specs/streaming-llm-responses.md` +Ajan akışı: `trustgraph-flow/trustgraph/agent/react/agent_manager.py` +PromptClient akışı: `trustgraph-base/trustgraph/base/prompt_client.py` diff --git a/docs/tech-specs/schema-refactoring-proposal.pt.md b/docs/tech-specs/schema-refactoring-proposal.pt.md new file mode 100644 index 00000000..426deb52 --- /dev/null +++ b/docs/tech-specs/schema-refactoring-proposal.pt.md @@ -0,0 +1,91 @@ +# Proposta de Refatoração do Diretório de Esquemas + +## Problemas Atuais + +1. **Estrutura plana** - Todos os esquemas em um único diretório dificultam a compreensão das relações. +2. **Preocupações misturadas** - Tipos principais, objetos de domínio e contratos de API todos misturados. +3. **Nomenclatura pouco clara** - Arquivos como "object.py", "types.py", "topic.py" não indicam claramente seu propósito. +4. **Ausência de camadas claras** - Não é fácil ver o que depende do quê. + +## Estrutura Proposta + +``` +trustgraph-base/trustgraph/schema/ +├── __init__.py +├── core/ # Core primitive types used everywhere +│ ├── __init__.py +│ ├── primitives.py # Error, Value, Triple, Field, RowSchema +│ ├── metadata.py # Metadata record +│ └── topic.py # Topic utilities +│ +├── knowledge/ # Knowledge domain models and extraction +│ ├── __init__.py +│ ├── graph.py # EntityContext, EntityEmbeddings, Triples +│ ├── document.py # Document, TextDocument, Chunk +│ ├── knowledge.py # Knowledge extraction types +│ ├── embeddings.py # All embedding-related types (moved from multiple files) +│ └── nlp.py # Definition, Topic, Relationship, Fact types +│ +└── services/ # Service request/response contracts + ├── __init__.py + ├── llm.py # TextCompletion, Embeddings, Tool requests/responses + ├── retrieval.py # GraphRAG, DocumentRAG queries/responses + ├── query.py # GraphEmbeddingsRequest/Response, DocumentEmbeddingsRequest/Response + ├── agent.py # Agent requests/responses + ├── flow.py # Flow requests/responses + ├── prompt.py # Prompt service requests/responses + ├── config.py # Configuration service + ├── library.py # Librarian service + └── lookup.py # Lookup service +``` + +## Principais Alterações + +1. **Organização hierárquica** - Separação clara entre tipos principais, modelos de conhecimento e contratos de serviço. +2. **Melhores nomes:** + `types.py` → `core/primitives.py` (propósito mais claro) + `object.py` → Divisão entre arquivos apropriados com base no conteúdo real. + `documents.py` → `knowledge/document.py` (singular, consistente) + `models.py` → `services/llm.py` (mais claro que tipo de modelos) + `prompt.py` → Divisão: partes de serviço para `services/prompt.py`, tipos de dados para `knowledge/nlp.py` + +3. **Agrupamento lógico:** + Todos os tipos de incorporação consolidados em `knowledge/embeddings.py` + Todos os contratos de serviço relacionados a LLM em `services/llm.py` + Separação clara de pares de solicitação/resposta no diretório de serviços. + Tipos de extração de conhecimento agrupados com outros modelos de domínio de conhecimento. + +4. **Clareza das dependências:** + Tipos principais não têm dependências. + Modelos de conhecimento dependem apenas do núcleo. + Contratos de serviço podem depender tanto do núcleo quanto dos modelos de conhecimento. + +## Benefícios da Migração + +1. **Navegação mais fácil** - Os desenvolvedores podem encontrar rapidamente o que precisam. +2. **Melhor modularidade** - Limites claros entre diferentes aspectos. +3. **Importações mais simples** - Caminhos de importação mais intuitivos. +4. **Preparado para o futuro** - Fácil de adicionar novos tipos de conhecimento ou serviços sem causar desordem. + +## Exemplos de Alterações de Importação + +```python +# Before +from trustgraph.schema import Error, Triple, GraphEmbeddings, TextCompletionRequest + +# After +from trustgraph.schema.core import Error, Triple +from trustgraph.schema.knowledge import GraphEmbeddings +from trustgraph.schema.services import TextCompletionRequest +``` + +## Notas de Implementação + +1. Mantenha a compatibilidade com versões anteriores, mantendo as importações no diretório raiz `__init__.py`. +2. Mova os arquivos gradualmente, atualizando as importações conforme necessário. +3. Considere adicionar um `legacy.py` que importe tudo para o período de transição. +4. Atualize a documentação para refletir a nova estrutura. + + + +[{"id": "1", "content": "Examinar a estrutura de diretórios do esquema atual", "status": "completed", "priority": "high"}, {"id": "2", "content": "Analisar os arquivos de esquema e seus propósitos", "status": "completed", "priority": "high"}, {"id": "3", "content": "Propor nomenclatura e estrutura aprimoradas", "status": "completed", "priority": "high"}] \ No newline at end of file diff --git a/docs/tech-specs/schema-refactoring-proposal.sw.md b/docs/tech-specs/schema-refactoring-proposal.sw.md new file mode 100644 index 00000000..a358bea5 --- /dev/null +++ b/docs/tech-specs/schema-refactoring-proposal.sw.md @@ -0,0 +1,91 @@ +# Pendekezo la Urekebishaji wa Saraka ya Mfumo + +## Masuala Yanayoendelea + +1. **Muundo tambarare** - Saraka moja inayokuwa na mifumo yote inafanya iwe ngumu kuelewa uhusiano. +2. **Mambo mchanganyikano** - Aina za msingi, vitu vya kikoa, na mikatiba ya API yote yamechanganywa. +3. **Majina yasiyo wazi** - Faili kama vile "object.py", "types.py", "topic.py" hazionyeshi wazi madhumuni yake. +4. **Hakuna tabaka wazi** - Haiwezekani kuona kwa urahisi nini kinategemea nini. + +## Muundo Ulio Pendekezwa + +``` +trustgraph-base/trustgraph/schema/ +├── __init__.py +├── core/ # Core primitive types used everywhere +│ ├── __init__.py +│ ├── primitives.py # Error, Value, Triple, Field, RowSchema +│ ├── metadata.py # Metadata record +│ └── topic.py # Topic utilities +│ +├── knowledge/ # Knowledge domain models and extraction +│ ├── __init__.py +│ ├── graph.py # EntityContext, EntityEmbeddings, Triples +│ ├── document.py # Document, TextDocument, Chunk +│ ├── knowledge.py # Knowledge extraction types +│ ├── embeddings.py # All embedding-related types (moved from multiple files) +│ └── nlp.py # Definition, Topic, Relationship, Fact types +│ +└── services/ # Service request/response contracts + ├── __init__.py + ├── llm.py # TextCompletion, Embeddings, Tool requests/responses + ├── retrieval.py # GraphRAG, DocumentRAG queries/responses + ├── query.py # GraphEmbeddingsRequest/Response, DocumentEmbeddingsRequest/Response + ├── agent.py # Agent requests/responses + ├── flow.py # Flow requests/responses + ├── prompt.py # Prompt service requests/responses + ├── config.py # Configuration service + ├── library.py # Librarian service + └── lookup.py # Lookup service +``` + +## Mabadiliko Muhimu + +1. **Mpangilio wa kimfumo** - Tofauti wazi kati ya aina kuu, modeli za maarifa, na mikatiba ya huduma. +2. **Majina bora zaidi**: + `types.py` → `core/primitives.py` (lengo lililoboreshwa) + `object.py` → Kugawanywa katika faili zinazofaa kulingana na yaliyomo halisi. + `documents.py` → `knowledge/document.py` (moja, thabiti) + `models.py` → `services/llm.py` (wazi zaidi ni aina gani ya modeli) + `prompt.py` → Kugawanywa: sehemu za huduma hadi `services/prompt.py`, aina za data hadi `knowledge/nlp.py` + +3. **Punguzo la mantiki**: + Aina zote za kuingiza zimeunganishwa katika `knowledge/embeddings.py` + Mikatiba yote ya huduma inayohusiana na LLM iko katika `services/llm.py` + Tofauti wazi ya jozi za ombi/jibu katika saraka ya huduma. + Aina za utoaji wa maarifa zimepangwa pamoja na modeli zingine za uwanja wa maarifa. + +4. **Ufafanuzi wa utegemezi**: + Aina kuu hazina utegemezi wowote. + Modeli za maarifa hutegemea tu aina kuu. + Mikatiba ya huduma inaweza kutegemea aina kuu na modeli za maarifa. + +## Faida za Uhamisho + +1. **Uramaji rahisi** - Wasanidi programu wanaweza kupata haraka kile wanachohitaji. +2. **Uunganishaji bora zaidi** - Mipaka wazi kati ya masuala tofauti. +3. **Uingizaji rahisi zaidi** - Njia za uingizaji ambazo ni za angavu zaidi. +4. **Inaweza kudumu kwa muda mrefu** - Rahisi kuongeza aina mpya za maarifa au huduma bila kusumbua. + +## Mfano wa Mabadiliko ya Uingizaji + +```python +# Before +from trustgraph.schema import Error, Triple, GraphEmbeddings, TextCompletionRequest + +# After +from trustgraph.schema.core import Error, Triple +from trustgraph.schema.knowledge import GraphEmbeddings +from trustgraph.schema.services import TextCompletionRequest +``` + +## Maelezo ya Utendaji + +1. Hakikisha utangamano wa zamani kwa kudumisha uingizaji wa faili katika sehemu kuu `__init__.py` +2. Hamisha faili hatua kwa hatua, na usasishe uingizaji wa faili kama inavyohitajika +3. Fikiria kuongeza `legacy.py` ambayo huingiza kila kitu kwa kipindi cha mpito +4. Sasisha nyaraka ili kuonyesha muundo mpya + + + +[{"id": "1", "content": "Fanyia uchunguzi muundo wa sasa wa saraka ya schema", "status": "imekamilika", "priority": "juu"}, {"id": "2", "content": "Changanua faili za schema na madhumuni yao", "status": "imekamilika", "priority": "juu"}, {"id": "3", "content": "Pendekeza jina na muundo uliobora", "status": "imekamilika", "priority": "juu"}] \ No newline at end of file diff --git a/docs/tech-specs/schema-refactoring-proposal.tr.md b/docs/tech-specs/schema-refactoring-proposal.tr.md new file mode 100644 index 00000000..353ee40a --- /dev/null +++ b/docs/tech-specs/schema-refactoring-proposal.tr.md @@ -0,0 +1,91 @@ +# Şema Dizini Yeniden Düzenleme Önerisi + +## Mevcut Sorunlar + +1. **Düz yapı** - Tüm şemaların tek bir dizinde olması, ilişkileri anlamayı zorlaştırıyor. +2. **Karışık konular** - Temel tipler, alan nesneleri ve API sözleşmeleri bir arada bulunuyor. +3. **Belirsiz adlandırma** - "object.py", "types.py", "topic.py" gibi dosyalar, amaçlarını açıkça belirtmiyor. +4. **Açık katmanlama yok** - Neyin neye bağlı olduğunu kolayca görmek mümkün değil. + +## Önerilen Yapı + +``` +trustgraph-base/trustgraph/schema/ +├── __init__.py +├── core/ # Core primitive types used everywhere +│ ├── __init__.py +│ ├── primitives.py # Error, Value, Triple, Field, RowSchema +│ ├── metadata.py # Metadata record +│ └── topic.py # Topic utilities +│ +├── knowledge/ # Knowledge domain models and extraction +│ ├── __init__.py +│ ├── graph.py # EntityContext, EntityEmbeddings, Triples +│ ├── document.py # Document, TextDocument, Chunk +│ ├── knowledge.py # Knowledge extraction types +│ ├── embeddings.py # All embedding-related types (moved from multiple files) +│ └── nlp.py # Definition, Topic, Relationship, Fact types +│ +└── services/ # Service request/response contracts + ├── __init__.py + ├── llm.py # TextCompletion, Embeddings, Tool requests/responses + ├── retrieval.py # GraphRAG, DocumentRAG queries/responses + ├── query.py # GraphEmbeddingsRequest/Response, DocumentEmbeddingsRequest/Response + ├── agent.py # Agent requests/responses + ├── flow.py # Flow requests/responses + ├── prompt.py # Prompt service requests/responses + ├── config.py # Configuration service + ├── library.py # Librarian service + └── lookup.py # Lookup service +``` + +## Temel Değişiklikler + +1. **Hiyerarşik organizasyon** - Temel tipler, bilgi modelleri ve hizmet sözleşmeleri arasında net bir ayrım. +2. **Daha iyi adlandırma**: + `types.py` → `core/primitives.py` (daha açık amaç) + `object.py` → Gerçek içeriğe göre uygun dosyalara ayrım + `documents.py` → `knowledge/document.py` (tekil, tutarlı) + `models.py` → `services/llm.py` (hangi tür modeller olduğu daha açık) + `prompt.py` → Ayrım: hizmet kısımları `services/prompt.py`'e, veri tipleri `knowledge/nlp.py`'ye + +3. **Mantıksal gruplandırma**: + Tüm gömme türleri `knowledge/embeddings.py` içinde toplandı. + Tüm LLM ile ilgili hizmet sözleşmeleri `services/llm.py` içinde. + Hizmetler dizininde istek/yanıt çiftlerinin net bir şekilde ayrılması. + Bilgi çıkarma türleri, diğer bilgi alanı modelleriyle gruplandırıldı. + +4. **Bağımlılık netliği**: + Temel tiplerin hiçbir bağımlılığı yoktur. + Bilgi modelleri yalnızca temel bağımlılıklarına sahiptir. + Hizmet sözleşmeleri hem temel hem de bilgi modellerine bağımlı olabilir. + +## Geçiş Faydaları + +1. **Daha kolay gezinme** - Geliştiriciler ihtiyaç duyduklarını hızla bulabilir. +2. **Daha iyi modülerlik** - Farklı konular arasındaki sınırlar nettir. +3. **Daha basit içe aktarmalar** - Daha sezgisel içe aktarma yolları. +4. **Geleceğe yönelik** - Yeni bilgi türleri veya hizmetler eklemek, karmaşayı önleyecek şekilde kolaydır. + +## Örnek İçe Aktarma Değişiklikleri + +```python +# Before +from trustgraph.schema import Error, Triple, GraphEmbeddings, TextCompletionRequest + +# After +from trustgraph.schema.core import Error, Triple +from trustgraph.schema.knowledge import GraphEmbeddings +from trustgraph.schema.services import TextCompletionRequest +``` + +## Uygulama Notları + +1. Kök dizindeki `__init__.py` içindeki import'ları koruyarak geriye dönük uyumluluğu sağlayın. +2. Dosyaları kademeli olarak taşıyın ve gerektiğinde import'ları güncelleyin. +3. Geçiş dönemi için her şeyi import eden bir `legacy.py` eklemeyi düşünün. +4. Yeni yapıyı yansıtacak şekilde dokümantasyonu güncelleyin. + + + +[{"id": "1", "content": "Mevcut şema dizin yapısını inceleyin", "status": "tamamlandı", "priority": "yüksek"}, {"id": "2", "content": "Şema dosyalarını ve amaçlarını analiz edin", "status": "tamamlandı", "priority": "yüksek"}, {"id": "3", "content": "Geliştirilmiş adlandırma ve yapı önerin", "status": "tamamlandı", "priority": "yüksek"}] \ No newline at end of file diff --git a/docs/tech-specs/streaming-llm-responses.ar.md b/docs/tech-specs/streaming-llm-responses.ar.md new file mode 100644 index 00000000..4e41bd99 --- /dev/null +++ b/docs/tech-specs/streaming-llm-responses.ar.md @@ -0,0 +1,570 @@ +# المواصفات الفنية لخدمة بث استجابات نماذج اللغة الكبيرة (LLM) + +## نظرة عامة + +تصف هذه المواصفات تنفيذ دعم البث لاستجابات نماذج اللغة الكبيرة في TrustGraph. يتيح البث التسليم في الوقت الفعلي للرموز (tokens) أثناء إنتاجها بواسطة نموذج اللغة الكبيرة، بدلاً من الانتظار حتى اكتمال توليد الاستجابة. + +يدعم هذا التنفيذ حالات الاستخدام التالية: + + +1. **واجهات مستخدم في الوقت الفعلي**: بث الرموز إلى واجهة المستخدم أثناء إنشائها، مما يوفر ملاحظات مرئية فورية. + +2. **تقليل وقت ظهور الرمز الأول**: يرى المستخدمون الإخراج على الفور بدلاً من الانتظار حتى اكتمال التوليد. + +3. **التعامل مع الاستجابات الطويلة**: التعامل مع المخرجات الطويلة جدًا التي قد تتسبب خلاف ذلك في انتهاء المهلة أو تجاوز حدود الذاكرة. + +4. **التطبيقات التفاعلية**: تمكين واجهات الدردشة والوكلاء المستجيبة. + +## الأهداف + + +**التوافق مع الإصدارات السابقة**: تستمر العملاء الحاليون الذين لا يستخدمون البث في العمل دون تعديل. + + **تصميم واجهة برمجة تطبيقات (API) متسق**: يستخدم البث والواجهات غير المتدفقة نفس أنماط المخططات مع اختلافات قليلة. + + **مرونة مزود الخدمة**: دعم البث عند توفره، مع توفير آلية بديلة سلسة عند عدم توفره. + + **التطبيق المرحلي**: تطبيق تدريجي لتقليل المخاطر. + +**دعم شامل**: دعم البث من مزود نموذج اللغة الكبيرة إلى تطبيقات العميل عبر Pulsar و Gateway API و Python API. + +## الخلفية + +### البنية الحالية + + +تعمل عملية إكمال النص الحالية لنماذج اللغة الكبيرة على النحو التالي: + +1. يرسل العميل `TextCompletionRequest` مع حقول `system` و `prompt`. +2. تعالج خدمة نموذج اللغة الكبيرة الطلب وتنتظر اكتمال التوليد. +3. يتم إرجاع `TextCompletionResponse` واحد مع سلسلة `response` كاملة. + +المخطط الحالي (`trustgraph-base/trustgraph/schema/services/llm.py`): + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() +``` + +### القيود الحالية + +**زمن الوصول (Latency)**: يجب على المستخدمين الانتظار حتى اكتمال الإنشاء قبل رؤية أي نتيجة. +**خطر انتهاء المهلة (Timeout)**: قد تتجاوز عمليات الإنشاء الطويلة حدود انتهاء المهلة الخاصة بالعميل. +**تجربة مستخدم سيئة (Poor UX)**: عدم وجود أي ملاحظات أثناء الإنشاء يخلق انطباعًا بالبطء. +**استخدام الموارد (Resource Usage)**: يجب تخزين الاستجابات الكاملة في الذاكرة. + +تعالج هذه المواصفات هذه القيود من خلال تمكين التسليم التدريجي للاستجابة مع الحفاظ على التوافق الكامل مع الإصدارات السابقة. + + +## التصميم التقني + +### المرحلة الأولى: البنية التحتية + +تضع المرحلة الأولى الأساس للبث عن طريق تعديل المخططات وواجهات برمجة التطبيقات (APIs) وأدوات سطر الأوامر (CLI). + + +#### تغييرات المخططات + +##### مخطط LLM (`trustgraph-base/trustgraph/schema/services/llm.py`) + +**تغييرات الطلبات:** + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() # NEW: Default false for backward compatibility +``` + +`streaming`: عندما `true`، يتم طلب تسليم الاستجابة بتدفق. +الافتراضي: `false` (يتم الحفاظ على السلوك الحالي). + +**تغييرات في الاستجابة:** + +```python +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +`end_of_stream`: عندما `true`، يشير هذا إلى أن هذا هو الرد النهائي (أو الوحيد). +للطلبات غير المتدفقة: رد واحد مع `end_of_stream=true`. +للطلبات المتدفقة: ردود متعددة، جميعها مع `end_of_stream=false`. + باستثناء الرد النهائي. + +##### مخطط المطالبة (`trustgraph-base/trustgraph/schema/services/prompt.py`). + +خدمة المطالبة تغلف إكمال النص، وبالتالي فهي تعكس نفس النمط: + +**تغييرات الطلب:** + +```python +class PromptRequest(Record): + id = String() + terms = Map(String()) + streaming = Boolean() # NEW: Default false +``` + +**التغييرات في الاستجابة:** + +```python +class PromptResponse(Record): + error = Error() + text = String() + object = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +#### التغييرات في واجهة برمجة التطبيقات (API) الخاصة بالبوابة. + +يجب أن تعرض واجهة برمجة التطبيقات (API) الخاصة بالبوابة إمكانات البث لعملاء HTTP/WebSocket. + +**تحديثات واجهة برمجة التطبيقات (API) REST:** + +`POST /api/v1/text-completion`: قبول المعامل `streaming` في نص الطلب. +يعتمد سلوك الاستجابة على علامة البث: + `streaming=false`: استجابة JSON واحدة (السلوك الحالي). + `streaming=true`: تدفق أحداث من الخادم (SSE) أو رسائل WebSocket. + +**تنسيق الاستجابة (البث):** + +يتبع كل جزء مُبث نفس هيكل المخطط. +```json +{ + "response": "partial text...", + "end_of_stream": false, + "model": "model-name" +} +``` + +الجزء الأخير: +```json +{ + "response": "final text chunk", + "end_of_stream": true, + "in_token": 150, + "out_token": 500, + "model": "model-name" +} +``` + +#### تغييرات في واجهة برمجة التطبيقات (API) الخاصة بـ Python + +يجب أن تدعم واجهة برمجة التطبيقات (API) الخاصة بعميل Python كلاً من الأوضاع المتدفقة وغير المتدفقة +مع الحفاظ على التوافق مع الإصدارات السابقة. + +**تحديثات لـ LlmClient** (`trustgraph-base/trustgraph/clients/llm_client.py`): + +```python +class LlmClient(BaseClient): + def request(self, system, prompt, timeout=300, streaming=False): + """ + Non-streaming request (backward compatible). + Returns complete response string. + """ + # Existing behavior when streaming=False + + async def request_stream(self, system, prompt, timeout=300): + """ + Streaming request. + Yields response chunks as they arrive. + """ + # New async generator method +``` + +**تحديثات PromptClient** (`trustgraph-base/trustgraph/base/prompt_client.py`): + +نمط مشابه مع المعامل `streaming` وإصدار مولد غير متزامن. + +#### تغييرات في أداة سطر الأوامر + +**tg-invoke-llm** (`trustgraph-cli/trustgraph/cli/invoke_llm.py`): + +``` +tg-invoke-llm [system] [prompt] [--no-streaming] [-u URL] [-f flow-id] +``` + +تفعيل البث افتراضيًا لتحسين تجربة المستخدم التفاعلية. +العلم `--no-streaming` يعطل البث. +عند تفعيل البث: إخراج الرموز إلى الإخراج القياسي (stdout) فور وصولها. +عند عدم تفعيل البث: الانتظار حتى اكتمال الاستجابة، ثم إخراجها. + +**tg-invoke-prompt** (`trustgraph-cli/trustgraph/cli/invoke_prompt.py`): + +``` +tg-invoke-prompt [template-id] [var=value...] [--no-streaming] [-u URL] [-f flow-id] +``` + +نفس النمط مثل `tg-invoke-llm`. + +#### تغييرات في الفئة الأساسية لخدمة نماذج اللغة الكبيرة (LLM). + +**LlmService** (`trustgraph-base/trustgraph/base/llm_service.py`): + +```python +class LlmService(FlowProcessor): + async def on_request(self, msg, consumer, flow): + request = msg.value() + streaming = getattr(request, 'streaming', False) + + if streaming and self.supports_streaming(): + async for chunk in self.generate_content_stream(...): + await self.send_response(chunk, end_of_stream=False) + await self.send_response(final_chunk, end_of_stream=True) + else: + response = await self.generate_content(...) + await self.send_response(response, end_of_stream=True) + + def supports_streaming(self): + """Override in subclass to indicate streaming support.""" + return False + + async def generate_content_stream(self, system, prompt, model, temperature): + """Override in subclass to implement streaming.""" + raise NotImplementedError() +``` + +-- + +### المرحلة الثانية: إثبات المفهوم لـ VertexAI + +تنفذ المرحلة الثانية البث في مزود واحد (VertexAI) للتحقق من صحة +البنية التحتية وتمكين الاختبار الشامل. + +#### تنفيذ VertexAI + +**الوحدة:** `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` + +**التغييرات:** + +1. تجاوز `supports_streaming()` لإرجاع `True` +2. تنفيذ مُولّد غير متزامن `generate_content_stream()` +3. التعامل مع نماذج Gemini و Claude (عبر واجهة برمجة تطبيقات VertexAI Anthropic) + +**البث باستخدام Gemini:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + model_instance = self.get_model(model, temperature) + response = model_instance.generate_content( + [system, prompt], + stream=True # Enable streaming + ) + for chunk in response: + yield LlmChunk( + text=chunk.text, + in_token=None, # Available only in final chunk + out_token=None, + ) + # Final chunk includes token counts from response.usage_metadata +``` + +**كلود (عبر VertexAI من شركة Anthropic) - البث:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + with self.anthropic_client.messages.stream(...) as stream: + for text in stream.text_stream: + yield LlmChunk(text=text) + # Token counts from stream.get_final_message() +``` + +#### الاختبار + +اختبارات الوحدة لتجميع الاستجابات المتدفقة. +اختبارات التكامل مع VertexAI (Gemini و Claude). +اختبارات شاملة: سطر الأوامر -> البوابة -> Pulsar -> VertexAI -> العودة. +اختبارات التوافق مع الإصدارات السابقة: لا تزال طلبات عدم التدفق تعمل. + +-- + +### المرحلة الثالثة: جميع مزودي نماذج اللغة الكبيرة + +تمتد المرحلة الثالثة لدعم التدفق إلى جميع مزودي نماذج اللغة الكبيرة في النظام. + +#### حالة تنفيذ المزود + +يجب على كل مزود إما: +1. **دعم كامل للتدفق**: تنفيذ `generate_content_stream()` +2. **وضع التوافق**: التعامل مع علامة `end_of_stream` بشكل صحيح + (إرجاع استجابة واحدة مع `end_of_stream=true`) + +| المزود | الحزمة | دعم التدفق | +|----------|---------|-------------------| +| OpenAI | trustgraph-flow | كامل (واجهة برمجة تطبيقات تدفق أصلية) | +| Claude/Anthropic | trustgraph-flow | كامل (واجهة برمجة تطبيقات تدفق أصلية) | +| Ollama | trustgraph-flow | كامل (واجهة برمجة تطبيقات تدفق أصلية) | +| Cohere | trustgraph-flow | كامل (واجهة برمجة تطبيقات تدفق أصلية) | +| Mistral | trustgraph-flow | كامل (واجهة برمجة تطبيقات تدفق أصلية) | +| Azure OpenAI | trustgraph-flow | كامل (واجهة برمجة تطبيقات تدفق أصلية) | +| Google AI Studio | trustgraph-flow | كامل (واجهة برمجة تطبيقات تدفق أصلية) | +| VertexAI | trustgraph-vertexai | كامل (المرحلة الثانية) | +| Bedrock | trustgraph-bedrock | كامل (واجهة برمجة تطبيقات تدفق أصلية) | +| LM Studio | trustgraph-flow | كامل (متوافق مع OpenAI) | +| LlamaFile | trustgraph-flow | كامل (متوافق مع OpenAI) | +| vLLM | trustgraph-flow | كامل (متوافق مع OpenAI) | +| TGI | trustgraph-flow | قيد التحديد | +| Azure | trustgraph-flow | قيد التحديد | + +#### نمط التنفيذ + +بالنسبة لمزودي نماذج اللغة الكبيرة المتوافقين مع OpenAI (OpenAI، LM Studio، LlamaFile، vLLM): + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + response = await self.client.chat.completions.create( + model=model, + messages=[ + {"role": "system", "content": system}, + {"role": "user", "content": prompt} + ], + temperature=temperature, + stream=True + ) + async for chunk in response: + if chunk.choices[0].delta.content: + yield LlmChunk(text=chunk.choices[0].delta.content) +``` + +-- + +### المرحلة الرابعة: واجهة برمجة التطبيقات (API) للوكيل + +المرحلة الرابعة توسع البث ليشمل واجهة برمجة التطبيقات (API) للوكيل. هذا أكثر تعقيدًا لأن +واجهة برمجة التطبيقات (API) للوكيل هي بالفعل متعددة الرسائل بطبيعتها (فكرة ← إجراء ← ملاحظة +← تكرار ← إجابة نهائية). + +#### مخطط الوكيل الحالي + +```python +class AgentStep(Record): + thought = String() + action = String() + arguments = Map(String()) + observation = String() + user = String() + +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + +class AgentResponse(Record): + answer = String() + error = Error() + thought = String() + observation = String() +``` + +#### التغييرات المقترحة في مخطط الوكيل. + +**طلب التغييرات:** + +```python +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + streaming = Boolean() # NEW: Default false +``` + +**التغييرات في الاستجابة:** + +ينتج الوكيل أنواعًا متعددة من المخرجات خلال دورة التفكير الخاصة به: +الأفكار (التفكير) +الإجراءات (استدعاءات الأدوات) +الملاحظات (نتائج الأدوات) +الإجابة (الاستجابة النهائية) +الأخطاء + +نظرًا لأن `chunk_type` يحدد نوع المحتوى الذي يتم إرساله، يمكن دمج الحقول المنفصلة +`answer`، `error`، `thought`، و `observation` في +حقل واحد وهو `content`: + +```python +class AgentResponse(Record): + chunk_type = String() # "thought", "action", "observation", "answer", "error" + content = String() # The actual content (interpretation depends on chunk_type) + end_of_message = Boolean() # Current thought/action/observation/answer is complete + end_of_dialog = Boolean() # Entire agent dialog is complete +``` + +**المعاني الدلالية للحقول:** + +`chunk_type`: يشير إلى نوع المحتوى الموجود في حقل `content`. + `"thought"`: تفكير/استنتاج الوكيل. + `"action"`: الأداة/الإجراء المستخدم. + `"observation"`: النتيجة من تنفيذ الأداة. + `"answer"`: الإجابة النهائية لسؤال المستخدم. + `"error"`: رسالة الخطأ. + +`content`: المحتوى المتدفق الفعلي، والذي يتم تفسيره بناءً على `chunk_type`. + +`end_of_message`: عندما `true`، يكون نوع الجزء الحالي مكتملًا. + مثال: تم إرسال جميع الرموز الخاصة بالتفكير الحالي. + يسمح للعملاء بمعرفة متى ينتقلون إلى المرحلة التالية. + +`end_of_dialog`: عندما `true`، يكون التفاعل بأكمله مع الوكيل قد اكتمل. + هذه هي الرسالة الأخيرة في التدفق. + +#### سلوك التدفق الخاص بالوكيل + +عندما `streaming=true`: + +1. **تدفق الأفكار:** + أجزاء متعددة مع `chunk_type="thought"`، `end_of_message=false`. + الجزء الأخير من التفكير يحتوي على `end_of_message=true`. +2. **إشعار الإجراء:** + جزء واحد مع `chunk_type="action"`، `end_of_message=true`. +3. **الملاحظة:** + جزء (أجزاء) مع `chunk_type="observation"`، والجزء الأخير يحتوي على `end_of_message=true`. +4. **كرر** الخطوات من 1 إلى 3 أثناء قيام الوكيل بالتفكير. +5. **الإجابة النهائية:** + `chunk_type="answer"` مع الإجابة النهائية في `content`. + الجزء الأخير يحتوي على `end_of_message=true`، `end_of_dialog=true`. + +**تسلسل التدفق النموذجي:** + +``` +{chunk_type: "thought", content: "I need to", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " search for...", end_of_message: true, end_of_dialog: false} +{chunk_type: "action", content: "search", end_of_message: true, end_of_dialog: false} +{chunk_type: "observation", content: "Found: ...", end_of_message: true, end_of_dialog: false} +{chunk_type: "thought", content: "Based on this", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " I can answer...", end_of_message: true, end_of_dialog: false} +{chunk_type: "answer", content: "The answer is...", end_of_message: true, end_of_dialog: true} +``` + +عندما `streaming=false`: +الحفاظ على السلوك الحالي +استجابة واحدة مع إجابة كاملة +`end_of_message=true`، `end_of_dialog=true` + +#### بوابة وواجهة برمجة تطبيقات بايثون + +البوابة: نقطة نهاية SSE/WebSocket جديدة لبث الوكيل +واجهة برمجة تطبيقات بايثون: طريقة مُولِّد غير متزامن جديدة `agent_stream()` + +-- + +## اعتبارات الأمان + +**لا توجد نقاط ضعف جديدة**: يستخدم البث نفس آليات المصادقة/التفويض +**تحديد المعدل**: تطبيق حدود معدل لكل رمز أو لكل جزء إذا لزم الأمر +**معالجة الاتصال**: إنهاء التدفقات بشكل صحيح عند قطع اتصال العميل +**إدارة المهلة الزمنية**: تحتاج طلبات البث إلى معالجة مناسبة للمهلة الزمنية + +## اعتبارات الأداء + +**الذاكرة**: يقلل البث من استخدام الذاكرة القصوى (بدون تخزين مؤقت للاستجابة الكاملة) +**زمن الوصول**: تم تقليل زمن الوصول إلى الرمز الأول بشكل كبير +**نفقات الاتصال**: تحتوي اتصالات SSE/WebSocket على نفقات صيانة الاتصال +**إنتاجية بولسار**: رسائل صغيرة متعددة مقابل رسالة كبيرة واحدة + مقايضة + +## استراتيجية الاختبار + +### اختبارات الوحدة +تسلسل/إلغاء تسلسل المخطط مع الحقول الجديدة +التوافق مع الإصدارات السابقة (تستخدم الحقول المفقودة القيم الافتراضية) +منطق تجميع الأجزاء + +### اختبارات التكامل +تطبيق كل مزود LLM لتنفيذ البث +نقاط نهاية البث لواجهة برمجة تطبيقات البوابة +طرق البث لعميل بايثون + +### اختبارات شاملة +إخراج أداة سطر الأوامر (CLI) للبث +التدفق الكامل: العميل → البوابة → بولسار → LLM → العودة +أحمال عمل مختلطة (بث/غير بث) + +### اختبارات التوافق مع الإصدارات السابقة +تعمل العملاء الحاليون دون تعديل +تتصرف طلبات عدم البث بشكل مماثل + +## خطة الترحيل + +### المرحلة الأولى: البنية التحتية +نشر تغييرات المخطط (متوافقة مع الإصدارات السابقة) +نشر تحديثات واجهة برمجة تطبيقات البوابة +نشر تحديثات واجهة برمجة تطبيقات بايثون +إصدار تحديثات أداة سطر الأوامر (CLI) + +### المرحلة الثانية: VertexAI +نشر تطبيق VertexAI للبث. +التحقق من صحته باستخدام أحمال العمل التجريبية. + +### المرحلة الثالثة: جميع المزودين. +نشر تحديثات المزودين بشكل تدريجي. +مراقبة المشكلات. + +### المرحلة الرابعة: واجهة برمجة تطبيقات الوكيل. +نشر تغييرات مخطط الوكيل. +نشر تطبيق البث للوكيل. +تحديث الوثائق. + +## الجدول الزمني. + +| المرحلة | الوصف | التبعيات | +|-------|-------------|--------------| +| المرحلة الأولى | البنية التحتية | لا يوجد | +| المرحلة الثانية | نموذج VertexAI الأولي | المرحلة الأولى | +| المرحلة الثالثة | جميع المزودين | المرحلة الثانية | +| المرحلة الرابعة | واجهة برمجة تطبيقات الوكيل | المرحلة الثالثة | + +## قرارات التصميم. + +تمت معالجة الأسئلة التالية أثناء التحديد: + +1. **عدد الرموز في البث**: عدد الرموز هو الفروق، وليس المجاميع التراكمية. + يمكن للمستهلكين جمعها إذا لزم الأمر. يتطابق هذا مع كيفية قيام معظم المزودين بالإبلاغ + عن الاستخدام ويبسط التنفيذ. + +2. **معالجة الأخطاء في التدفقات**: في حالة حدوث خطأ، يتم ملء الحقل `error` + ولا يلزم وجود أي حقول أخرى. الخطأ هو دائمًا آخر رسالة - لا يُسمح بإرسال أو استقبال رسائل لاحقة بعد ذلك. + أو توقعها. + خطأ. بالنسبة لتدفقات نماذج اللغة الكبيرة/التعليمات، `end_of_stream=true`. بالنسبة لتدفقات الوكلاء، + `chunk_type="error"` مع `end_of_dialog=true`. + +3. **استعادة الاستجابات الجزئية**: بروتوكول المراسلة (Pulsار) يتميز بالمرونة، + لذلك لا توجد حاجة إلى إعادة محاولة الرسائل على مستوى الرسالة. إذا فقد العميل تتبع التدفق + أو انقطع الاتصال، فيجب عليه إعادة محاولة الطلب بأكمله من البداية. + +4. **خدمة الاستجابة السريعة المتدفقة**: تدعم البث فقط للنصوص (`text`). + الاستجابات، وليس الاستجابات المنظمة (`object`). تعرف خدمة الاستجابة السريعة في + البداية ما إذا كانت المخرجات ستكون بتنسيق JSON أو نص بناءً على قالب + الاستعلام. إذا تم إجراء طلب بث لاستعلام ينتج عنه مخرجات بتنسيق JSON، فإن + يجب أن يقوم الخدمة إما: + بإرجاع كائن JSON كامل في استجابة واحدة باستخدام `end_of_stream=true`، أو + برفض طلب البث مع وجود خطأ. + +## الأسئلة المفتوحة + +لا يوجد أسئلة في الوقت الحالي. + +## المراجع + +مخطط نموذج اللغة الكبير الحالي: `trustgraph-base/trustgraph/schema/services/llm.py` +مخطط المطالبة الحالي: `trustgraph-base/trustgraph/schema/services/prompt.py` +مخطط الوكيل الحالي: `trustgraph-base/trustgraph/schema/services/agent.py` +الخدمة الأساسية لنموذج اللغة الكبير: `trustgraph-base/trustgraph/base/llm_service.py` +مزود VertexAI: `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` +واجهة برمجة التطبيقات (API) للواجهة: `trustgraph-base/trustgraph/api/` +أدوات سطر الأوامر (CLI): `trustgraph-cli/trustgraph/cli/` diff --git a/docs/tech-specs/streaming-llm-responses.es.md b/docs/tech-specs/streaming-llm-responses.es.md new file mode 100644 index 00000000..c267399b --- /dev/null +++ b/docs/tech-specs/streaming-llm-responses.es.md @@ -0,0 +1,570 @@ +# Especificación Técnica de Respuestas de LLM en Streaming + +## Resumen + +Esta especificación describe la implementación del soporte de streaming para respuestas de LLM +en TrustGraph. El streaming permite la entrega en tiempo real de tokens generados +a medida que son producidos por el LLM, en lugar de esperar a que se complete +la generación de la respuesta. + +Esta implementación admite los siguientes casos de uso: + +1. **Interfaces de Usuario en Tiempo Real**: Transmite tokens a la interfaz de usuario a medida que se generan, + proporcionando retroalimentación visual inmediata. +2. **Reducción del Tiempo Hasta el Primer Token**: Los usuarios ven la salida inmediatamente + en lugar de esperar a que se complete la generación. +3. **Manejo de Respuestas Largas**: Maneja salidas muy largas que de otro modo + podrían provocar un tiempo de espera o exceder los límites de memoria. +4. **Aplicaciones Interactivas**: Permite interfaces de chat y agentes receptivas. + +## Objetivos + +**Compatibilidad con Versiones Anteriores**: Los clientes existentes que no utilizan streaming continúan funcionando + sin modificaciones. +**Diseño de API Consistente**: El streaming y el no streaming utilizan los mismos patrones de esquema + con una divergencia mínima. +**Flexibilidad del Proveedor**: Soporte de streaming cuando esté disponible, con una + alternativa gradual cuando no esté disponible. +**Implementación por Fases**: Implementación incremental para reducir el riesgo. +**Soporte de Extremo a Extremo**: Streaming desde el proveedor de LLM hasta las aplicaciones cliente + a través de Pulsar, la API de Gateway y la API de Python. + +## Antecedentes + +### Arquitectura Actual + +El flujo actual de finalización de texto de LLM funciona de la siguiente manera: + +1. El cliente envía `TextCompletionRequest` con los campos `system` y `prompt`. +2. El servicio de LLM procesa la solicitud y espera a que se complete la generación. +3. Se devuelve un único `TextCompletionResponse` con la cadena `response` completa. + +Esquema actual (`trustgraph-base/trustgraph/schema/services/llm.py`): + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() +``` + +### Limitaciones actuales + +**Latencia**: Los usuarios deben esperar a que se complete la generación antes de ver cualquier resultado. +**Riesgo de tiempo de espera**: Las generaciones largas pueden exceder los umbrales de tiempo de espera del cliente. +**Mala experiencia de usuario**: La falta de retroalimentación durante la generación crea la percepción de lentitud. +**Uso de recursos**: Las respuestas completas deben almacenarse en búfer en la memoria. + +Esta especificación aborda estas limitaciones al permitir la entrega incremental de respuestas, manteniendo la compatibilidad total con versiones anteriores. + + +## Diseño técnico + +### Fase 1: Infraestructura + +La Fase 1 establece la base para la transmisión mediante la modificación de esquemas, API y herramientas de línea de comandos. + + +#### Cambios en el esquema + +##### Esquema de LLM (`trustgraph-base/trustgraph/schema/services/llm.py`) + +**Cambios en la solicitud:** + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() # NEW: Default false for backward compatibility +``` + +`streaming`: Cuando `true`, solicita la entrega de la respuesta en modo de transmisión. +Predeterminado: `false` (el comportamiento existente se mantiene). + +**Cambios en la respuesta:** + +```python +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +`end_of_stream`: Cuando `true`, indica que esta es la respuesta final (o única). +Para solicitudes no de transmisión: Respuesta única con `end_of_stream=true`. +Para solicitudes de transmisión: Múltiples respuestas, todas con `end_of_stream=false` + excepto la última. + +##### Esquema de la solicitud (`trustgraph-base/trustgraph/schema/services/prompt.py`) + +El servicio de solicitud envuelve la finalización de texto, por lo que refleja el mismo patrón: + +**Cambios en la solicitud:** + +```python +class PromptRequest(Record): + id = String() + terms = Map(String()) + streaming = Boolean() # NEW: Default false +``` + +**Cambios en la respuesta:** + +```python +class PromptResponse(Record): + error = Error() + text = String() + object = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +#### Cambios en la API de Gateway + +La API de Gateway debe exponer capacidades de transmisión a clientes HTTP/WebSocket. + +**Actualizaciones de la API REST:** + +`POST /api/v1/text-completion`: Aceptar el parámetro `streaming` en el cuerpo de la solicitud. +El comportamiento de la respuesta depende de la bandera de transmisión: + `streaming=false`: Respuesta JSON única (comportamiento actual). + `streaming=true`: Flujo de eventos enviados por el servidor (SSE) o mensajes WebSocket. + +**Formato de respuesta (transmisión):** + +Cada fragmento transmitido sigue la misma estructura de esquema: +```json +{ + "response": "partial text...", + "end_of_stream": false, + "model": "model-name" +} +``` + +Fragmento final: +```json +{ + "response": "final text chunk", + "end_of_stream": true, + "in_token": 150, + "out_token": 500, + "model": "model-name" +} +``` + +#### Cambios en la API de Python + +La API del cliente de Python debe soportar tanto modos de transmisión como no de transmisión +manteniendo la compatibilidad con versiones anteriores. + +**Actualizaciones de LlmClient** (`trustgraph-base/trustgraph/clients/llm_client.py`): + +```python +class LlmClient(BaseClient): + def request(self, system, prompt, timeout=300, streaming=False): + """ + Non-streaming request (backward compatible). + Returns complete response string. + """ + # Existing behavior when streaming=False + + async def request_stream(self, system, prompt, timeout=300): + """ + Streaming request. + Yields response chunks as they arrive. + """ + # New async generator method +``` + +**Actualizaciones de PromptClient** (`trustgraph-base/trustgraph/base/prompt_client.py`): + +Patrón similar con el parámetro `streaming` y la variante de generador asíncrono. + +#### Cambios en la herramienta de línea de comandos + +**tg-invoke-llm** (`trustgraph-cli/trustgraph/cli/invoke_llm.py`): + +``` +tg-invoke-llm [system] [prompt] [--no-streaming] [-u URL] [-f flow-id] +``` + +La transmisión está habilitada de forma predeterminada para una mejor experiencia de usuario interactiva. +La opción `--no-streaming` desactiva la transmisión. +Cuando la transmisión está habilitada: envía los tokens a la salida estándar a medida que llegan. +Cuando la transmisión no está habilitada: espera la respuesta completa y luego la muestra. + +**tg-invoke-prompt** (`trustgraph-cli/trustgraph/cli/invoke_prompt.py`): + +``` +tg-invoke-prompt [template-id] [var=value...] [--no-streaming] [-u URL] [-f flow-id] +``` + +El mismo patrón que `tg-invoke-llm`. + +#### Cambios en la Clase Base del Servicio LLM + +**LlmService** (`trustgraph-base/trustgraph/base/llm_service.py`): + +```python +class LlmService(FlowProcessor): + async def on_request(self, msg, consumer, flow): + request = msg.value() + streaming = getattr(request, 'streaming', False) + + if streaming and self.supports_streaming(): + async for chunk in self.generate_content_stream(...): + await self.send_response(chunk, end_of_stream=False) + await self.send_response(final_chunk, end_of_stream=True) + else: + response = await self.generate_content(...) + await self.send_response(response, end_of_stream=True) + + def supports_streaming(self): + """Override in subclass to indicate streaming support.""" + return False + + async def generate_content_stream(self, system, prompt, model, temperature): + """Override in subclass to implement streaming.""" + raise NotImplementedError() +``` + +-- + +### Fase 2: Prueba de concepto de VertexAI + +La Fase 2 implementa el streaming en un único proveedor (VertexAI) para validar la +infraestructura y habilitar pruebas de extremo a extremo. + +#### Implementación de VertexAI + +**Módulo:** `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` + +**Cambios:** + +1. Sobreescribir `supports_streaming()` para devolver `True` +2. Implementar generador asíncrono `generate_content_stream()` +3. Manejar tanto los modelos Gemini como Claude (a través de la API de VertexAI Anthropic) + +**Streaming de Gemini:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + model_instance = self.get_model(model, temperature) + response = model_instance.generate_content( + [system, prompt], + stream=True # Enable streaming + ) + for chunk in response: + yield LlmChunk( + text=chunk.text, + in_token=None, # Available only in final chunk + out_token=None, + ) + # Final chunk includes token counts from response.usage_metadata +``` + +**Claude (a través de VertexAI Anthropic) en modo de transmisión:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + with self.anthropic_client.messages.stream(...) as stream: + for text in stream.text_stream: + yield LlmChunk(text=text) + # Token counts from stream.get_final_message() +``` + +#### Pruebas + +Pruebas unitarias para el ensamblaje de respuestas en streaming. +Pruebas de integración con VertexAI (Gemini y Claude). +Pruebas de extremo a extremo: CLI -> Gateway -> Pulsar -> VertexAI -> back. +Pruebas de compatibilidad con versiones anteriores: Las solicitudes no en streaming aún funcionan. + +-- + +### Fase 3: Todos los proveedores de LLM + +La fase 3 extiende el soporte de streaming a todos los proveedores de LLM en el sistema. + +#### Estado de implementación del proveedor + +Cada proveedor debe: +1. **Soporte completo de streaming**: Implementar `generate_content_stream()` +2. **Modo de compatibilidad**: Manejar la bandera `end_of_stream` correctamente + (devolver una única respuesta con `end_of_stream=true`) + +| Proveedor | Paquete | Soporte de streaming | +|----------|---------|-------------------| +| OpenAI | trustgraph-flow | Completo (API de streaming nativo) | +| Claude/Anthropic | trustgraph-flow | Completo (API de streaming nativo) | +| Ollama | trustgraph-flow | Completo (API de streaming nativo) | +| Cohere | trustgraph-flow | Completo (API de streaming nativo) | +| Mistral | trustgraph-flow | Completo (API de streaming nativo) | +| Azure OpenAI | trustgraph-flow | Completo (API de streaming nativo) | +| Google AI Studio | trustgraph-flow | Completo (API de streaming nativo) | +| VertexAI | trustgraph-vertexai | Completo (Fase 2) | +| Bedrock | trustgraph-bedrock | Completo (API de streaming nativo) | +| LM Studio | trustgraph-flow | Completo (compatible con OpenAI) | +| LlamaFile | trustgraph-flow | Completo (compatible con OpenAI) | +| vLLM | trustgraph-flow | Completo (compatible con OpenAI) | +| TGI | trustgraph-flow | Por determinar | +| Azure | trustgraph-flow | Por determinar | + +#### Patrón de implementación + +Para proveedores compatibles con OpenAI (OpenAI, LM Studio, LlamaFile, vLLM): + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + response = await self.client.chat.completions.create( + model=model, + messages=[ + {"role": "system", "content": system}, + {"role": "user", "content": prompt} + ], + temperature=temperature, + stream=True + ) + async for chunk in response: + if chunk.choices[0].delta.content: + yield LlmChunk(text=chunk.choices[0].delta.content) +``` + +-- + +### Fase 4: API del Agente + +La Fase 4 extiende la transmisión a la API del Agente. Esto es más complejo porque +la API del Agente ya es inherentemente multi-mensaje (pensamiento → acción → observación +→ repetir → respuesta final). + +#### Esquema actual del Agente + +```python +class AgentStep(Record): + thought = String() + action = String() + arguments = Map(String()) + observation = String() + user = String() + +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + +class AgentResponse(Record): + answer = String() + error = Error() + thought = String() + observation = String() +``` + +#### Cambios Propuestos al Esquema del Agente + +**Solicitar Cambios:** + +```python +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + streaming = Boolean() # NEW: Default false +``` + +**Cambios en la respuesta:** + +El agente produce múltiples tipos de salida durante su ciclo de razonamiento: +Pensamientos (razonamiento) +Acciones (llamadas a herramientas) +Observaciones (resultados de las herramientas) +Respuesta (respuesta final) +Errores + +Dado que `chunk_type` identifica qué tipo de contenido se está enviando, los campos separados +`answer`, `error`, `thought` y `observation` se pueden combinar en +un único campo `content`: + +```python +class AgentResponse(Record): + chunk_type = String() # "thought", "action", "observation", "answer", "error" + content = String() # The actual content (interpretation depends on chunk_type) + end_of_message = Boolean() # Current thought/action/observation/answer is complete + end_of_dialog = Boolean() # Entire agent dialog is complete +``` + +**Semántica de los campos:** + +`chunk_type`: Indica qué tipo de contenido se encuentra en el campo `content` + `"thought"`: Razonamiento/pensamiento del agente + `"action"`: Herramienta/acción que se está invocando + `"observation"`: Resultado de la ejecución de la herramienta + `"answer"`: Respuesta final a la pregunta del usuario + `"error"`: Mensaje de error + +`content`: El contenido transmitido real, interpretado según `chunk_type` + +`end_of_message`: Cuando `true`, el tipo de fragmento actual está completo + Ejemplo: Todos los tokens para el pensamiento actual han sido enviados + Permite a los clientes saber cuándo pasar a la siguiente etapa + +`end_of_dialog`: Cuando `true`, la interacción completa del agente ha finalizado + Este es el mensaje final en la transmisión + +#### Comportamiento de la transmisión del agente + +Cuando `streaming=true`: + +1. **Transmisión de pensamientos:** + Múltiples fragmentos con `chunk_type="thought"`, `end_of_message=false` + El fragmento final del pensamiento tiene `end_of_message=true` +2. **Notificación de acción:** + Un solo fragmento con `chunk_type="action"`, `end_of_message=true` +3. **Observación:** + Fragmento(s) con `chunk_type="observation"`, el final tiene `end_of_message=true` +4. **Repetir** los pasos 1-3 mientras el agente razona +5. **Respuesta final:** + `chunk_type="answer"` con la respuesta final en `content` + El último fragmento tiene `end_of_message=true`, `end_of_dialog=true` + +**Secuencia de ejemplo de la transmisión:** + +``` +{chunk_type: "thought", content: "I need to", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " search for...", end_of_message: true, end_of_dialog: false} +{chunk_type: "action", content: "search", end_of_message: true, end_of_dialog: false} +{chunk_type: "observation", content: "Found: ...", end_of_message: true, end_of_dialog: false} +{chunk_type: "thought", content: "Based on this", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " I can answer...", end_of_message: true, end_of_dialog: false} +{chunk_type: "answer", content: "The answer is...", end_of_message: true, end_of_dialog: true} +``` + +Cuando `streaming=false`: +Comportamiento actual preservado +Respuesta única con respuesta completa +`end_of_message=true`, `end_of_dialog=true` + +#### Gateway y API de Python + +Gateway: Nuevo punto final SSE/WebSocket para la transmisión de agentes +API de Python: Nuevo método de generador asíncrono `agent_stream()` + +-- + +## Consideraciones de seguridad + +**Sin nueva superficie de ataque**: La transmisión utiliza la misma autenticación/autorización +**Limitación de velocidad**: Aplicar límites de velocidad por token o por fragmento si es necesario +**Manejo de conexiones**: Terminar correctamente las transmisiones en caso de desconexión del cliente +**Gestión de tiempos de espera**: Las solicitudes de transmisión requieren un manejo adecuado de los tiempos de espera + +## Consideraciones de rendimiento + +**Memoria**: La transmisión reduce el uso máximo de memoria (sin almacenamiento en búfer de la respuesta completa) +**Latencia**: El tiempo hasta el primer token se reduce significativamente +**Sobrecarga de conexión**: Las conexiones SSE/WebSocket tienen una sobrecarga de mantenimiento activo +**Rendimiento de Pulsar**: Múltiples mensajes pequeños frente a un mensaje grande único + tradeoff + +## Estrategia de pruebas + +### Pruebas unitarias +Serialización/deserialización de esquema con nuevos campos +Compatibilidad con versiones anteriores (los campos faltantes utilizan los valores predeterminados) +Lógica de ensamblaje de fragmentos + +### Pruebas de integración +Implementación de transmisión de cada proveedor de LLM +Puntos finales de transmisión de la API de Gateway +Métodos de transmisión del cliente de Python + +### Pruebas de extremo a extremo +Salida de transmisión de la herramienta de línea de comandos +Flujo completo: Cliente → Gateway → Pulsar → LLM → de vuelta +Cargas de trabajo mixtas de transmisión/no transmisión + +### Pruebas de compatibilidad con versiones anteriores +Los clientes existentes funcionan sin modificaciones +Las solicitudes no de transmisión se comportan de la misma manera + +## Plan de migración + +### Fase 1: Infraestructura +Implementar cambios de esquema (compatible con versiones anteriores) +Implementar actualizaciones de la API de Gateway +Implementar actualizaciones de la API de Python +Lanzar actualizaciones de la herramienta de línea de comandos + +### Fase 2: VertexAI +Implementar la implementación de transmisión de VertexAI +Validar con cargas de trabajo de prueba + +### Fase 3: Todos los proveedores +Implementar las actualizaciones de los proveedores de forma incremental +Monitorear problemas + +### Fase 4: API de agente +Implementar cambios de esquema de agente +Implementar la implementación de transmisión de agente +Actualizar la documentación + +## Cronograma + +| Fase | Descripción | Dependencias | +|-------|-------------|--------------| +| Fase 1 | Infraestructura | Ninguna | +| Fase 2 | PoC de VertexAI | Fase 1 | +| Fase 3 | Todos los proveedores | Fase 2 | +| Fase 4 | API de agente | Fase 3 | + +## Decisiones de diseño + +Las siguientes preguntas se resolvieron durante la especificación: + +1. **Conteo de tokens en la transmisión**: Los conteos de tokens son deltas, no totales acumulados. + Los consumidores pueden sumarlos si es necesario. Esto coincide con la forma en que la mayoría de los proveedores informan + el uso y simplifica la implementación. + +2. **Manejo de errores en la transmisión**: Si ocurre un error, el campo `error` se + completa y no se necesitan otros campos. Un error siempre es la comunicación final + no se permiten ni se esperan mensajes posteriores después de + un error. Para las transmisiones de LLM/Prompt, `end_of_stream=true`. Para las transmisiones de agente, + `chunk_type="error"` con `end_of_dialog=true`. + +3. **Recuperación de respuesta parcial**: El protocolo de mensajería (Pulsar) es resistente, + por lo que no se necesita reintento a nivel de mensaje. Si un cliente pierde el seguimiento de la transmisión + o se desconecta, debe reintentar la solicitud completa desde cero. + +4. **Transmisión del servicio de prompt**: La transmisión solo es compatible con texto (`text`) + respuestas, no respuestas estructuradas (`object`). El servicio de prompt lo sabe desde + el principio si la salida será JSON o texto según la plantilla del prompt. Si se realiza una + solicitud de transmisión para un prompt de salida JSON, el + servicio debe: + Devolver el JSON completo en una sola respuesta con `end_of_stream=true`, o + Rechazar la solicitud de transmisión con un error + +## Preguntas abiertas + +Ninguna en este momento. + +## Referencias + +Esquema de LLM actual: `trustgraph-base/trustgraph/schema/services/llm.py` +Esquema de prompt actual: `trustgraph-base/trustgraph/schema/services/prompt.py` +Esquema de agente actual: `trustgraph-base/trustgraph/schema/services/agent.py` +Base del servicio de LLM: `trustgraph-base/trustgraph/base/llm_service.py` +Proveedor de VertexAI: `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` +API de Gateway: `trustgraph-base/trustgraph/api/` +Herramientas de CLI: `trustgraph-cli/trustgraph/cli/` diff --git a/docs/tech-specs/streaming-llm-responses.he.md b/docs/tech-specs/streaming-llm-responses.he.md new file mode 100644 index 00000000..e860d05f --- /dev/null +++ b/docs/tech-specs/streaming-llm-responses.he.md @@ -0,0 +1,570 @@ +# מפרט טכני לתגובות LLM בסטרימינג + +## סקירה כללית + +מפרט זה מתאר את יישום התמיכה בסטרימינג עבור תגובות LLM +ב-TrustGraph. סטרימינג מאפשר העברה בזמן אמת של טוקנים שנוצרו +ככל שהם מיוצרים על ידי ה-LLM, במקום לחכות להשלמת יצירת +התגובה. + +יישום זה תומך בתרחישי שימוש הבאים: + +1. **ממשקי משתמש בזמן אמת**: העברת טוקנים לממשק המשתמש בזמן יצירתם, + תוך מתן משוב ויזואלי מיידי. +2. **זמן עד לטוקן הראשון מופחת**: המשתמש רואה את הפלט מיד + ולא מחכה ליצירה מלאה. +3. **טיפול בתגובות ארוכות**: טיפול בפלטים ארוכים מאוד שעלולים + אחרת לגרום לחריגה מהזמן או לחרוג ממגבלות הזיכרון. +4. **יישומים אינטראקטיביים**: אפשור ממשקי צ'אט וסוכנים מגיבים. + +## מטרות + +**תאימות לאחור**: לקוחות קיימים שאינם משתמשים בסטרימינג ממשיכים + לעבוד ללא שינוי. +**עיצוב API עקבי**: סטרימינג ולא סטרימינג משתמשים באותם דפוסי + סכימה עם סטייה מינימלית. +**גמישות ספק**: תמיכה בסטרימינג כאשר הוא זמין, מעבר חלק + כאשר הוא אינו זמין. +**פריסה מדורגת**: יישום הדרגתי להפחתת סיכונים. +**תמיכה מקצה לקצה**: סטרימינג מספק ה-LLM דרך ליישומי לקוח + באמצעות Pulsar, Gateway API ו-Python API. + +## רקע + +### ארכיטקטורה נוכחית + +זרימת השלמת הטקסט הנוכחית של ה-LLM פועלת באופן הבא: + +1. לקוח שולח `TextCompletionRequest` עם שדות `system` ו-`prompt`. +2. שירות ה-LLM מעבד את הבקשה וממתין להשלמת היצירה. +3. `TextCompletionResponse` יחיד מוחזר עם מחרוזת `response` מלאה. + +סכימה נוכחית (`trustgraph-base/trustgraph/schema/services/llm.py`): + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() +``` + +### מגבלות נוכחיות + +**השהייה (Latency)**: משתמשים חייבים לחכות לסיום יצירת התוכן לפני שהם רואים פלט כלשהו. +**סיכון לחריגת זמן (Timeout)**: יצירת תוכן ארוכה עלולה לחרוג מספי זמן המוגדר בלקוח. +**חוויית משתמש ירודה (Poor UX)**: היעדר משוב במהלך היצירה יוצר תחושה של איטיות. +**שימוש במשאבים**: תגובות מלאות חייבות להיות מאוחסנות בזיכרון. + +מפרט זה מתייחס למגבלות אלה על ידי אפשור העברת תגובה הדרגתית תוך שמירה על תאימות מלאה לאחור. + + +## עיצוב טכני + +### שלב 1: תשתית + +שלב 1 מקיים את הבסיס להעברה באמצעות שינוי סכימות, ממשקי API וכלי שורת פקודה. + + +#### שינויים בסכימה + +##### סכימת LLM (`trustgraph-base/trustgraph/schema/services/llm.py`) + +**שינויים בבקשה:** + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() # NEW: Default false for backward compatibility +``` + +`streaming`: כאשר `true`, מבקשים משלוח תגובה בסטרימינג. +ברירת מחדל: `false` (ההתנהגות הקיימת נשמרת). + +**שינויים בתגובה:** + +```python +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +`end_of_stream`: כאשר `true`, מציין שזו התגובה הסופית (או היחידה). +עבור בקשות שאינן סטרימינג: תגובה יחידה עם `end_of_stream=true`. +עבור בקשות סטרימינג: מספר תגובות, כולן עם `end_of_stream=false`. + מלבד התגובה האחרונה. + +##### סכימת הפרומפט (`trustgraph-base/trustgraph/schema/services/prompt.py`) + +שירות הפרומפט עוטף השלמת טקסט, ולכן הוא משקף את אותו דפוס: + +**שינויים בבקשה:** + +```python +class PromptRequest(Record): + id = String() + terms = Map(String()) + streaming = Boolean() # NEW: Default false +``` + +**שינויים בתגובה:** + +```python +class PromptResponse(Record): + error = Error() + text = String() + object = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +#### שינויים בממשק ה-Gateway API + +ממשק ה-Gateway API חייב לחשוף יכולות סטרימינג ללקוחות HTTP/WebSocket. + +**עדכונים לממשק ה-REST API:** + +`POST /api/v1/text-completion`: קבלת פרמטר `streaming` בגוף הבקשה +התנהגות התגובה תלויה בדגל הסטרימינג: + `streaming=false`: תגובת JSON בודדת (ההתנהגות הנוכחית) + `streaming=true`: זרם Server-Sent Events (SSE) או הודעות WebSocket + +**פורמט תגובה (סטרימינג):** + +כל חלק בזרם עוקב אחר מבנה הסכימה זהה: +```json +{ + "response": "partial text...", + "end_of_stream": false, + "model": "model-name" +} +``` + +חלק אחרון: +```json +{ + "response": "final text chunk", + "end_of_stream": true, + "in_token": 150, + "out_token": 500, + "model": "model-name" +} +``` + +#### שינויים בממשק ה-API של Python + +ממשק ה-API של הלקוח ב-Python חייב לתמוך הן במצב סטרימינג והן במצב לא-סטרימינג +תוך שמירה על תאימות לאחור. + +**עדכונים ל-LlmClient** (`trustgraph-base/trustgraph/clients/llm_client.py`): + +```python +class LlmClient(BaseClient): + def request(self, system, prompt, timeout=300, streaming=False): + """ + Non-streaming request (backward compatible). + Returns complete response string. + """ + # Existing behavior when streaming=False + + async def request_stream(self, system, prompt, timeout=300): + """ + Streaming request. + Yields response chunks as they arrive. + """ + # New async generator method +``` + +**עדכונים עבור PromptClient** (`trustgraph-base/trustgraph/base/prompt_client.py`): + +דפוס דומה עם הפרמטר `streaming` וגרסה אסינכרונית של מחולל. + +#### שינויים בכלי שורת הפקודה + +**tg-invoke-llm** (`trustgraph-cli/trustgraph/cli/invoke_llm.py`): + +``` +tg-invoke-llm [system] [prompt] [--no-streaming] [-u URL] [-f flow-id] +``` + +הפעלת סטרימינג כברירת מחדל לשיפור חוויית משתמש אינטראקטיבית. +הדגל `--no-streaming` משבית את הסטרימינג. +כאשר הסטרימינג מופעל: פלט טוקנים לפלט סטנדרטי כשהם מגיעים. +כאשר הסטרימינג אינו מופעל: ממתינים לתגובה מלאה, ולאחר מכן מבצעים פלט. + +**tg-invoke-prompt** (`trustgraph-cli/trustgraph/cli/invoke_prompt.py`): + +``` +tg-invoke-prompt [template-id] [var=value...] [--no-streaming] [-u URL] [-f flow-id] +``` + +אותו דפוס כמו `tg-invoke-llm`. + +#### שינויים במחלקת הבסיס של שירות מודל שפה גדול (LLM). + +**LlmService** (`trustgraph-base/trustgraph/base/llm_service.py`): + +```python +class LlmService(FlowProcessor): + async def on_request(self, msg, consumer, flow): + request = msg.value() + streaming = getattr(request, 'streaming', False) + + if streaming and self.supports_streaming(): + async for chunk in self.generate_content_stream(...): + await self.send_response(chunk, end_of_stream=False) + await self.send_response(final_chunk, end_of_stream=True) + else: + response = await self.generate_content(...) + await self.send_response(response, end_of_stream=True) + + def supports_streaming(self): + """Override in subclass to indicate streaming support.""" + return False + + async def generate_content_stream(self, system, prompt, model, temperature): + """Override in subclass to implement streaming.""" + raise NotImplementedError() +``` + +-- + +### שלב 2: הוכחת היתכנות של VertexAI + +שלב 2 מיישם סטרימינג בספק יחיד (VertexAI) כדי לאמת את +התשתית ולאפשר בדיקות מקצה לקצה. + +#### יישום VertexAI + +**מודול:** `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` + +**שינויים:** + +1. החלפה של `supports_streaming()` כדי להחזיר `True` +2. יישום מחולל אסינכרוני `generate_content_stream()` +3. טיפול גם במודלים של Gemini וגם של Claude (דרך ממשק ה-API של VertexAI Anthropic) + +**סטרימינג של Gemini:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + model_instance = self.get_model(model, temperature) + response = model_instance.generate_content( + [system, prompt], + stream=True # Enable streaming + ) + for chunk in response: + yield LlmChunk( + text=chunk.text, + in_token=None, # Available only in final chunk + out_token=None, + ) + # Final chunk includes token counts from response.usage_metadata +``` + +**קלוד (דרך VertexAI של חברת Anthropic) - סטרימינג:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + with self.anthropic_client.messages.stream(...) as stream: + for text in stream.text_stream: + yield LlmChunk(text=text) + # Token counts from stream.get_final_message() +``` + +#### בדיקות + +בדיקות יחידה עבור הרכבת תגובות סטרימינג +בדיקות אינטגרציה עם VertexAI (Gemini ו-Claude) +בדיקות מקצה לקצה: CLI -> Gateway -> Pulsar -> VertexAI -> חזרה +בדיקות תאימות לאחור: בקשות שאינן סטרימינג עדיין עובדות + +-- + +### שלב 3: כל ספקי מודלי שפה גדולים (LLM) + +שלב 3 מרחיב את תמיכת הסטרימינג לכל ספקי מודלי השפה הגדולים במערכת. + +#### סטטוס יישום ספק + +כל ספק חייב לבצע אחת מהפעולות הבאות: +1. **תמיכה מלאה בסטרימינג**: ליישם `generate_content_stream()` +2. **מצב תאימות**: לטפל בדגל `end_of_stream` בצורה נכונה + (להחזיר תגובה בודדת עם `end_of_stream=true`) + +| ספק | חבילה | תמיכה בסטרימינג | +|----------|---------|-------------------| +| OpenAI | trustgraph-flow | מלא (ממשק סטרימינג מקורי) | +| Claude/Anthropic | trustgraph-flow | מלא (ממשק סטרימינג מקורי) | +| Ollama | trustgraph-flow | מלא (ממשק סטרימינג מקורי) | +| Cohere | trustgraph-flow | מלא (ממשק סטרימינג מקורי) | +| Mistral | trustgraph-flow | מלא (ממשק סטרימינג מקורי) | +| Azure OpenAI | trustgraph-flow | מלא (ממשק סטרימינג מקורי) | +| Google AI Studio | trustgraph-flow | מלא (ממשק סטרימינג מקורי) | +| VertexAI | trustgraph-vertexai | מלא (שלב 2) | +| Bedrock | trustgraph-bedrock | מלא (ממשק סטרימינג מקורי) | +| LM Studio | trustgraph-flow | מלא (תואם ל-OpenAI) | +| LlamaFile | trustgraph-flow | מלא (תואם ל-OpenAI) | +| vLLM | trustgraph-flow | מלא (תואם ל-OpenAI) | +| TGI | trustgraph-flow | מצומצם | +| Azure | trustgraph-flow | מצומצם | + +#### תבנית יישום + +עבור ספקים התואמים ל-OpenAI (OpenAI, LM Studio, LlamaFile, vLLM): + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + response = await self.client.chat.completions.create( + model=model, + messages=[ + {"role": "system", "content": system}, + {"role": "user", "content": prompt} + ], + temperature=temperature, + stream=True + ) + async for chunk in response: + if chunk.choices[0].delta.content: + yield LlmChunk(text=chunk.choices[0].delta.content) +``` + +-- + +### שלב 4: ממשק API של הסוכן + +שלב 4 מרחיב את הסטרימינג לממשק ה-API של הסוכן. זה מורכב יותר מכיוון שה- +ממשק ה-API של הסוכן הוא כבר מטבעו רב-הודעות (מחשבה → פעולה → תצפית +→ חזור → תשובה סופית). + +#### הסכימה הנוכחית של הסוכן + +```python +class AgentStep(Record): + thought = String() + action = String() + arguments = Map(String()) + observation = String() + user = String() + +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + +class AgentResponse(Record): + answer = String() + error = Error() + thought = String() + observation = String() +``` + +#### שינויים מוצעים בסכימת הסוכן + +**בקשות לשינויים:** + +```python +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + streaming = Boolean() # NEW: Default false +``` + +**שינויים בתגובה:** + +הסוכן מייצר סוגים שונים של פלט במהלך מחזור החשיבה שלו: +מחשבות (היגיון) +פעולות (קריאות לכלי) +תצפיות (תוצאות של כלי) +תשובה (תגובה סופית) +שגיאות + +מכיוון ש-`chunk_type` מציין איזה סוג תוכן נשלח, השדות הנפרדים +`answer`, `error`, `thought` ו-`observation` יכולים להיות מקובצים לשדה +`content` יחיד: + +```python +class AgentResponse(Record): + chunk_type = String() # "thought", "action", "observation", "answer", "error" + content = String() # The actual content (interpretation depends on chunk_type) + end_of_message = Boolean() # Current thought/action/observation/answer is complete + end_of_dialog = Boolean() # Entire agent dialog is complete +``` + +**סמנטיקה של שדות:** + +`chunk_type`: מציין איזה סוג תוכן נמצא בשדה `content` + `"thought"`: חשיבה/היגיון של הסוכן + `"action"`: כלי/פעולה המופעלת + `"observation"`: תוצאה מהפעלת הכלי + `"answer"`: תשובה סופית לשאלה של המשתמש + `"error"`: הודעת שגיאה + +`content`: התוכן המועבר בפועל, המפורש בהתאם ל-`chunk_type` + +`end_of_message`: כאשר `true`, סוג החלק הנוכחי הושלם + דוגמה: כל הטוקנים עבור המחשבה הנוכחית נשלחו + מאפשר ללקוחות לדעת מתי לעבור לשלב הבא + +`end_of_dialog`: כאשר `true`, האינטראקציה כולה של הסוכן הושלמה + זו ההודעה האחרונה בזרם + +#### התנהגות סטרימינג של הסוכן + +כאשר `streaming=true`: + +1. **סטרימינג של מחשבות:** + מספר חלקים עם `chunk_type="thought"`, `end_of_message=false` + החלק האחרון של המחשבה מכיל `end_of_message=true` +2. **הודעת פעולה:** + חלק יחיד עם `chunk_type="action"`, `end_of_message=true` +3. **תצפית:** + חלק/ים עם `chunk_type="observation"`, האחרון מכיל `end_of_message=true` +4. **חזור** על שלבים 1-3 כאשר הסוכן מסיק מסקנות +5. **תשובה סופית:** + `chunk_type="answer"` עם התגובה הסופית ב-`content` + החלק האחרון מכיל `end_of_message=true`, `end_of_dialog=true` + +**רצף סטרימינג לדוגמה:** + +``` +{chunk_type: "thought", content: "I need to", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " search for...", end_of_message: true, end_of_dialog: false} +{chunk_type: "action", content: "search", end_of_message: true, end_of_dialog: false} +{chunk_type: "observation", content: "Found: ...", end_of_message: true, end_of_dialog: false} +{chunk_type: "thought", content: "Based on this", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " I can answer...", end_of_message: true, end_of_dialog: false} +{chunk_type: "answer", content: "The answer is...", end_of_message: true, end_of_dialog: true} +``` + +כאשר `streaming=false`: +התנהגות נוכחית נשמרת +תגובה אחת עם תשובה מלאה +`end_of_message=true`, `end_of_dialog=true` + +#### שער (Gateway) ו-API בפייתון + +שער: נקודת קצה חדשה של SSE/WebSocket עבור סטרימינג של סוכן +API בפייתון: שיטת גנרטור אסינכרונית חדשה `agent_stream()` + +-- + +## שיקולי אבטחה + +**ללא נקודות תורפה חדשות**: סטרימינג משתמש באותה אימות/הרשאה +**הגבלת קצב**: יש להחיל מגבלות קצב פר-טוקן או פר-חלק במידת הצורך +**טיפול בחיבורים**: יש לסיים חיבורים בצורה תקינה בעת ניתוק הלקוח +**ניהול תזמון**: בקשות סטרימינג דורשות טיפול מתאים בתזמון + +## שיקולי ביצועים + +**זיכרון**: סטרימינג מפחית את השימוש בזיכרון המקסימלי (ללא אחסון מלא של התגובה) +**השהיה**: זמן עד לקבלת הטוקן הראשון קטן משמעותית +**תקורה של חיבורים**: לחיבורי SSE/WebSocket יש תקורה של שמירה על חיבור פעיל +**תפוקת Pulsar**: מספר הודעות קטנות לעומת הודעה גדולה אחת + פשרה + +## אסטרטגיית בדיקות + +### בדיקות יחידה +סריאליזציה/דה-סריאליזציה של סכימה עם שדות חדשים +תאימות לאחור (שדות חסרים משתמשים בערכי ברירת מחדל) +לוגיקת הרכבת חלקים + +### בדיקות אינטגרציה +יישום הסטרימינג של כל ספק מודלי שפה גדולים (LLM) +נקודות קצה של סטרימינג של API בשער +שיטות סטרימינג של לקוח בפייתון + +### בדיקות מקצה לקצה +פלט סטרימינג של כלי שורת הפקודה (CLI) +זרימה מלאה: לקוח → שער → Pulsar → LLM → חזרה +עומסי עבודה מעורבים של סטרימינג/לא סטרימינג + +### בדיקות תאימות לאחור +לקוחות קיימים עובדים ללא שינוי +בקשות לא סטרימינג מתנהגות באופן זהה + +## תוכנית מעבר + +### שלב 1: תשתית +פריסת שינויי סכימה (תואמת לאחור) +פריסת עדכוני API בשער +פריסת עדכוני API בפייתון +שחרור עדכוני כלי שורת הפקודה + +### שלב 2: VertexAI +הטמעת יישום סטרימינג של VertexAI +אימות באמצעות עומסי עבודה לבדיקה + +### שלב 3: כל הספקים +הטמעת עדכוני ספק באופן הדרגתי +ניטור לאיתור בעיות + +### שלב 4: ממשק API של סוכן +הטמעת שינויים בסכימת הסוכן +הטמעת יישום סטרימינג של סוכן +עדכון התיעוד + +## ציר זמן + +| שלב | תיאור | תלויות | +|-------|-------------|--------------| +| שלב 1 | תשתית | אין | +| שלב 2 | הוכחת היתכנות של VertexAI | שלב 1 | +| שלב 3 | כל הספקים | שלב 2 | +| שלב 4 | ממשק API של סוכן | שלב 3 | + +## החלטות עיצוב + +השאלות הבאות נפתרו במהלך המפרט: + +1. **ספירת טוקנים בסטרימינג**: ספירת הטוקנים היא הפרשים, ולא סכומים מצטברים. + צרכנים יכולים לחבר אותם אם יש צורך. זה תואם לאופן שבו רוב הספקים מדווחים + על שימוש ומפשט את היישום. + +2. **טיפול בשגיאות בזרמים**: אם מתרחשת שגיאה, השדה `error` מאוכלס ושאר השדות אינם נחוצים. שגיאה היא תמיד ההודעה האחרונה - אסור לשלוח או לצפות להודעות נוספות לאחר מכן. + + + שגיאה. עבור זרמי מודלים שפתיים (LLM) / הנחיות, `end_of_stream=true`. עבור זרמי סוכנים, + `chunk_type="error"` עם `end_of_dialog=true`. + +3. **התאוששות מתגובה חלקית**: פרוטוקול העברת ההודעות (Pulsar) עמיד, + ולכן אין צורך בניסיונות חוזרים ברמת ההודעה. אם לקוח מאבד את המעקב אחר הזרם + או מתנתק, עליו לנסות שוב את כל הבקשה מההתחלה. + +4. **שירות מהיר עם סטרימינג**: סטרימינג נתמך רק עבור טקסט (`text`) + תשובות, ולא עבור תשובות מובנות (`object`). שירות הפרומפט יודע מראש + האם הפלט יהיה JSON או טקסט, בהתבסס על תבנית הפרומפט. אם מתבצעת + בקשת סטרימינג עבור פרומפט שפלטו הוא JSON, אז... + השירות צריך או: + להחזיר את קובץ ה-JSON השלם בתגובה אחת עם `end_of_stream=true`, או + לדחות את בקשת הסטרימינג עם שגיאה + +## שאלות פתוחות + +אין כרגע. + +## הפניות + +סכימת מודל שפה גדול (LLM) נוכחית: `trustgraph-base/trustgraph/schema/services/llm.py` +סכימת הנחיה נוכחית: `trustgraph-base/trustgraph/schema/services/prompt.py` +סכימת סוכן נוכחית: `trustgraph-base/trustgraph/schema/services/agent.py` +שירות LLM בסיסי: `trustgraph-base/trustgraph/base/llm_service.py` +ספק VertexAI: `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` +ממשק API של שער: `trustgraph-base/trustgraph/api/` +כלי שורת פקודה: `trustgraph-cli/trustgraph/cli/` diff --git a/docs/tech-specs/streaming-llm-responses.hi.md b/docs/tech-specs/streaming-llm-responses.hi.md new file mode 100644 index 00000000..730e0b16 --- /dev/null +++ b/docs/tech-specs/streaming-llm-responses.hi.md @@ -0,0 +1,570 @@ +# स्ट्रीमिंग एलएलएम प्रतिक्रियाओं के लिए तकनीकी विनिर्देश + +## अवलोकन + +यह विनिर्देश ट्रस्टग्राफ में एलएलएम प्रतिक्रियाओं के लिए स्ट्रीमिंग समर्थन के कार्यान्वयन का वर्णन करता है। स्ट्रीमिंग, उत्पन्न किए जा रहे टोकन को वास्तविक समय में वितरित करने की अनुमति देता है, बजाय कि पूरी प्रतिक्रिया उत्पन्न होने तक प्रतीक्षा करने के। +स्ट्रीमिंग, एलएलएम द्वारा उत्पन्न किए जा रहे टोकन को वास्तविक समय में वितरित करने की अनुमति देता है, बजाय कि पूरी प्रतिक्रिया उत्पन्न होने तक प्रतीक्षा करने के। +स्ट्रीमिंग, उत्पन्न किए जा रहे टोकन को वास्तविक समय में वितरित करने की अनुमति देता है, बजाय कि पूरी प्रतिक्रिया उत्पन्न होने तक प्रतीक्षा करने के। +स्ट्रीमिंग, उत्पन्न किए जा रहे टोकन को वास्तविक समय में वितरित करने की अनुमति देता है, बजाय कि पूरी प्रतिक्रिया उत्पन्न होने तक प्रतीक्षा करने के। + +यह कार्यान्वयन निम्नलिखित उपयोग मामलों का समर्थन करता है: + +1. **वास्तविक समय उपयोगकर्ता इंटरफेस**: उत्पन्न होने पर टोकन को UI में भेजें, + जिससे तत्काल दृश्य प्रतिक्रिया प्रदान की जा सके। +2. **पहले टोकन के लिए कम समय**: उपयोगकर्ता तुरंत आउटपुट देखना शुरू करते हैं, + पूर्ण पीढ़ी की प्रतीक्षा करने के बजाय। +3. **लंबी प्रतिक्रिया प्रबंधन**: बहुत लंबी आउटपुट को संभालें जो अन्यथा + समय समाप्त हो सकते हैं या मेमोरी सीमा से अधिक हो सकते हैं। +4. **इंटरैक्टिव एप्लिकेशन**: उत्तरदायी चैट और एजेंट इंटरफेस को सक्षम करें। + +## लक्ष्य + +**पिछड़ा संगतता (Backward Compatibility)**: मौजूदा, गैर-स्ट्रीमिंग क्लाइंट बिना किसी बदलाव के काम करते रहते हैं। + बिना किसी बदलाव के। +**संगत एपीआई डिज़ाइन (Consistent API Design)**: स्ट्रीमिंग और गैर-स्ट्रीमिंग दोनों समान स्कीमा पैटर्न का उपयोग करते हैं, जिसमें न्यूनतम विचलन होता है। + होता है। +**प्रदाता लचीलापन (Provider Flexibility)**: जहां उपलब्ध हो, वहां स्ट्रीमिंग का समर्थन करें, और जहां उपलब्ध न हो, वहां सुचारू रूप से वापस आएं। + वापस आएं। +**चरणबद्ध कार्यान्वयन (Phased Rollout)**: जोखिम को कम करने के लिए क्रमिक कार्यान्वयन। +**एंड-टू-एंड समर्थन (End-to-End Support)**: एलएलएम प्रदाता से लेकर क्लाइंट तक स्ट्रीमिंग, पल्सर, गेटवे एपीआई और पायथन एपीआई के माध्यम से एप्लिकेशन तक। + एप्लिकेशन तक। + +## पृष्ठभूमि (Background) + +### वर्तमान आर्किटेक्चर (Current Architecture) + +वर्तमान एलएलएम टेक्स्ट कंप्लीशन प्रवाह इस प्रकार काम करता है: + +1. क्लाइंट `TextCompletionRequest` भेजता है जिसमें `system` और `prompt` फ़ील्ड होते हैं। +2. एलएलएम सेवा अनुरोध को संसाधित करती है और पूर्ण पीढ़ी की प्रतीक्षा करती है। +3. पूर्ण `response` स्ट्रिंग के साथ एक `TextCompletionResponse` वापस किया जाता है। + +वर्तमान स्कीमा (`trustgraph-base/trustgraph/schema/services/llm.py`): + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() +``` + +### वर्तमान सीमाएँ + +**विलंबता (Latency)**: उपयोगकर्ताओं को किसी भी आउटपुट को देखने से पहले पूर्ण पीढ़ी के पूरा होने का इंतजार करना पड़ता है। +**समय-सीमा (Timeout) का जोखिम**: लंबी पीढ़ी क्लाइंट समय-सीमा सीमाओं से अधिक हो सकती है। +**खराब उपयोगकर्ता अनुभव (Poor UX)**: पीढ़ी के दौरान कोई प्रतिक्रिया नहीं होने से धीमेपन का आभास होता है। +**संसाधन उपयोग (Resource Usage)**: पूर्ण प्रतिक्रियाओं को मेमोरी में बफर किया जाना चाहिए। + +यह विनिर्देश क्रमिक प्रतिक्रिया को सक्षम करके इन सीमाओं को संबोधित करता है, जबकि पूर्ण पश्च संगतता (backward compatibility) बनाए रखता है। + + +## तकनीकी डिज़ाइन + +### चरण 1: बुनियादी ढांचा + +चरण 1, स्ट्रीमिंग के लिए आधार तैयार करता है, जिसमें स्कीमा, एपीआई और सीएलआई टूल में संशोधन शामिल हैं। + + +#### स्कीमा परिवर्तन + +##### एलएलएम स्कीमा (`trustgraph-base/trustgraph/schema/services/llm.py`) + +**अनुरोध परिवर्तन:** + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() # NEW: Default false for backward compatibility +``` + +`streaming`: जब `true`, तो स्ट्रीमिंग प्रतिक्रिया डिलीवरी का अनुरोध करता है। +डिफ़ॉल्ट: `false` (मौजूदा व्यवहार संरक्षित)। + +**प्रतिक्रिया में परिवर्तन:** + +```python +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +`end_of_stream`: जब `true`, तो यह दर्शाता है कि यह अंतिम (या एकमात्र) प्रतिक्रिया है। +गैर-स्ट्रीमिंग अनुरोधों के लिए: `end_of_stream=true` के साथ एकल प्रतिक्रिया। +स्ट्रीमिंग अनुरोधों के लिए: `end_of_stream=false` के साथ कई प्रतिक्रियाएँ, + अंतिम प्रतिक्रिया को छोड़कर। + +##### प्रॉम्प्ट स्कीमा (`trustgraph-base/trustgraph/schema/services/prompt.py`) + +प्रॉम्प्ट सेवा टेक्स्ट कंप्लीशन को लपेटती है, इसलिए यह समान पैटर्न को प्रतिबिंबित करती है: + +**अनुरोध परिवर्तन:** + +```python +class PromptRequest(Record): + id = String() + terms = Map(String()) + streaming = Boolean() # NEW: Default false +``` + +**प्रतिक्रिया में परिवर्तन:** + +```python +class PromptResponse(Record): + error = Error() + text = String() + object = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +#### गेटवे एपीआई में बदलाव + +गेटवे एपीआई को एचटीटीपी/वेबसोकेट क्लाइंट्स के लिए स्ट्रीमिंग क्षमताएं प्रदान करनी होंगी। + +**रेस्ट एपीआई अपडेट:** + +`POST /api/v1/text-completion`: अनुरोध बॉडी में `streaming` पैरामीटर स्वीकार करें +प्रतिक्रिया व्यवहार स्ट्रीमिंग फ़्लैग पर निर्भर करता है: + `streaming=false`: एकल JSON प्रतिक्रिया (वर्तमान व्यवहार) + `streaming=true`: सर्वर-सेंट इवेंट्स (एसएसई) स्ट्रीम या वेबसोकेट संदेश + +**प्रतिक्रिया प्रारूप (स्ट्रीमिंग):** + +प्रत्येक स्ट्रीम किए गए भाग में समान स्कीमा संरचना होती है: +```json +{ + "response": "partial text...", + "end_of_stream": false, + "model": "model-name" +} +``` + +अंतिम भाग: +```json +{ + "response": "final text chunk", + "end_of_stream": true, + "in_token": 150, + "out_token": 500, + "model": "model-name" +} +``` + +#### पायथन एपीआई में बदलाव + +पायथन क्लाइंट एपीआई को स्ट्रीमिंग और नॉन-स्ट्रीमिंग दोनों मोड का समर्थन करना चाहिए +साथ ही पिछली अनुकूलता बनाए रखनी चाहिए। + +**LlmClient अपडेट** (`trustgraph-base/trustgraph/clients/llm_client.py`): + +```python +class LlmClient(BaseClient): + def request(self, system, prompt, timeout=300, streaming=False): + """ + Non-streaming request (backward compatible). + Returns complete response string. + """ + # Existing behavior when streaming=False + + async def request_stream(self, system, prompt, timeout=300): + """ + Streaming request. + Yields response chunks as they arrive. + """ + # New async generator method +``` + +**प्रॉम्प्टक्लाइंट अपडेट** (`trustgraph-base/trustgraph/base/prompt_client.py`): + +`streaming` पैरामीटर और एसिंक्रोनस जेनरेटर संस्करण के साथ समान पैटर्न। + +#### सीएलआई टूल में बदलाव + +**tg-invoke-llm** (`trustgraph-cli/trustgraph/cli/invoke_llm.py`): + +``` +tg-invoke-llm [system] [prompt] [--no-streaming] [-u URL] [-f flow-id] +``` + +डिफ़ॉल्ट रूप से बेहतर इंटरैक्टिव यूएक्स के लिए स्ट्रीमिंग सक्षम है। +`--no-streaming` ध्वज स्ट्रीमिंग को अक्षम करता है। +जब स्ट्रीमिंग हो: आउटपुट टोकन को stdout पर तब भेजें जब वे आएं। +जब स्ट्रीमिंग न हो: पूर्ण प्रतिक्रिया की प्रतीक्षा करें, फिर आउटपुट करें। + +**tg-invoke-prompt** (`trustgraph-cli/trustgraph/cli/invoke_prompt.py`): + +``` +tg-invoke-prompt [template-id] [var=value...] [--no-streaming] [-u URL] [-f flow-id] +``` + +`tg-invoke-llm` के समान पैटर्न। + +#### एलएलएम सर्विस बेस क्लास में बदलाव + +**LlmService** (`trustgraph-base/trustgraph/base/llm_service.py`): + +```python +class LlmService(FlowProcessor): + async def on_request(self, msg, consumer, flow): + request = msg.value() + streaming = getattr(request, 'streaming', False) + + if streaming and self.supports_streaming(): + async for chunk in self.generate_content_stream(...): + await self.send_response(chunk, end_of_stream=False) + await self.send_response(final_chunk, end_of_stream=True) + else: + response = await self.generate_content(...) + await self.send_response(response, end_of_stream=True) + + def supports_streaming(self): + """Override in subclass to indicate streaming support.""" + return False + + async def generate_content_stream(self, system, prompt, model, temperature): + """Override in subclass to implement streaming.""" + raise NotImplementedError() +``` + +-- + +### चरण 2: वर्टेक्सएआई प्रूफ ऑफ कॉन्सेप्ट + +चरण 2, सत्यापन के लिए एक ही प्रदाता (वर्टेक्सएआई) में स्ट्रीमिंग को लागू करता है और एंड-टू-एंड परीक्षण को सक्षम करता है। +बुनियादी ढांचे। + +#### वर्टेक्सएआई कार्यान्वयन + +**मॉड्यूल:** `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` + +**परिवर्तन:** + +1. `supports_streaming()` को `True` लौटाने के लिए ओवरराइड करें। +2. `generate_content_stream()` एसिंक्रोनस जेनरेटर को लागू करें। +3. जेमिनी और क्लाउड दोनों मॉडलों को संभालें (वर्टेक्सएआई एंथ्रोपिक एपीआई के माध्यम से)। + +**जेमिनी स्ट्रीमिंग:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + model_instance = self.get_model(model, temperature) + response = model_instance.generate_content( + [system, prompt], + stream=True # Enable streaming + ) + for chunk in response: + yield LlmChunk( + text=chunk.text, + in_token=None, # Available only in final chunk + out_token=None, + ) + # Final chunk includes token counts from response.usage_metadata +``` + +**क्लाउड (वर्टेक्सएआई एंथ्रोपिक) स्ट्रीमिंग:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + with self.anthropic_client.messages.stream(...) as stream: + for text in stream.text_stream: + yield LlmChunk(text=text) + # Token counts from stream.get_final_message() +``` + +#### परीक्षण + +स्ट्रीमिंग प्रतिक्रिया असेंबली के लिए यूनिट परीक्षण +वर्टेक्सएआई (जेमिनी और क्लाउड) के साथ एकीकरण परीक्षण +एंड-टू-एंड परीक्षण: CLI -> गेटवे -> पल्सर -> वर्टेक्सएआई -> बैक +पिछड़े संगतता परीक्षण: गैर-स्ट्रीमिंग अनुरोध अभी भी काम करते हैं + +-- + +### चरण 3: सभी एलएलएम प्रदाता + +चरण 3 सिस्टम में सभी एलएलएम प्रदाताओं के लिए स्ट्रीमिंग समर्थन का विस्तार करता है। + +#### प्रदाता कार्यान्वयन स्थिति + +प्रत्येक प्रदाता को या तो: +1. **पूर्ण स्ट्रीमिंग समर्थन**: `generate_content_stream()` को लागू करें +2. **संगतता मोड**: `end_of_stream` ध्वज को सही ढंग से संभालें + (एकल प्रतिक्रिया लौटाएं जिसमें `end_of_stream=true` हो) + +| प्रदाता | पैकेज | स्ट्रीमिंग समर्थन | +|----------|---------|-------------------| +| ओपनएआई | trustgraph-flow | पूर्ण (मूल स्ट्रीमिंग एपीआई) | +| क्लाउड/एंथ्रोपिक | trustgraph-flow | पूर्ण (मूल स्ट्रीमिंग एपीआई) | +| ओलामा | trustgraph-flow | पूर्ण (मूल स्ट्रीमिंग एपीआई) | +| कोहेर | trustgraph-flow | पूर्ण (मूल स्ट्रीमिंग एपीआई) | +| मिस्ट्रल | trustgraph-flow | पूर्ण (मूल स्ट्रीमिंग एपीआई) | +| एज़्योर ओपनएआई | trustgraph-flow | पूर्ण (मूल स्ट्रीमिंग एपीआई) | +| गूगल एआई स्टूडियो | trustgraph-flow | पूर्ण (मूल स्ट्रीमिंग एपीआई) | +| वर्टेक्सएआई | trustgraph-vertexai | पूर्ण (चरण 2) | +| बेडरोक | trustgraph-bedrock | पूर्ण (मूल स्ट्रीमिंग एपीआई) | +| एलएम स्टूडियो | trustgraph-flow | पूर्ण (ओपनएआई-संगत) | +| लैमाफाइल | trustgraph-flow | पूर्ण (ओपनएआई-संगत) | +| वीएलएलएम | trustgraph-flow | पूर्ण (ओपनएआई-संगत) | +| टीजीआई | trustgraph-flow | तय किया जाना है | +| एज़्योर | trustgraph-flow | तय किया जाना है | + +#### कार्यान्वयन पैटर्न + +ओपनएआई-संगत प्रदाताओं (ओपनएआई, एलएम स्टूडियो, लैमाफाइल, वीएलएलएम) के लिए: + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + response = await self.client.chat.completions.create( + model=model, + messages=[ + {"role": "system", "content": system}, + {"role": "user", "content": prompt} + ], + temperature=temperature, + stream=True + ) + async for chunk in response: + if chunk.choices[0].delta.content: + yield LlmChunk(text=chunk.choices[0].delta.content) +``` + +-- + +### चरण 4: एजेंट एपीआई + +चरण 4, एजेंट एपीआई तक स्ट्रीमिंग का विस्तार करता है। यह अधिक जटिल है क्योंकि +एजेंट एपीआई स्वभाव से ही मल्टी-मैसेज है (विचार → क्रिया → अवलोकन +→ दोहराव → अंतिम उत्तर)। + +#### वर्तमान एजेंट स्कीमा + +```python +class AgentStep(Record): + thought = String() + action = String() + arguments = Map(String()) + observation = String() + user = String() + +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + +class AgentResponse(Record): + answer = String() + error = Error() + thought = String() + observation = String() +``` + +#### प्रस्तावित एजेंट स्कीमा में परिवर्तन + +**परिवर्तन का अनुरोध:** + +```python +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + streaming = Boolean() # NEW: Default false +``` + +**प्रतिक्रिया में परिवर्तन:** + +एजेंट अपनी तर्क प्रक्रिया के दौरान कई प्रकार के आउटपुट उत्पन्न करता है: +विचार (तर्क) +क्रियाएं (उपकरण कॉल) +अवलोकन (उपकरण परिणाम) +उत्तर (अंतिम प्रतिक्रिया) +त्रुटियाँ + +चूँकि `chunk_type` यह बताता है कि किस प्रकार की सामग्री भेजी जा रही है, इसलिए अलग-अलग +`answer`, `error`, `thought`, और `observation` फ़ील्ड को एक साथ मिलाया जा सकता है। +एक एकल `content` फ़ील्ड: + +```python +class AgentResponse(Record): + chunk_type = String() # "thought", "action", "observation", "answer", "error" + content = String() # The actual content (interpretation depends on chunk_type) + end_of_message = Boolean() # Current thought/action/observation/answer is complete + end_of_dialog = Boolean() # Entire agent dialog is complete +``` + +**फ़ील्ड सिमेंटिक्स:** + +`chunk_type`: यह इंगित करता है कि `content` फ़ील्ड में किस प्रकार की सामग्री है + `"thought"`: एजेंट की तर्क/सोच + `"action"`: उपयोग किए जा रहे टूल/क्रिया + `"observation"`: टूल निष्पादन का परिणाम + `"answer"`: उपयोगकर्ता के प्रश्न का अंतिम उत्तर + `"error"`: त्रुटि संदेश + +`content`: वास्तविक स्ट्रीम की सामग्री, जिसे `chunk_type` के आधार पर व्याख्यायित किया जाता है + +`end_of_message`: जब `true`, तो वर्तमान चंक प्रकार पूरा हो गया है + उदाहरण: वर्तमान विचार के लिए सभी टोकन भेजे जा चुके हैं + यह क्लाइंट को यह जानने की अनुमति देता है कि अगले चरण पर कब जाना है + +`end_of_dialog`: जब `true`, तो संपूर्ण एजेंट इंटरैक्शन पूरा हो गया है + यह स्ट्रीम में अंतिम संदेश है + +#### एजेंट स्ट्रीमिंग व्यवहार + +जब `streaming=true`: + +1. **विचार स्ट्रीमिंग:** + `chunk_type="thought"`, `end_of_message=false` के साथ कई चंक + अंतिम विचार चंक में `end_of_message=true` होता है +2. **एक्शन नोटिफिकेशन:** + `chunk_type="action"`, `end_of_message=true` के साथ एक चंक +3. **अवलोकन:** + `chunk_type="observation"` के साथ चंक(s), अंतिम में `end_of_message=true` होता है +4. **चरण 1-3 को दोहराएं** क्योंकि एजेंट तर्क करता है +5. **अंतिम उत्तर:** + `chunk_type="answer"` जिसमें `content` में अंतिम प्रतिक्रिया है + अंतिम चंक में `end_of_message=true`, `end_of_dialog=true` होता है + +**उदाहरण स्ट्रीम अनुक्रम:** + +``` +{chunk_type: "thought", content: "I need to", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " search for...", end_of_message: true, end_of_dialog: false} +{chunk_type: "action", content: "search", end_of_message: true, end_of_dialog: false} +{chunk_type: "observation", content: "Found: ...", end_of_message: true, end_of_dialog: false} +{chunk_type: "thought", content: "Based on this", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " I can answer...", end_of_message: true, end_of_dialog: false} +{chunk_type: "answer", content: "The answer is...", end_of_message: true, end_of_dialog: true} +``` + +जब `streaming=false`: +वर्तमान व्यवहार संरक्षित +पूर्ण उत्तर के साथ एकल प्रतिक्रिया +`end_of_message=true`, `end_of_dialog=true` + +#### गेटवे और पायथन एपीआई + +गेटवे: एजेंट स्ट्रीमिंग के लिए नया एसएसई/वेबसोकेट एंडपॉइंट +पायथन एपीआई: नया `agent_stream()` एसिंक्रोनस जेनरेटर विधि + +-- + +## सुरक्षा संबंधी विचार + +**कोई नया आक्रमण सतह नहीं**: स्ट्रीमिंग समान प्रमाणीकरण/प्राधिकरण का उपयोग करती है +**दर सीमा**: यदि आवश्यक हो तो प्रति-टोकन या प्रति-खंड दर सीमा लागू करें +**कनेक्शन हैंडलिंग**: क्लाइंट डिस्कनेक्ट होने पर स्ट्रीम को ठीक से समाप्त करें +**टाइमआउट प्रबंधन**: स्ट्रीमिंग अनुरोधों के लिए उचित टाइमआउट हैंडलिंग की आवश्यकता होती है + +## प्रदर्शन संबंधी विचार + +**मेमोरी**: स्ट्रीमिंग से पीक मेमोरी उपयोग कम होता है (कोई पूर्ण प्रतिक्रिया बफरिंग नहीं) +**विलंबता**: पहले टोकन तक का समय काफी कम हो जाता है +**कनेक्शन ओवरहेड**: एसएसई/वेबसोकेट कनेक्शन में कीप-अलाइव ओवरहेड होता है +**पल्सर थ्रूपुट**: एक बड़े संदेश के मुकाबले कई छोटे संदेशों का व्यापार + ट्रेडऑफ़ + +## परीक्षण रणनीति + +### यूनिट टेस्ट +नए फ़ील्ड के साथ स्कीमा सीरियलाइज़ेशन/डीसेरियलाइज़ेशन +पिछड़ा संगतता (गायब फ़ील्ड डिफ़ॉल्ट का उपयोग करते हैं) +चंक असेंबली लॉजिक + +### एकीकरण परीक्षण +प्रत्येक एलएलएम प्रदाता का स्ट्रीमिंग कार्यान्वयन +गेटवे एपीआई स्ट्रीमिंग एंडपॉइंट +पायथन क्लाइंट स्ट्रीमिंग विधियाँ + +### एंड-टू-एंड टेस्ट +सीएलआई टूल स्ट्रीमिंग आउटपुट +पूर्ण प्रवाह: क्लाइंट → गेटवे → पल्सर → एलएलएम → वापस +मिश्रित स्ट्रीमिंग/गैर-स्ट्रीमिंग वर्कलोड + +### पिछड़ा संगतता परीक्षण +मौजूदा क्लाइंट बिना किसी संशोधन के काम करते हैं +गैर-स्ट्रीमिंग अनुरोध समान रूप से व्यवहार करते हैं + +## माइग्रेशन योजना + +### चरण 1: बुनियादी ढांचा +स्कीमा परिवर्तन तैनात करें (पिछड़ा संगत) +गेटवे एपीआई अपडेट तैनात करें +पायथन एपीआई अपडेट तैनात करें +सीएलआई टूल अपडेट जारी करें + +### चरण 2: वर्टेक्सएआई +वर्टेक्सएआई स्ट्रीमिंग कार्यान्वयन को तैनात करें। +परीक्षण वर्कलोड के साथ सत्यापन करें। + +### चरण 3: सभी प्रदाता +प्रदाता अपडेट को धीरे-धीरे लागू करें। +समस्याओं की निगरानी करें। + +### चरण 4: एजेंट एपीआई +एजेंट स्कीमा परिवर्तनों को तैनात करें। +एजेंट स्ट्रीमिंग कार्यान्वयन को तैनात करें। +दस्तावेज़ को अपडेट करें। + +## समयरेखा + +| चरण | विवरण | निर्भरताएँ | +|-------|-------------|--------------| +| चरण 1 | बुनियादी ढांचा | कोई नहीं | +| चरण 2 | वर्टेक्सएआई प्रूफ ऑफ कॉन्सेप्ट | चरण 1 | +| चरण 3 | सभी प्रदाता | चरण 2 | +| चरण 4 | एजेंट एपीआई | चरण 3 | + +## डिज़ाइन निर्णय + +निम्नलिखित प्रश्नों को विनिर्देश के दौरान हल किया गया था: + +1. **स्ट्रीमिंग में टोकन गणना**: टोकन गणनाएँ अंतर हैं, न कि चल रही कुल। + उपभोक्ता आवश्यकतानुसार उन्हें जोड़ सकते हैं। यह अधिकांश प्रदाता द्वारा उपयोग की रिपोर्टिंग के तरीके से मेल खाता है + और कार्यान्वयन को सरल बनाता है। + +2. **स्ट्रीम में त्रुटि प्रबंधन**: यदि कोई त्रुटि होती है, तो `error` फ़ील्ड भरा जाता है और अन्य फ़ील्ड की आवश्यकता नहीं होती है। त्रुटि हमेशा अंतिम संचार होती है - इसके बाद कोई अन्य संदेश अनुमत या अपेक्षित नहीं हैं। + 2. **स्ट्रीम में त्रुटि प्रबंधन**: यदि कोई त्रुटि होती है, तो ⟦CODE_0⟧ फ़ील्ड भरा जाता है और अन्य फ़ील्ड की आवश्यकता नहीं होती है। त्रुटि हमेशा अंतिम संचार होती है - इसके बाद कोई अन्य संदेश अनुमत या अपेक्षित नहीं हैं। + 2. **स्ट्रीम में त्रुटि प्रबंधन**: यदि कोई त्रुटि होती है, तो ⟦CODE_0⟧ फ़ील्ड भरा जाता है और अन्य फ़ील्ड की आवश्यकता नहीं होती है। त्रुटि हमेशा अंतिम संचार होती है - इसके बाद कोई अन्य संदेश अनुमत या अपेक्षित नहीं हैं। + एक त्रुटि। एलएलएम/प्रॉम्प्ट स्ट्रीम के लिए, `end_of_stream=true`। एजेंट स्ट्रीम के लिए, + `chunk_type="error"` को `end_of_dialog=true` के साथ। + +3. **आंशिक प्रतिक्रिया पुनर्प्राप्ति**: संदेश प्रोटोकॉल (पल्सर) मजबूत है, + इसलिए संदेश-स्तर पर पुनः प्रयास की आवश्यकता नहीं है। यदि कोई क्लाइंट स्ट्रीम को खो देता है + या डिस्कनेक्ट हो जाता है, तो उसे पूरी अनुरोध को शुरुआत से फिर से प्रयास करना होगा। + +4. **त्वरित सेवा स्ट्रीमिंग**: स्ट्रीमिंग केवल टेक्स्ट (`text`) के लिए समर्थित है। + प्रतिक्रियाओं के लिए, संरचित (`object`) प्रतिक्रियाओं के लिए नहीं। त्वरित सेवा पहले से ही जानती है कि + आउटपुट JSON होगा या टेक्स्ट-आधारित, यह प्रॉम्प्ट टेम्पलेट पर निर्भर करता है। यदि JSON-आउटपुट प्रॉम्प्ट के लिए + एक स्ट्रीमिंग अनुरोध किया जाता है, तो + सेवा को या तो: + `end_of_stream=true` के साथ एक ही प्रतिक्रिया में पूरा JSON वापस करना चाहिए, या + त्रुटि के साथ स्ट्रीमिंग अनुरोध को अस्वीकार करना चाहिए + +## खुले प्रश्न + +फिलहाल कोई नहीं। + +## संदर्भ + +वर्तमान एलएलएम स्कीमा: `trustgraph-base/trustgraph/schema/services/llm.py` +वर्तमान प्रॉम्प्ट स्कीमा: `trustgraph-base/trustgraph/schema/services/prompt.py` +वर्तमान एजेंट स्कीमा: `trustgraph-base/trustgraph/schema/services/agent.py` +एलएलएम सेवा आधार: `trustgraph-base/trustgraph/base/llm_service.py` +वर्टेक्सएआई प्रदाता: `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` +गेटवे एपीआई: `trustgraph-base/trustgraph/api/` +सीएलआई उपकरण: `trustgraph-cli/trustgraph/cli/` diff --git a/docs/tech-specs/streaming-llm-responses.pt.md b/docs/tech-specs/streaming-llm-responses.pt.md new file mode 100644 index 00000000..612bab19 --- /dev/null +++ b/docs/tech-specs/streaming-llm-responses.pt.md @@ -0,0 +1,570 @@ +# Especificação Técnica de Respostas de LLM em Streaming + +## Visão Geral + +Esta especificação descreve a implementação do suporte a streaming para respostas de LLM +no TrustGraph. O streaming permite a entrega em tempo real de tokens gerados +à medida que são produzidos pelo LLM, em vez de esperar pela geração completa +da resposta. + +Esta implementação suporta os seguintes casos de uso: + +1. **Interfaces de Usuário em Tempo Real**: Transmita tokens para a interface do usuário à medida que são gerados, + fornecendo feedback visual imediato. +2. **Tempo de Primeiro Token Reduzido**: Os usuários veem a saída começando imediatamente + em vez de esperar pela geração completa. +3. **Tratamento de Respostas Longas**: Lidar com saídas muito longas que, de outra forma, + poderiam causar timeout ou exceder os limites de memória. +4. **Aplicações Interativas**: Permitir interfaces de bate-papo e agentes responsivas. + +## Objetivos + +**Compatibilidade com Versões Anteriores**: Os clientes existentes que não utilizam streaming continuam a funcionar + sem modificação. +**Design de API Consistente**: O streaming e o uso sem streaming utilizam os mesmos padrões de esquema + com mínima divergência. +**Flexibilidade do Provedor**: Suporte ao streaming quando disponível, com uma alternativa + suave quando não disponível. +**Implementação Gradual**: Implementação incremental para reduzir o risco. +**Suporte de Ponta a Ponta**: Streaming do provedor de LLM até as aplicações do cliente + via Pulsar, Gateway API e Python API. + +## Contexto + +### Arquitetura Atual + +O fluxo atual de conclusão de texto de LLM opera da seguinte forma: + +1. O cliente envia `TextCompletionRequest` com os campos `system` e `prompt`. +2. O serviço de LLM processa a solicitação e espera pela geração completa. +3. Um único `TextCompletionResponse` é retornado com a string `response` completa. + +Esquema atual (`trustgraph-base/trustgraph/schema/services/llm.py`): + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() +``` + +### Limitações Atuais + +**Latência**: Os usuários devem esperar pela geração completa antes de ver qualquer resultado. +**Risco de Timeout**: Gerações longas podem exceder os limites de tempo de espera do cliente. +**Má Experiência do Usuário**: A falta de feedback durante a geração cria a percepção de lentidão. +**Uso de Recursos**: As respostas completas devem ser armazenadas em memória. + +Esta especificação aborda essas limitações, permitindo a entrega incremental de respostas, mantendo total compatibilidade com versões anteriores. + + +## Design Técnico + +### Fase 1: Infraestrutura + +A Fase 1 estabelece a base para o streaming, modificando esquemas, APIs e ferramentas de linha de comando. + + +#### Alterações no Esquema + +##### Esquema LLM (`trustgraph-base/trustgraph/schema/services/llm.py`) + +**Alterações na Requisição:** + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() # NEW: Default false for backward compatibility +``` + +`streaming`: Quando `true`, solicita a entrega de resposta em fluxo. +Padrão: `false` (o comportamento existente é preservado). + +**Alterações na Resposta:** + +```python +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +`end_of_stream`: Quando `true`, indica que esta é a resposta final (ou única). +Para solicitações não em fluxo contínuo: Resposta única com `end_of_stream=true`. +Para solicitações em fluxo contínuo: Múltiplas respostas, todas com `end_of_stream=false` + exceto a última. + +##### Esquema do Prompt (`trustgraph-base/trustgraph/schema/services/prompt.py`) + +O serviço de prompt envolve a conclusão de texto, portanto, ele segue o mesmo padrão: + +**Alterações na Solicitação:** + +```python +class PromptRequest(Record): + id = String() + terms = Map(String()) + streaming = Boolean() # NEW: Default false +``` + +**Alterações na Resposta:** + +```python +class PromptResponse(Record): + error = Error() + text = String() + object = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +#### Alterações na API Gateway + +A API Gateway deve expor capacidades de streaming para clientes HTTP/WebSocket. + +**Atualizações da API REST:** + +`POST /api/v1/text-completion`: Aceitar o parâmetro `streaming` no corpo da requisição +O comportamento da resposta depende da flag de streaming: + `streaming=false`: Resposta JSON única (comportamento atual) + `streaming=true`: Fluxo de eventos enviados pelo servidor (SSE) ou mensagens WebSocket + +**Formato da Resposta (Streaming):** + +Cada bloco transmitido segue a mesma estrutura de esquema: +```json +{ + "response": "partial text...", + "end_of_stream": false, + "model": "model-name" +} +``` + +Trecho final: +```json +{ + "response": "final text chunk", + "end_of_stream": true, + "in_token": 150, + "out_token": 500, + "model": "model-name" +} +``` + +#### Alterações na API Python + +A API do cliente Python deve suportar tanto o modo de streaming quanto o modo não-streaming, +mantendo a compatibilidade com versões anteriores. + +**Atualizações do LlmClient** (`trustgraph-base/trustgraph/clients/llm_client.py`): + +```python +class LlmClient(BaseClient): + def request(self, system, prompt, timeout=300, streaming=False): + """ + Non-streaming request (backward compatible). + Returns complete response string. + """ + # Existing behavior when streaming=False + + async def request_stream(self, system, prompt, timeout=300): + """ + Streaming request. + Yields response chunks as they arrive. + """ + # New async generator method +``` + +**Atualizações do PromptClient** (`trustgraph-base/trustgraph/base/prompt_client.py`): + +Padrão semelhante com o parâmetro `streaming` e a variante de gerador assíncrono. + +#### Alterações na Ferramenta de Linha de Comando (CLI) + +**tg-invoke-llm** (`trustgraph-cli/trustgraph/cli/invoke_llm.py`): + +``` +tg-invoke-llm [system] [prompt] [--no-streaming] [-u URL] [-f flow-id] +``` + +Streaming habilitado por padrão para uma melhor experiência de usuário interativa. +A flag `--no-streaming` desabilita o streaming. +Quando o streaming está habilitado: Envie os tokens para a saída padrão (stdout) à medida que chegam. +Quando o streaming não está habilitado: Aguarde a resposta completa e, em seguida, envie. + +**tg-invoke-prompt** (`trustgraph-cli/trustgraph/cli/invoke_prompt.py`): + +``` +tg-invoke-prompt [template-id] [var=value...] [--no-streaming] [-u URL] [-f flow-id] +``` + +Mesmo padrão que `tg-invoke-llm`. + +#### Alterações na Classe Base do Serviço LLM + +**LlmService** (`trustgraph-base/trustgraph/base/llm_service.py`): + +```python +class LlmService(FlowProcessor): + async def on_request(self, msg, consumer, flow): + request = msg.value() + streaming = getattr(request, 'streaming', False) + + if streaming and self.supports_streaming(): + async for chunk in self.generate_content_stream(...): + await self.send_response(chunk, end_of_stream=False) + await self.send_response(final_chunk, end_of_stream=True) + else: + response = await self.generate_content(...) + await self.send_response(response, end_of_stream=True) + + def supports_streaming(self): + """Override in subclass to indicate streaming support.""" + return False + + async def generate_content_stream(self, system, prompt, model, temperature): + """Override in subclass to implement streaming.""" + raise NotImplementedError() +``` + +-- + +### Fase 2: Prova de Conceito do VertexAI + +A Fase 2 implementa o streaming em um único provedor (VertexAI) para validar a +infraestrutura e permitir testes de ponta a ponta. + +#### Implementação do VertexAI + +**Módulo:** `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` + +**Alterações:** + +1. Substituir `supports_streaming()` para retornar `True` +2. Implementar gerador assíncrono `generate_content_stream()` +3. Lidar com modelos Gemini e Claude (via API Anthropic do VertexAI) + +**Streaming do Gemini:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + model_instance = self.get_model(model, temperature) + response = model_instance.generate_content( + [system, prompt], + stream=True # Enable streaming + ) + for chunk in response: + yield LlmChunk( + text=chunk.text, + in_token=None, # Available only in final chunk + out_token=None, + ) + # Final chunk includes token counts from response.usage_metadata +``` + +**Claude (via VertexAI Anthropic) Streaming:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + with self.anthropic_client.messages.stream(...) as stream: + for text in stream.text_stream: + yield LlmChunk(text=text) + # Token counts from stream.get_final_message() +``` + +#### Testes + +Testes unitários para a montagem da resposta em streaming +Testes de integração com o VertexAI (Gemini e Claude) +Testes de ponta a ponta: CLI -> Gateway -> Pulsar -> VertexAI -> de volta +Testes de compatibilidade com versões anteriores: as solicitações não em streaming ainda funcionam + +-- + +### Fase 3: Todos os Provedores de LLM + +A Fase 3 estende o suporte a streaming para todos os provedores de LLM no sistema. + +#### Status de Implementação do Provedor + +Cada provedor deve: +1. **Suporte Completo a Streaming**: Implementar `generate_content_stream()` +2. **Modo de Compatibilidade**: Lidar com a flag `end_of_stream` corretamente + (retornar uma única resposta com `end_of_stream=true`) + +| Provedor | Pacote | Suporte a Streaming | +|----------|---------|-------------------| +| OpenAI | trustgraph-flow | Completo (API de streaming nativa) | +| Claude/Anthropic | trustgraph-flow | Completo (API de streaming nativa) | +| Ollama | trustgraph-flow | Completo (API de streaming nativa) | +| Cohere | trustgraph-flow | Completo (API de streaming nativa) | +| Mistral | trustgraph-flow | Completo (API de streaming nativa) | +| Azure OpenAI | trustgraph-flow | Completo (API de streaming nativa) | +| Google AI Studio | trustgraph-flow | Completo (API de streaming nativa) | +| VertexAI | trustgraph-vertexai | Completo (Fase 2) | +| Bedrock | trustgraph-bedrock | Completo (API de streaming nativa) | +| LM Studio | trustgraph-flow | Completo (compatível com OpenAI) | +| LlamaFile | trustgraph-flow | Completo (compatível com OpenAI) | +| vLLM | trustgraph-flow | Completo (compatível com OpenAI) | +| TGI | trustgraph-flow | A ser definido | +| Azure | trustgraph-flow | A ser definido | + +#### Padrão de Implementação + +Para provedores compatíveis com OpenAI (OpenAI, LM Studio, LlamaFile, vLLM): + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + response = await self.client.chat.completions.create( + model=model, + messages=[ + {"role": "system", "content": system}, + {"role": "user", "content": prompt} + ], + temperature=temperature, + stream=True + ) + async for chunk in response: + if chunk.choices[0].delta.content: + yield LlmChunk(text=chunk.choices[0].delta.content) +``` + +-- + +### Fase 4: API do Agente + +A Fase 4 estende o streaming para a API do Agente. Isso é mais complexo porque a +API do Agente já é inerentemente multi-mensagem (pensamento → ação → observação +→ repetir → resposta final). + +#### Esquema Atual do Agente + +```python +class AgentStep(Record): + thought = String() + action = String() + arguments = Map(String()) + observation = String() + user = String() + +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + +class AgentResponse(Record): + answer = String() + error = Error() + thought = String() + observation = String() +``` + +#### Alterações Propostas no Esquema do Agente + +**Solicitar Alterações:** + +```python +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + streaming = Boolean() # NEW: Default false +``` + +**Alterações na Resposta:** + +O agente produz múltiplos tipos de saída durante seu ciclo de raciocínio: +Pensamentos (raciocínio) +Ações (chamadas de ferramentas) +Observações (resultados das ferramentas) +Resposta (resposta final) +Erros + +Como `chunk_type` identifica o tipo de conteúdo que está sendo enviado, os campos separados +`answer`, `error`, `thought` e `observation` podem ser combinados em +um único campo `content`: + +```python +class AgentResponse(Record): + chunk_type = String() # "thought", "action", "observation", "answer", "error" + content = String() # The actual content (interpretation depends on chunk_type) + end_of_message = Boolean() # Current thought/action/observation/answer is complete + end_of_dialog = Boolean() # Entire agent dialog is complete +``` + +**Semântica dos Campos:** + +`chunk_type`: Indica o tipo de conteúdo presente no campo `content` + `"thought"`: Raciocínio/pensamento do agente + `"action"`: Ferramenta/ação sendo invocada + `"observation"`: Resultado da execução da ferramenta + `"answer"`: Resposta final à pergunta do usuário + `"error"`: Mensagem de erro + +`content`: O conteúdo transmitido, interpretado com base em `chunk_type` + +`end_of_message`: Quando `true`, o tipo de bloco atual está completo + Exemplo: Todos os tokens para o pensamento atual foram enviados + Permite que os clientes saibam quando avançar para a próxima etapa + +`end_of_dialog`: Quando `true`, toda a interação do agente está completa + Esta é a mensagem final no fluxo + +#### Comportamento de Streaming do Agente + +Quando `streaming=true`: + +1. **Streaming de pensamento:** + Múltiplos blocos com `chunk_type="thought"`, `end_of_message=false` + O bloco final do pensamento tem `end_of_message=true` +2. **Notificação de ação:** + Um único bloco com `chunk_type="action"`, `end_of_message=true` +3. **Observação:** + Bloco(s) com `chunk_type="observation"`, o final tem `end_of_message=true` +4. **Repita** as etapas 1-3 enquanto o agente raciocina +5. **Resposta final:** + `chunk_type="answer"` com a resposta final em `content` + O último bloco tem `end_of_message=true`, `end_of_dialog=true` + +**Exemplo de Sequência de Streaming:** + +``` +{chunk_type: "thought", content: "I need to", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " search for...", end_of_message: true, end_of_dialog: false} +{chunk_type: "action", content: "search", end_of_message: true, end_of_dialog: false} +{chunk_type: "observation", content: "Found: ...", end_of_message: true, end_of_dialog: false} +{chunk_type: "thought", content: "Based on this", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " I can answer...", end_of_message: true, end_of_dialog: false} +{chunk_type: "answer", content: "The answer is...", end_of_message: true, end_of_dialog: true} +``` + +Quando `streaming=false`: +Comportamento atual preservado +Resposta única com resposta completa +`end_of_message=true`, `end_of_dialog=true` + +#### Gateway e API Python + +Gateway: Novo endpoint SSE/WebSocket para streaming de agentes +API Python: Novo método gerador assíncrono `agent_stream()` + +-- + +## Considerações de Segurança + +**Nenhuma nova superfície de ataque**: O streaming usa a mesma autenticação/autorização +**Limitação de taxa**: Aplique limites de taxa por token ou por bloco, se necessário +**Gerenciamento de conexão**: Termine corretamente os streams em caso de desconexão do cliente +**Gerenciamento de tempo limite**: As solicitações de streaming precisam de um tratamento de tempo limite adequado + +## Considerações de Desempenho + +**Memória**: O streaming reduz o uso máximo de memória (sem bufferização completa da resposta) +**Latência**: O tempo para o primeiro token é significativamente reduzido +**Sobrecarga de conexão**: As conexões SSE/WebSocket têm uma sobrecarga de keep-alive +**Throughput do Pulsar**: Múltiplas mensagens pequenas vs. uma única mensagem grande + tradeoff + +## Estratégia de Testes + +### Testes Unitários +Serialização/desserialização de esquema com novos campos +Compatibilidade com versões anteriores (campos ausentes usam valores padrão) +Lógica de montagem de blocos + +### Testes de Integração +Implementação de streaming de cada provedor de LLM +Pontos finais de streaming da API Gateway +Métodos de streaming do cliente Python + +### Testes de Ponta a Ponta +Saída de streaming da ferramenta CLI +Fluxo completo: Cliente → Gateway → Pulsar → LLM → de volta +Cargas de trabalho mistas de streaming/não streaming + +### Testes de Compatibilidade com Versões Anteriores +Clientes existentes funcionam sem modificação +As solicitações não de streaming se comportam de forma idêntica + +## Plano de Migração + +### Fase 1: Infraestrutura +Implante as alterações de esquema (compatível com versões anteriores) +Implante as atualizações da API Gateway +Implante as atualizações da API Python +Lance as atualizações da ferramenta CLI + +### Fase 2: VertexAI +Implementar a implementação de streaming do VertexAI +Validar com cargas de trabalho de teste + +### Fase 3: Todos os Provedores +Implementar as atualizações do provedor de forma incremental +Monitorar para identificar problemas + +### Fase 4: API do Agente +Implementar as alterações do esquema do agente +Implementar a implementação de streaming do agente +Atualizar a documentação + +## Cronograma + +| Fase | Descrição | Dependências | +|-------|-------------|--------------| +| Fase 1 | Infraestrutura | Nenhum | +| Fase 2 | Prova de Conceito do VertexAI | Fase 1 | +| Fase 3 | Todos os Provedores | Fase 2 | +| Fase 4 | API do Agente | Fase 3 | + +## Decisões de Design + +As seguintes perguntas foram resolvidas durante a especificação: + +1. **Contagem de Tokens no Streaming**: As contagens de tokens são diferenças, não totais cumulativos. + Os consumidores podem somá-las, se necessário. Isso corresponde à forma como a maioria dos provedores relata + o uso e simplifica a implementação. + +2. **Tratamento de Erros em Streams**: Se ocorrer um erro, o campo `error` é + preenchido e nenhum outro campo é necessário. Um erro é sempre a comunicação final - nenhuma mensagem subsequente é permitida ou esperada após + isso. + um erro. Para fluxos de LLM/Prompt, `end_of_stream=true`. Para fluxos de Agente, + `chunk_type="error"` com `end_of_dialog=true`. + +3. **Recuperação Parcial de Respostas**: O protocolo de mensagens (Pulsar) é resiliente, + portanto, a repetição em nível de mensagem não é necessária. Se um cliente perder o controle do fluxo + ou desconectar, ele deve repetir a solicitação completa do zero. + +4. **Streaming de Respostas Rápidas**: O streaming é suportado apenas para respostas de texto (`text`). + As respostas estruturadas (`object`) não são suportadas. O serviço de respostas rápidas sabe, + desde o início, se a saída será JSON ou texto, com base no modelo da solicitação. Se + uma solicitação de streaming for feita para uma solicitação de saída JSON, o + serviço deve: + Retornar o JSON completo em uma única resposta com `end_of_stream=true`, ou + Rejeitar a solicitação de streaming com um erro. + +## Perguntas Abertas + +Nenhum neste momento. + +## Referências + +Esquema atual do LLM: `trustgraph-base/trustgraph/schema/services/llm.py` +Esquema atual do prompt: `trustgraph-base/trustgraph/schema/services/prompt.py` +Esquema atual do agente: `trustgraph-base/trustgraph/schema/services/agent.py` +Serviço base do LLM: `trustgraph-base/trustgraph/base/llm_service.py` +Provedor VertexAI: `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` +API de gateway: `trustgraph-base/trustgraph/api/` +Ferramentas de linha de comando: `trustgraph-cli/trustgraph/cli/` diff --git a/docs/tech-specs/streaming-llm-responses.ru.md b/docs/tech-specs/streaming-llm-responses.ru.md new file mode 100644 index 00000000..202935c2 --- /dev/null +++ b/docs/tech-specs/streaming-llm-responses.ru.md @@ -0,0 +1,570 @@ +# Техническая спецификация потоковой передачи ответов LLM + +## Обзор + +Эта спецификация описывает реализацию поддержки потоковой передачи для ответов LLM +в TrustGraph. Потоковая передача обеспечивает доставку сгенерированных +токенов в режиме реального времени по мере их создания LLM, а не после +завершения полной генерации ответа. + +Эта реализация поддерживает следующие сценарии использования: + +1. **Интерфейсы пользователя в реальном времени**: Передавайте токены в пользовательский интерфейс по мере их генерации, + обеспечивая немедленную визуальную обратную связь. +2. **Сокращение времени до первого токена**: Пользователи видят вывод сразу, + а не после полной генерации. +3. **Обработка очень длинных ответов**: Обрабатывайте очень длинные ответы, которые в противном случае + могли бы привести к таймаутам или превышению лимитов памяти. +4. **Интерактивные приложения**: Обеспечьте отзывчивые чат-интерфейсы и интерфейсы агентов. + +## Цели + +**Обратная совместимость**: Существующие клиенты, не использующие потоковую передачу, продолжают работать + без изменений. +**Согласованный дизайн API**: Потоковая передача и не потоковая передача используют одни и те же схемы + с минимальными отклонениями. +**Гибкость для поставщиков**: Поддержка потоковой передачи, где это возможно, и плавный + переход к не потоковой передаче, где это невозможно. +**Поэтапное внедрение**: Постепенная реализация для снижения рисков. +**Комплексная поддержка**: Потоковая передача от поставщика LLM до клиентских + приложений через Pulsar, Gateway API и Python API. + +## Обзор + +### Текущая архитектура + +Текущий процесс текстового завершения LLM работает следующим образом: + +1. Клиент отправляет `TextCompletionRequest` с полями `system` и `prompt`. +2. Сервис LLM обрабатывает запрос и ожидает полной генерации. +3. Возвращается один `TextCompletionResponse` с полной строкой `response`. + +Текущая схема (`trustgraph-base/trustgraph/schema/services/llm.py`): + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() +``` + +### Текущие ограничения + +**Задержка**: Пользователи должны ждать завершения генерации, прежде чем увидеть какой-либо результат. +**Риск превышения времени ожидания**: Длительная генерация может превысить лимиты времени ожидания клиента. +**Плохой пользовательский опыт**: Отсутствие обратной связи во время генерации создает ощущение медленной работы. +**Использование ресурсов**: Полные ответы должны быть буферизованы в памяти. + +Эта спецификация решает эти ограничения, обеспечивая постепенную передачу ответа, при этом сохраняя полную обратную совместимость. + + +## Техническое проектирование + +### Фаза 1: Инфраструктура + +Фаза 1 закладывает основу для потоковой передачи путем изменения схем, API и инструментов командной строки. + + +#### Изменения в схемах + +##### Схема LLM (`trustgraph-base/trustgraph/schema/services/llm.py`) + +**Изменения в запросах:** + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() # NEW: Default false for backward compatibility +``` + +`streaming`: Когда `true`, запрашивается потоковая доставка ответа. +По умолчанию: `false` (сохранено существующее поведение). + +**Изменения в ответе:** + +```python +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +`end_of_stream`: Когда `true`, указывает на то, что это окончательный (или единственный) ответ. +Для нестриминговых запросов: Один ответ с `end_of_stream=true`. +Для стриминговых запросов: Множественные ответы, все с `end_of_stream=false`, + за исключением последнего. + +##### Схема запроса (`trustgraph-base/trustgraph/schema/services/prompt.py`) + +Сервис запросов оборачивает завершение текста, поэтому он следует той же схеме: + +**Изменения в запросе:** + +```python +class PromptRequest(Record): + id = String() + terms = Map(String()) + streaming = Boolean() # NEW: Default false +``` + +**Изменения в ответе:** + +```python +class PromptResponse(Record): + error = Error() + text = String() + object = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +#### Изменения API шлюза + +API шлюз должен предоставлять возможности потоковой передачи данных для клиентов HTTP/WebSocket. + +**Обновления REST API:** + +`POST /api/v1/text-completion`: Принимать параметр `streaming` в теле запроса +Поведение ответа зависит от флага потоковой передачи: + `streaming=false`: Одиночный ответ в формате JSON (текущее поведение) + `streaming=true`: Поток событий от сервера (SSE) или сообщения WebSocket + +**Формат ответа (потоковая передача):** + +Каждый фрагмент, передаваемый потоком, имеет одинаковую структуру схемы: +```json +{ + "response": "partial text...", + "end_of_stream": false, + "model": "model-name" +} +``` + +Заключительный раздел: +```json +{ + "response": "final text chunk", + "end_of_stream": true, + "in_token": 150, + "out_token": 500, + "model": "model-name" +} +``` + +#### Изменения в API Python + +API клиента Python должен поддерживать как потоковый, так и не потоковый режимы, +при этом сохраняя обратную совместимость. + +**Обновления LlmClient** (`trustgraph-base/trustgraph/clients/llm_client.py`): + +```python +class LlmClient(BaseClient): + def request(self, system, prompt, timeout=300, streaming=False): + """ + Non-streaming request (backward compatible). + Returns complete response string. + """ + # Existing behavior when streaming=False + + async def request_stream(self, system, prompt, timeout=300): + """ + Streaming request. + Yields response chunks as they arrive. + """ + # New async generator method +``` + +**Обновления PromptClient** (`trustgraph-base/trustgraph/base/prompt_client.py`): + +Аналогичный шаблон с параметром `streaming` и вариантом асинхронного генератора. + +#### Изменения инструмента командной строки + +**tg-invoke-llm** (`trustgraph-cli/trustgraph/cli/invoke_llm.py`): + +``` +tg-invoke-llm [system] [prompt] [--no-streaming] [-u URL] [-f flow-id] +``` + +По умолчанию включен режим потоковой передачи для улучшения интерактивного пользовательского опыта. +Флаг `--no-streaming` отключает режим потоковой передачи. +В режиме потоковой передачи: выводите токены в стандартный вывод по мере их поступления. +В режиме, когда потоковая передача отключена: дождитесь получения полного ответа, а затем выведите его. + +**tg-invoke-prompt** (`trustgraph-cli/trustgraph/cli/invoke_prompt.py`): + +``` +tg-invoke-prompt [template-id] [var=value...] [--no-streaming] [-u URL] [-f flow-id] +``` + +Такой же шаблон, как у `tg-invoke-llm`. + +#### Изменения базового класса LLM Service. + +**LlmService** (`trustgraph-base/trustgraph/base/llm_service.py`): + +```python +class LlmService(FlowProcessor): + async def on_request(self, msg, consumer, flow): + request = msg.value() + streaming = getattr(request, 'streaming', False) + + if streaming and self.supports_streaming(): + async for chunk in self.generate_content_stream(...): + await self.send_response(chunk, end_of_stream=False) + await self.send_response(final_chunk, end_of_stream=True) + else: + response = await self.generate_content(...) + await self.send_response(response, end_of_stream=True) + + def supports_streaming(self): + """Override in subclass to indicate streaming support.""" + return False + + async def generate_content_stream(self, system, prompt, model, temperature): + """Override in subclass to implement streaming.""" + raise NotImplementedError() +``` + +-- + +### Фаза 2: Проверка концепции VertexAI + +Фаза 2 реализует потоковую передачу данных в одном провайдере (VertexAI) для проверки +инфраструктуры и обеспечения сквозного тестирования. + +#### Реализация VertexAI + +**Модуль:** `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` + +**Изменения:** + +1. Переопределить `supports_streaming()` для возврата `True` +2. Реализовать асинхронный генератор `generate_content_stream()` +3. Поддержка моделей Gemini и Claude (через VertexAI Anthropic API) + +**Потоковая передача данных Gemini:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + model_instance = self.get_model(model, temperature) + response = model_instance.generate_content( + [system, prompt], + stream=True # Enable streaming + ) + for chunk in response: + yield LlmChunk( + text=chunk.text, + in_token=None, # Available only in final chunk + out_token=None, + ) + # Final chunk includes token counts from response.usage_metadata +``` + +**Claude (через VertexAI Anthropic) в режиме потоковой передачи:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + with self.anthropic_client.messages.stream(...) as stream: + for text in stream.text_stream: + yield LlmChunk(text=text) + # Token counts from stream.get_final_message() +``` + +#### Тестирование + +Юнит-тесты для сборки потоковых ответов +Интеграционные тесты с VertexAI (Gemini и Claude) +Комплексные тесты: CLI -> Gateway -> Pulsar -> VertexAI -> back +Тесты обратной совместимости: Непотоковые запросы по-прежнему работают + +-- + +### Фаза 3: Все провайдеры LLM + +Фаза 3 расширяет поддержку потоковой передачи для всех провайдеров LLM в системе. + +#### Статус реализации для каждого провайдера + +Каждый провайдер должен либо: +1. **Полная поддержка потоковой передачи**: Реализовать `generate_content_stream()` +2. **Режим совместимости**: Правильно обрабатывать флаг `end_of_stream` + (возвращать единый ответ с `end_of_stream=true`) + +| Провайдер | Пакет | Поддержка потоковой передачи | +|----------|---------|-------------------| +| OpenAI | trustgraph-flow | Полная (нативная API потоковой передачи) | +| Claude/Anthropic | trustgraph-flow | Полная (нативная API потоковой передачи) | +| Ollama | trustgraph-flow | Полная (нативная API потоковой передачи) | +| Cohere | trustgraph-flow | Полная (нативная API потоковой передачи) | +| Mistral | trustgraph-flow | Полная (нативная API потоковой передачи) | +| Azure OpenAI | trustgraph-flow | Полная (нативная API потоковой передачи) | +| Google AI Studio | trustgraph-flow | Полная (нативная API потоковой передачи) | +| VertexAI | trustgraph-vertexai | Полная (Фаза 2) | +| Bedrock | trustgraph-bedrock | Полная (нативная API потоковой передачи) | +| LM Studio | trustgraph-flow | Полная (совместима с OpenAI) | +| LlamaFile | trustgraph-flow | Полная (совместима с OpenAI) | +| vLLM | trustgraph-flow | Полная (совместима с OpenAI) | +| TGI | trustgraph-flow | Будет определено | +| Azure | trustgraph-flow | Будет определено | + +#### Шаблон реализации + +Для провайдеров, совместимых с OpenAI (OpenAI, LM Studio, LlamaFile, vLLM): + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + response = await self.client.chat.completions.create( + model=model, + messages=[ + {"role": "system", "content": system}, + {"role": "user", "content": prompt} + ], + temperature=temperature, + stream=True + ) + async for chunk in response: + if chunk.choices[0].delta.content: + yield LlmChunk(text=chunk.choices[0].delta.content) +``` + +-- + +### Фаза 4: API агента + +Фаза 4 расширяет потоковую передачу на API агента. Это более сложный процесс, поскольку +API агента изначально предназначен для работы с несколькими сообщениями (мысль → действие → наблюдение +→ повтор → окончательный ответ). + +#### Текущая схема агента + +```python +class AgentStep(Record): + thought = String() + action = String() + arguments = Map(String()) + observation = String() + user = String() + +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + +class AgentResponse(Record): + answer = String() + error = Error() + thought = String() + observation = String() +``` + +#### Предлагаемые изменения схемы агента + +**Запрос изменений:** + +```python +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + streaming = Boolean() # NEW: Default false +``` + +**Изменения в ответах:** + +Агент генерирует несколько типов выходных данных в процессе рассуждения: +Мысли (рассуждения) +Действия (вызовы инструментов) +Наблюдения (результаты работы инструментов) +Ответ (окончательный ответ) +Ошибки + +Поскольку `chunk_type` указывает на тип передаваемого контента, отдельные +поля `answer`, `error`, `thought` и `observation` можно объединить в +одно поле `content`: + +```python +class AgentResponse(Record): + chunk_type = String() # "thought", "action", "observation", "answer", "error" + content = String() # The actual content (interpretation depends on chunk_type) + end_of_message = Boolean() # Current thought/action/observation/answer is complete + end_of_dialog = Boolean() # Entire agent dialog is complete +``` + +**Семантика полей:** + +`chunk_type`: Указывает, какой тип содержимого находится в поле `content` + `"thought"`: Рассуждения/мысли агента + `"action"`: Используемый инструмент/действие + `"observation"`: Результат выполнения инструмента + `"answer"`: Окончательный ответ на вопрос пользователя + `"error"`: Сообщение об ошибке + +`content`: Фактическое потоковое содержимое, интерпретируемое на основе `chunk_type` + +`end_of_message`: Когда `true`, текущий тип фрагмента завершен + Пример: Все токены для текущей мысли были отправлены + Позволяет клиентам знать, когда переходить к следующему этапу + +`end_of_dialog`: Когда `true`, все взаимодействие с агентом завершено + Это последнее сообщение в потоке + +#### Поведение потоковой передачи агента + +Когда `streaming=true`: + +1. **Потоковая передача мыслей:** + Несколько фрагментов с `chunk_type="thought"`, `end_of_message=false` + Последний фрагмент мысли содержит `end_of_message=true` +2. **Уведомление о действии:** + Один фрагмент с `chunk_type="action"`, `end_of_message=true` +3. **Наблюдение:** + Один или несколько фрагментов с `chunk_type="observation"`, последний содержит `end_of_message=true` +4. **Повторяйте** шаги 1-3, пока агент рассуждает +5. **Окончательный ответ:** + `chunk_type="answer"` с окончательным ответом в `content` + Последний фрагмент содержит `end_of_message=true`, `end_of_dialog=true` + +**Пример последовательности потоковой передачи:** + +``` +{chunk_type: "thought", content: "I need to", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " search for...", end_of_message: true, end_of_dialog: false} +{chunk_type: "action", content: "search", end_of_message: true, end_of_dialog: false} +{chunk_type: "observation", content: "Found: ...", end_of_message: true, end_of_dialog: false} +{chunk_type: "thought", content: "Based on this", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " I can answer...", end_of_message: true, end_of_dialog: false} +{chunk_type: "answer", content: "The answer is...", end_of_message: true, end_of_dialog: true} +``` + +Когда `streaming=false`: +Текущее поведение сохранено +Единый ответ с полным ответом +`end_of_message=true`, `end_of_dialog=true` + +#### Шлюз и Python API + +Шлюз: Новый SSE/WebSocket endpoint для потоковой передачи данных от агента +Python API: Новый асинхронный генератор `agent_stream()` + +-- + +## Соображения безопасности + +**Отсутствие новых уязвимостей**: Потоковая передача использует ту же аутентификацию/авторизацию +**Ограничение скорости**: При необходимости применяйте ограничения скорости на токен или на фрагмент +**Обработка соединений**: Правильно завершайте потоки при отключении клиента +**Управление временем ожидания**: Запросы потоковой передачи требуют соответствующей обработки времени ожидания + +## Соображения производительности + +**Память**: Потоковая передача снижает пиковое использование памяти (без полной буферизации ответа) +**Задержка**: Время до первого токена значительно сокращено +**Накладные расходы на соединение**: Соединения SSE/WebSocket имеют накладные расходы на поддержание соединения +**Производительность Pulsar**: Несколько небольших сообщений против одного большого сообщения - компромисс + tradeoff + +## Стратегия тестирования + +### Юнит-тесты +Сериализация/десериализация схемы с новыми полями +Обратная совместимость (отсутствующие поля используют значения по умолчанию) +Логика сборки фрагментов + +### Интеграционные тесты +Реализация потоковой передачи каждого поставщика LLM +Потоковые конечные точки API шлюза +Методы потоковой передачи клиента на Python + +### Комплексные тесты +Вывод потоковой передачи инструмента командной строки +Полный поток: Клиент → Шлюз → Pulsar → LLM → обратно +Смешанные потоковые и не потоковые рабочие нагрузки + +### Тесты обратной совместимости +Существующие клиенты работают без изменений +Запросы без потоковой передачи ведут себя идентично + +## План миграции + +### Фаза 1: Инфраструктура +Развертывание изменений схемы (обратная совместимость) +Развертывание обновлений API шлюза +Развертывание обновлений Python API +Выпуск обновлений инструмента командной строки + +### Фаза 2: VertexAI +Развернуть поточную реализацию VertexAI. +Проверить с помощью тестовых нагрузок. + +### Фаза 3: Все провайдеры +Постепенно внедрять обновления для провайдеров. +Отслеживать наличие проблем. + +### Фаза 4: API агента +Развернуть изменения схемы агента. +Развернуть поточную реализацию агента. +Обновить документацию. + +## График + +| Фаза | Описание | Зависимости | +|-------|-------------|--------------| +| Фаза 1 | Инфраструктура | Отсутствуют | +| Фаза 2 | VertexAI, пилотный проект | Фаза 1 | +| Фаза 3 | Все провайдеры | Фаза 2 | +| Фаза 4 | API агента | Фаза 3 | + +## Принятые решения по проектированию + +В процессе разработки спецификации были решены следующие вопросы: + +1. **Количество токенов в потоке**: Количество токенов указывается как разница, а не как текущая сумма. + Потребители могут суммировать их, если это необходимо. Это соответствует тому, как большинство провайдеров + сообщают об использовании и упрощает реализацию. + +2. **Обработка ошибок в потоках**: В случае возникновения ошибки, поле `error` + заполняется, и другие поля не требуются. Ошибка всегда является последним + сообщением - после ошибки не допускаются и не ожидаются последующие сообщения. + Для потоков LLM/Prompt: `end_of_stream=true`. Для потоков Agent: + `chunk_type="error"` с `end_of_dialog=true`. + +3. **Восстановление после частичного ответа**: Протокол обмена сообщениями (Pulsar) устойчив, + поэтому повторная отправка сообщений на уровне отдельных сообщений не требуется. + Если клиент теряет отслеживание потока или отключается, он должен повторить +полный запрос с самого начала. +4. **Быстрая потоковая передача**: Потоковая передача поддерживается только для текстовых ответов (`text`). + ответы, а не для структурированных (`object`) ответов. Сервис запросов знает заранее, + будет ли вывод в формате JSON или текста, в зависимости от шаблона запроса. Если + выполняется запрос на потоковую передачу для запроса, предназначенного для вывода JSON, + сервис должен либо: + Вернуть полный JSON в одном ответе с `end_of_stream=true`, или + Отклонить запрос на потоковую передачу с ошибкой. + +## Открытые вопросы + +На данный момент их нет. + +## Ссылки + +Текущая схема LLM: `trustgraph-base/trustgraph/schema/services/llm.py` +Текущая схема запросов: `trustgraph-base/trustgraph/schema/services/prompt.py` +Текущая схема агента: `trustgraph-base/trustgraph/schema/services/agent.py` +Базовый URL службы LLM: `trustgraph-base/trustgraph/base/llm_service.py` +Провайдер VertexAI: `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` +API шлюза: `trustgraph-base/trustgraph/api/` +Инструменты CLI: `trustgraph-cli/trustgraph/cli/` diff --git a/docs/tech-specs/streaming-llm-responses.sw.md b/docs/tech-specs/streaming-llm-responses.sw.md new file mode 100644 index 00000000..654ae8b7 --- /dev/null +++ b/docs/tech-specs/streaming-llm-responses.sw.md @@ -0,0 +1,570 @@ +# Vigezo vya Kiufundi vya Utoaji wa Majibu ya LLM kwa Kutiririsha + +## Muhtasari + +Vigezo hivi vinaelezea utekelezaji wa msaada wa utiririshaji kwa majibu ya LLM +katika TrustGraph. Utiririshaji unawezesha utoaji wa wakati halisi wa alama (tokens) +zinazozalishwa na LLM, badala ya kusubiri hadi majibu kamili yatengenezwe. + + +Utendaji huu unaunga mkono matumizi yafuatayo: + +1. **Mawasiliano ya Mtumiaji ya Kawaida**: Tuma alama kwenye UI wakati zinaozalishwa, + huku ukitoa maoni ya kuonekana mara moja. +2. **Punguuzo la Muda wa Alama ya Kwanza**: Watumiaji huona matokeo mara moja + badala ya kusubiri hadi utengenezaji kamili utimalike. +3. **Usimamizi wa Majibu Marefu**: Shirikisha matokeo marefu sana ambayo vinginevyo + yanaweza kusababisha kukatika au kuzidi mipaka ya kumbukumbu. +4. **Matumizi Tendo**: Wezesha mawasiliano na mawakala yenye majibu. + +## Lengo + +**Ulinganishaji na Mifumo ya Zamani**: Wateja wa zamani ambao hawatumiwi teknolojia ya utiririshaji wanaendelea kufanya kazi + bila mabadiliko. +**Muundo wa API Unaofuata Kanuni**: Utiririshaji na mfumo ambao hautiririshi hutumia muundo sawa + na tofauti ndogo. +**Uwezo wa Mtoa Huduma**: Kusaidia utiririshaji pale unapopatikana, na + utaratibu wa kurejesha pale unapokosekana. +**Utekelezaji Hatua kwa Hatua**: Utaratibu wa kutekeleza hatua kwa hatua ili kupunguza hatari. +**Usaidizi Kamili**: Utiririshaji kutoka kwa mtoa huduma wa LLM hadi kwa programu + za mteja kupitia Pulsar, Gateway API, na Python API. + +## Asili + +### Muundo wa Sasa + +Mchakato wa sasa wa kukamilisha maandishi wa LLM unafanya kazi kama ifuatavyo: + +1. Mteja hutuma `TextCompletionRequest` pamoja na sehemu za `system` na `prompt`. +2. Huduma ya LLM huchakata ombi na kusubiri uzalishaji kamili. +3. `TextCompletionResponse` moja inarejeshwa pamoja na `response` kamili. + +Muundo wa sasa (`trustgraph-base/trustgraph/schema/services/llm.py`): + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() +``` + +### Marekebisho ya Sasa + +**Ucheleweshaji**: Watumiaji lazima wasubiri hadi utengenezaji kukamilika kabisa kabla ya kuona matokeo yoyote. +**Hatari ya Muda wa Kufikia (Timeout)**: Utengenezaji mrefu unaweza kuzidi mipaka ya muda wa kufikia ya mteja. +**Uzoefu duni wa mtumiaji (UX)**: Hakuna maelezo wakati wa utengenezaji huunda hisia ya utaratibu polepole. +**Matumizi ya Rasilimali**: Majibu kamili lazima yakahifadhiwe katika kumbukumbu. + +Maelekezo haya yanashughulikia mapungufu haya kwa kuwezesha utoaji wa majibu kwa hatua, +huku ikiendelea kudumisha utangamano kamili wa zamani. + +## Muundo wa Kiufundi + +### Awamu ya 1: Miundombinu + +Awamu ya 1 huunda msingi wa utiririshaji kwa kufanya mabadiliko katika muundo, API, +na zana za CLI. + +#### Mabadiliko ya Muundo + +##### Muundo wa LLM (`trustgraph-base/trustgraph/schema/services/llm.py`) + +**Mabadiliko ya Ombi:** + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() # NEW: Default false for backward compatibility +``` + +`streaming`: Wakati `true`, huomba utoaji wa majibu kwa njia ya mtiririko. +Chaguya: `false` (tabia iliyopo inahifadhiwa). + +**Mabadiliko ya Majibu:** + +```python +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +`end_of_stream`: Wakati `true`, inaonyesha kwamba hii ndiyo jibu la mwisho (au pekee). +Kwa ombi lisilo la utiririshaji: Jibu moja na `end_of_stream=true`. +Kwa ombi la utiririshaji: Majibu mengi, yote na `end_of_stream=false`. + isipokuwa jibu la mwisho. + +##### Muundo wa Ombi (`trustgraph-base/trustgraph/schema/services/prompt.py`) + +Huduma ya ombi inajumuisha kukamilisha maandishi, kwa hivyo inafuata muundo sawa: + +**Mabadiliko ya Ombi:** + +```python +class PromptRequest(Record): + id = String() + terms = Map(String()) + streaming = Boolean() # NEW: Default false +``` + +**Mabadiliko ya Majibu:** + +```python +class PromptResponse(Record): + error = Error() + text = String() + object = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +#### Mabadiliko ya API ya Langara + +API ya Langara lazima iweze kuonyesha uwezo wa utiririshaji kwa wateja wa HTTP/WebSocket. + +**Sasisho za API ya REST:** + +`POST /api/v1/text-completion`: Kukubali parameter `streaming` katika mwili wa ombi +Tabia ya majibu inategemea bendera ya utiririshaji: + `streaming=false`: Jibu moja la JSON (tabia ya sasa) + `streaming=true`: Mto wa Matukio Yanayotumwa na Server (SSE) au ujumbe wa WebSocket + +**Muundo wa Majibu (Utiririshaji):** + +Kila sehemu iliyoyirishwa ifuataye muundo sawa: +```json +{ + "response": "partial text...", + "end_of_stream": false, + "model": "model-name" +} +``` + +Sehemu ya mwisho: +```json +{ + "response": "final text chunk", + "end_of_stream": true, + "in_token": 150, + "out_token": 500, + "model": "model-name" +} +``` + +#### Mabadiliko ya API ya Python + +API ya mteja wa Python lazima iunge mkono njia zote mbili za utiririshaji na zisizo za utiririshaji +huku ikiendelea kutoa utangamano na matoleo ya awali. + +**Sasisho za LlmClient** (`trustgraph-base/trustgraph/clients/llm_client.py`): + +```python +class LlmClient(BaseClient): + def request(self, system, prompt, timeout=300, streaming=False): + """ + Non-streaming request (backward compatible). + Returns complete response string. + """ + # Existing behavior when streaming=False + + async def request_stream(self, system, prompt, timeout=300): + """ + Streaming request. + Yields response chunks as they arrive. + """ + # New async generator method +``` + +**Sasisho za PromptClient** (`trustgraph-base/trustgraph/base/prompt_client.py`): + +Mfumo sawa na parameter ya `streaming` na toleo la jenereta isiyo na usumbufu. + +#### Mabadiliko ya Zana ya CLI + +**tg-invoke-llm** (`trustgraph-cli/trustgraph/cli/invoke_llm.py`): + +``` +tg-invoke-llm [system] [prompt] [--no-streaming] [-u URL] [-f flow-id] +``` + +Uhamishaji (streaming) huwezeshwa kwa chagu kuendana na uzoefu bora wa mtumiaji. +Bendera `--no-streaming` inazuia uhamishaji. +Wakati uhamishaji unafanya kazi: Tuma alama (tokens) kwenye stdout kadri zinavyofika. +Wakati uhamishaji haufanyi kazi: Subiri jibu kamili, kisha toa. + +**tg-invoke-prompt** (`trustgraph-cli/trustgraph/cli/invoke_prompt.py`): + +``` +tg-invoke-prompt [template-id] [var=value...] [--no-streaming] [-u URL] [-f flow-id] +``` + +Mfumo sawa na `tg-invoke-llm`. + +#### Mabadiliko ya Darasa Msingi la Huduma ya LLM. + +**LlmService** (`trustgraph-base/trustgraph/base/llm_service.py`): + +```python +class LlmService(FlowProcessor): + async def on_request(self, msg, consumer, flow): + request = msg.value() + streaming = getattr(request, 'streaming', False) + + if streaming and self.supports_streaming(): + async for chunk in self.generate_content_stream(...): + await self.send_response(chunk, end_of_stream=False) + await self.send_response(final_chunk, end_of_stream=True) + else: + response = await self.generate_content(...) + await self.send_response(response, end_of_stream=True) + + def supports_streaming(self): + """Override in subclass to indicate streaming support.""" + return False + + async def generate_content_stream(self, system, prompt, model, temperature): + """Override in subclass to implement streaming.""" + raise NotImplementedError() +``` + +-- + +### Awamu ya 2: Uthibitisho wa Dhana wa VertexAI + +Awamu ya 2 inatekeleza utiririshaji katika mtoa huduma mmoja (VertexAI) ili kuthibitisha +miundombinu na kuwezesha majaribio ya mwisho hadi mwisho. + +#### Utendaji wa VertexAI + +**Moduli:** `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` + +**Mabadiliko:** + +1. Badilisha `supports_streaming()` ili irudishe `True` +2. Leta mtayarishaji wa async `generate_content_stream()` +3. Shiriki modeli zote za Gemini na Claude (kupitia API ya VertexAI Anthropic) + +**Utiririshaji wa Gemini:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + model_instance = self.get_model(model, temperature) + response = model_instance.generate_content( + [system, prompt], + stream=True # Enable streaming + ) + for chunk in response: + yield LlmChunk( + text=chunk.text, + in_token=None, # Available only in final chunk + out_token=None, + ) + # Final chunk includes token counts from response.usage_metadata +``` + +**Claude (kupitia VertexAI Anthropic) Uhamishaji wa Data:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + with self.anthropic_client.messages.stream(...) as stream: + for text in stream.text_stream: + yield LlmChunk(text=text) + # Token counts from stream.get_final_message() +``` + +#### Mtihani + +Majaribio ya kitengo kwa ajili ya kusanyiko la majibu ya utiririshaji +Majaribio ya ujumuishaji na VertexAI (Gemini na Claude) +Majaribio kamili: CLI -> Gateway -> Pulsar -> VertexAI -> nyuma +Majaribio ya utangamano: Maombi ya isiyo ya utiririshaji bado hufanya kazi + +-- + +### Awamu ya 3: Watoa Huduma Wote wa LLM + +Awamu ya 3 inaongeza utiifu wa utiririshaji kwa watoa huduma wote wa LLM katika mfumo. + +#### Hali ya Utumiaji wa Mtoa Huduma + +Kila mtoa huduma lazima ifanye mojawapo ya yafuatayo: +1. **Utiifu Kamili wa Utiririshaji**: Tengeneza `generate_content_stream()` +2. **Njia ya Utangamano**: Shikilia bendera ya `end_of_stream` kwa usahihi + (irudishe jibu moja na `end_of_stream=true`) + +| Mtoa Huduma | Kifurushi | Utiifu wa Utiririshaji | +|----------|---------|-------------------| +| OpenAI | trustgraph-flow | Kamili (API ya asili ya utiririshaji) | +| Claude/Anthropic | trustgraph-flow | Kamili (API ya asili ya utiririshaji) | +| Ollama | trustgraph-flow | Kamili (API ya asili ya utiririshaji) | +| Cohere | trustgraph-flow | Kamili (API ya asili ya utiririshaji) | +| Mistral | trustgraph-flow | Kamili (API ya asili ya utiririshaji) | +| Azure OpenAI | trustgraph-flow | Kamili (API ya asili ya utiririshaji) | +| Google AI Studio | trustgraph-flow | Kamili (API ya asili ya utiririshaji) | +| VertexAI | trustgraph-vertexai | Kamili (Awamu ya 2) | +| Bedrock | trustgraph-bedrock | Kamili (API ya asili ya utiririshaji) | +| LM Studio | trustgraph-flow | Kamili (Inafaa na OpenAI) | +| LlamaFile | trustgraph-flow | Kamili (Inafaa na OpenAI) | +| vLLM | trustgraph-flow | Kamili (Inafaa na OpenAI) | +| TGI | trustgraph-flow | Itatolewa baadaye | +| Azure | trustgraph-flow | Itatolewa baadaye | + +#### Mfumo wa Utumiaji + +Kwa watoa huduma wanaofaa na OpenAI (OpenAI, LM Studio, LlamaFile, vLLM): + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + response = await self.client.chat.completions.create( + model=model, + messages=[ + {"role": "system", "content": system}, + {"role": "user", "content": prompt} + ], + temperature=temperature, + stream=True + ) + async for chunk in response: + if chunk.choices[0].delta.content: + yield LlmChunk(text=chunk.choices[0].delta.content) +``` + +-- + +### Awamu ya 4: API ya Wakala + +Awamu ya 4 inaongeza utiririshaji kwenye API ya Wakala. Hii ni ngumu zaidi kwa sababu +API ya Wakala tayari ni mfumo wa ujumbe mwingi (fikra → kitendo → uchunguzi +→ rudia → jibu la mwisho). + +#### Mpango wa Sasa wa Wakala + +```python +class AgentStep(Record): + thought = String() + action = String() + arguments = Map(String()) + observation = String() + user = String() + +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + +class AgentResponse(Record): + answer = String() + error = Error() + thought = String() + observation = String() +``` + +#### Mabadiliko Yanayopendekezwa ya Muundo wa Wakala + +**Omba Mabadiliko:** + +```python +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + streaming = Boolean() # NEW: Default false +``` + +**Mabadiliko ya Majibu:** + +Wakala hutengeneza aina nyingi za matokeo wakati wa mchakato wake wa kufikiri: +Mawazo (ufikiri) +Vitendo (simu za zana) +Uchunguzi (matokeo ya zana) +Jibu (jibu la mwisho) +Madosa + +Kwa kuwa `chunk_type` inaonyesha aina gani ya maudhui yanatumiwa, nafasi tofauti +za `answer`, `error`, `thought`, na `observation` zinaweza kuunganishwa katika +nafasi moja ya `content`: + +```python +class AgentResponse(Record): + chunk_type = String() # "thought", "action", "observation", "answer", "error" + content = String() # The actual content (interpretation depends on chunk_type) + end_of_message = Boolean() # Current thought/action/observation/answer is complete + end_of_dialog = Boolean() # Entire agent dialog is complete +``` + +**Maana ya Viwanja:** + +`chunk_type`: Inaonyesha aina ya yaliyomo katika sehemu `content` + `"thought"`: Tafakari/fikra za wakala + `"action"`: Chombo/kitendo kinachotumika + `"observation"`: Matokeo ya utekelezaji wa chombo + `"answer"`: Jibu la mwisho kwa swali la mtumiaji + `"error"`: Ujumbe wa kosa + +`content`: Yaliyomo halisi yanayotiririshwa, ambayo hutafsiriwa kulingana na `chunk_type` + +`end_of_message`: Wakati `true`, aina ya sehemu ya sasa imekamilika + Mfano: Alama zote za fikra ya sasa zimetumwa + Inaruhusu wateja kujua wakati wa kuendelea na hatua inayofuata + +`end_of_dialog`: Wakati `true`, mwingiliano wote wa wakala umekamilika + Hii ndio ujumbe wa mwisho katika mtiririko + +#### Tabia ya Utiririshaji wa Wakala + +Wakati `streaming=true`: + +1. **Utiririshaji wa fikra:** + Sehemu nyingi zenye `chunk_type="thought"`, `end_of_message=false` + Sehemu ya mwisho ya fikra ina `end_of_message=true` +2. **Arifa ya kitendo:** + Sehemu moja yenye `chunk_type="action"`, `end_of_message=true` +3. **Uchunguzi:** + Sehemu(ma) yenye `chunk_type="observation"`, ya mwisho ina `end_of_message=true` +4. **Rudia** hatua za 1-3 wakati wakala anafikiri +5. **Jibu la mwisho:** + `chunk_type="answer"` yenye jibu la mwisho katika `content` + Sehemu ya mwisho ina `end_of_message=true`, `end_of_dialog=true` + +**Mfululizo wa Mfano wa Mtiririko:** + +``` +{chunk_type: "thought", content: "I need to", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " search for...", end_of_message: true, end_of_dialog: false} +{chunk_type: "action", content: "search", end_of_message: true, end_of_dialog: false} +{chunk_type: "observation", content: "Found: ...", end_of_message: true, end_of_dialog: false} +{chunk_type: "thought", content: "Based on this", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " I can answer...", end_of_message: true, end_of_dialog: false} +{chunk_type: "answer", content: "The answer is...", end_of_message: true, end_of_dialog: true} +``` + +Wakati `streaming=false`: +Tabia ya sasa inahifadhiwa +Jibu moja lenye jibu kamili +`end_of_message=true`, `end_of_dialog=true` + +#### Bandari na API ya Python + +Bandari: Njia mpya ya SSE/WebSocket kwa utiririshaji wa wakala +API ya Python: Njia mpya ya `agent_stream()` ya jenereta ya async + +-- + +## Masuala ya Usalama + +**Hakuna eneo jipya la shambulio**: Utiririshaji hutumia uthibitishaji/idhini sawa +**Mipaka ya kasi**: Tumia mipaka ya kasi kwa kila tokeni au kila sehemu ikiwa inahitajika +**Usimamizi wa muunganisho**: Vunjeni kwa usahihi mitiririsho wakati mteja anakatiza +**Usimamizi wa muda**: Maombi ya utiririshaji yanahitaji usimamizi sahihi wa muda + +## Masuala ya Utendaji + +**Kumbukumbu**: Utiririshaji hupunguza matumizi ya juu ya kumbukumbu (hakuna buffering kamili ya jibu) +**Ucheleweshaji**: Muda wa hadi tokeni ya kwanza umepunguzwa sana +**Mzigo wa muunganisho**: Muunganisho wa SSE/WebSocket una mzigo wa kudumisha muunganisho +**Uwezo wa Pulsar**: Ujumbe mdogo mwingi dhidi ya ujumbe mmoja mkubwa + mbadala + +## Mkakati wa Majaribio + +### Majaribio ya Kitengo +Usanidi/uondoaji wa schema na sehemu mpya +Utangamano wa nyuma (sehemu zilizopotea hutumia chaguo-msingi) +Mantiki ya kusanyiko ya sehemu + +### Majaribio ya Uunganisho +Utaratibu wa utiririshaji wa kila mtoa huduma wa LLM +Njia za utiririshaji za API ya Bandari +Njia za utiririshaji za mteja wa Python + +### Majaribio ya Ukingo hadi Ukingo +Pato la utiririshaji la zana ya CLI +Mchakato kamili: Mteja → Bandari → Pulsar → LLM → kurudi +Mizigo mchanganyiko ya utiririshaji/isiyo ya utiririshaji + +### Majaribio ya Utangamano wa Nyuma +Wateja wazima hufanya kazi bila mabadiliko +Maombi ya utiririshaji hayatendeshwi sawa + +## Mpango wa Uhamishaji + +### Awamu ya 1: Miundombinu +Weka mabadiliko ya schema (utangamano wa nyuma) +Weka sasisho za API ya Bandari +Weka sasisho za API ya Python +Toa sasisho za zana ya CLI + +### Awamu ya 2: VertexAI +Tuma utekelezaji wa VertexAI unaotumia mtiririko. +Thibitisha kwa kutumia majaribio. + +### Awamu ya 3: Watoa Huduma Wote +Toa sasisho za watoa huduma hatua kwa hatua. +Fuatilia masuala yaliyotokea. + +### Awamu ya 4: API ya Wakala +Tuma mabadiliko ya muundo wa wakala. +Tuma utekelezaji wa mtiririko wa wakala. +Sasisha nyaraka. + +## Ratiba + +| Awamu | Maelezo | Utendaji | +|-------|-------------|--------------| +| Awamu ya 1 | Miundombinu | Hakuna | +| Awamu ya 2 | Jaribio la VertexAI | Awamu ya 1 | +| Awamu ya 3 | Watoa Huduma Wote | Awamu ya 2 | +| Awamu ya 4 | API ya Wakala | Awamu ya 3 | + +## Maamuzi ya Ubunifu + +Maswali yafuatayo yaliyulizwa yamejibiwa wakati wa maelezo: + +1. **Hesabu za Tokeni katika Mtiririko**: Hesabu za tokeni ni tofauti, sio jumla. + Wateja wanaweza kuzijumlisha ikiwa ni lazima. Hii inalingana na jinsi watoa huduma wengi wanavyoripoti + matumizi na inarahisisha utekelezaji. + +2. **Usimamizi wa Madhira katika Mitiririko**: Ikiwa hitilafu itatokea, sehemu ya `error` + itajazwa na sehemu zingine hazihitajiki. Hitilafu daima ndio mawasiliano ya mwisho + jumbe zingine za baadae haziruhusiwi au zinatarajiwa baada ya + hitilafu. Kwa mitiririko ya LLM/Prompt, `end_of_stream=true`. Kwa mitiririko ya Wakala, + `chunk_type="error"` pamoja na `end_of_dialog=true`. + +3. **Urekebishaji wa Majibu ya Kawaida**: Itifaki ya mawasiliano (Pulsar) ni thabiti, + kwa hivyo, kujaribu tena jumbe za mtu binafsi haihitajiki. Ikiwa mteja unapoteza + uhusiano wa mtiririko au kukatika, lazima ujaribu tena ombi lote kutoka mwanzo. + +4. **Mtiririko wa Huduma ya Prompt**: Mtiririko unaoendeshwa tu kwa maandishi (`text`) + majibu, sio majibu yaliyopangwa (`object`). Huduma ya prompt inajua + mapema ikiwa pato itakuwa JSON au maandishi kulingana na kiolezo cha prompt. + Ikiwa ombi la mtiririko lilitolewa kwa prompt ya pato ya JSON, huduma + inapaswa: + Kurudisha JSON kamili katika jibu moja pamoja na `end_of_stream=true`, au + Kukataa ombi la mtiririko na hitilafu + +## Maswali Yaliyobaki + +Hakuna kwa sasa. + +## Marejeleo + +Muundo wa sasa wa LLM: `trustgraph-base/trustgraph/schema/services/llm.py` +Muundo wa sasa wa prompt: `trustgraph-base/trustgraph/schema/services/prompt.py` +Muundo wa sasa wa wakala: `trustgraph-base/trustgraph/schema/services/agent.py` +Msingi wa huduma ya LLM: `trustgraph-base/trustgraph/base/llm_service.py` +Mtoa huduma wa VertexAI: `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` +API ya lango: `trustgraph-base/trustgraph/api/` +Zana za CLI: `trustgraph-cli/trustgraph/cli/` diff --git a/docs/tech-specs/streaming-llm-responses.tr.md b/docs/tech-specs/streaming-llm-responses.tr.md new file mode 100644 index 00000000..d2c391dc --- /dev/null +++ b/docs/tech-specs/streaming-llm-responses.tr.md @@ -0,0 +1,570 @@ +# Akışlı LLM Yanıtları Teknik Özellikleri + +## Genel Bakış + +Bu özellik, TrustGraph'ta LLM yanıtları için akış desteğinin uygulanmasını tanımlar. Akış, üretilen token'ların LLM tarafından üretildikleri anda gerçek zamanlı olarak iletilmesini sağlar, böylece tamamlanmış bir yanıtın oluşturulmasını beklemez. + +Bu uygulama aşağıdaki kullanım senaryolarını destekler: + + +1. **Gerçek Zamanlı Kullanıcı Arayüzleri**: Token'ları, oluşturuldukları anda kullanıcı arayüzüne aktarın ve böylece anında görsel geri bildirim sağlayın. + +2. **İlk Token'a Ulaşma Süresinin Azaltılması**: Kullanıcılar, tam oluşturma beklemeden çıktıyı hemen görmeye başlar. + +3. **Uzun Yanıtların İşlenmesi**: Aksi takdirde zaman aşımına uğrayabilecek veya bellek sınırlarını aşabilecek çok uzun çıktıları işleyin. + +4. **Etkileşimli Uygulamalar**: Duyarlı sohbet ve ajan arayüzlerini etkinleştirin. + +## Hedefler + + +**Geriye Dönük Uyumluluk**: Mevcut, akış kullanmayan istemciler, herhangi bir değişiklik yapılmadan çalışmaya devam etmelidir. + + **Tutarlı API Tasarımı**: Akışlı ve akışsız kullanım, minimum farklılıklarla aynı şema kalıplarını kullanır. + + **Sağlayıcı Esnekliği**: Akış mevcut olduğunda akışı destekleyin, aksi takdirde zarif bir şekilde geri dönün. + + **Aşamalı Dağıtım**: Riski azaltmak için kademeli uygulama. + +**Uçtan Uca Destek**: LLM sağlayıcısından Pulsar, Gateway API ve Python API aracılığıyla istemci uygulamalarına kadar akış desteği. + +## Arka Plan + +### Mevcut Mimari + + +Mevcut LLM metin tamamlama akışı aşağıdaki gibi çalışır: + +1. İstemci, `TextCompletionRequest` ile `system` ve `prompt` alanlarını gönderir. +2. LLM hizmeti, isteği işler ve tamamlanmış bir oluşturmayı bekler. +3. Tamamlanmış `response` dizesiyle tek bir `TextCompletionResponse` döndürülür. + +Mevcut şema (`trustgraph-base/trustgraph/schema/services/llm.py`): + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() +``` + +### Mevcut Sınırlamalar + +**Gecikme**: Kullanıcılar, herhangi bir çıktı görmeden önce, tamamlanmış bir üretimi beklemelidir. +**Zaman Aşımı Riski**: Uzun üretmeler, istemci zaman aşımı eşiklerini aşabilir. +**Kötü Kullanıcı Deneyimi**: Üretim sırasında geri bildirim olmaması, yavaşlık algısı yaratır. +**Kaynak Kullanımı**: Tam yanıtlar bellekte tamponlanmalıdır. + +Bu özellik, art arda yanıt verme özelliğini etkinleştirerek bu sınırlamalara çözüm getirir ve aynı zamanda tam geriye dönük uyumluluğu korur. + + +## Teknik Tasarım + +### Aşama 1: Altyapı + +Aşama 1, şemaları, API'leri ve komut satırı araçlarını değiştirerek akış için temel altyapıyı oluşturur. + + +#### Şema Değişiklikleri + +##### LLM Şeması (`trustgraph-base/trustgraph/schema/services/llm.py`) + +**İstek Değişiklikleri:** + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() # NEW: Default false for backward compatibility +``` + +`streaming`: `true` olduğunda, akışlı yanıt gönderimi talep eder. +Varsayılan: `false` (mevcut davranış korunmuştur). + +**Yanıt Değişiklikleri:** + +```python +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +`end_of_stream`: `true` olduğunda, bunun son (veya tek) yanıt olduğunu gösterir. +Akış olmayan istekler için: `end_of_stream=true` ile tek bir yanıt. +Akış istekleri için: `end_of_stream=false` ile birden fazla yanıt (son yanıt hariç). + hariç. + +##### İstek Şeması (`trustgraph-base/trustgraph/schema/services/prompt.py`) + +İstek hizmeti, metin tamamlama işlemini kapsar, bu nedenle aynı kalıbı yansıtır: + +**İstek Değişiklikleri:** + +```python +class PromptRequest(Record): + id = String() + terms = Map(String()) + streaming = Boolean() # NEW: Default false +``` + +**Değişiklikler:** + +```python +class PromptResponse(Record): + error = Error() + text = String() + object = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +#### Ağ Geçidi API Değişiklikleri + +Ağ Geçidi API'sinin, HTTP/WebSocket istemcilerine akış yeteneklerini sunması gerekir. + +**REST API Güncellemeleri:** + +`POST /api/v1/text-completion`: İstek gövdesinde `streaming` parametresini kabul et +Yanıt davranışı, akış bayrağına bağlıdır: + `streaming=false`: Tek JSON yanıtı (mevcut davranış) + `streaming=true`: Sunucu Tarafından Gönderilen Olaylar (SSE) akışı veya WebSocket mesajları + +**Yanıt Formatı (Akış):** + +Her akış parçası, aynı şema yapısını izler: +```json +{ + "response": "partial text...", + "end_of_stream": false, + "model": "model-name" +} +``` + +Son bölüm: +```json +{ + "response": "final text chunk", + "end_of_stream": true, + "in_token": 150, + "out_token": 500, + "model": "model-name" +} +``` + +#### Python API Değişiklikleri + +Python istemci API'si, geriye dönük uyumluluğu korurken hem akışlı hem de akışsız modları desteklemelidir. + + +**LlmClient Güncellemeleri** (`trustgraph-base/trustgraph/clients/llm_client.py`): + +```python +class LlmClient(BaseClient): + def request(self, system, prompt, timeout=300, streaming=False): + """ + Non-streaming request (backward compatible). + Returns complete response string. + """ + # Existing behavior when streaming=False + + async def request_stream(self, system, prompt, timeout=300): + """ + Streaming request. + Yields response chunks as they arrive. + """ + # New async generator method +``` + +**PromptClient Güncellemeleri** (`trustgraph-base/trustgraph/base/prompt_client.py`): + +`streaming` parametresi ve asenkron üreteç varyantıyla benzer yapı. + +#### CLI Aracı Değişiklikleri + +**tg-invoke-llm** (`trustgraph-cli/trustgraph/cli/invoke_llm.py`): + +``` +tg-invoke-llm [system] [prompt] [--no-streaming] [-u URL] [-f flow-id] +``` + +Daha iyi etkileşimli kullanıcı deneyimi için, akış varsayılan olarak etkindir. +`--no-streaming` bayrağı, akışı devre dışı bırakır. +Akış açıkken: Token'ları geldikleri gibi standart çıktıya yazdırın. +Akış kapalıyken: Tam yanıtı bekleyin, ardından çıktı verin. + +**tg-invoke-prompt** (`trustgraph-cli/trustgraph/cli/invoke_prompt.py`): + +``` +tg-invoke-prompt [template-id] [var=value...] [--no-streaming] [-u URL] [-f flow-id] +``` + +`tg-invoke-llm` ile aynı kalıp. + +#### LLM Hizmeti Temel Sınıfındaki Değişiklikler + +**LlmService** (`trustgraph-base/trustgraph/base/llm_service.py`): + +```python +class LlmService(FlowProcessor): + async def on_request(self, msg, consumer, flow): + request = msg.value() + streaming = getattr(request, 'streaming', False) + + if streaming and self.supports_streaming(): + async for chunk in self.generate_content_stream(...): + await self.send_response(chunk, end_of_stream=False) + await self.send_response(final_chunk, end_of_stream=True) + else: + response = await self.generate_content(...) + await self.send_response(response, end_of_stream=True) + + def supports_streaming(self): + """Override in subclass to indicate streaming support.""" + return False + + async def generate_content_stream(self, system, prompt, model, temperature): + """Override in subclass to implement streaming.""" + raise NotImplementedError() +``` + +-- + +### 2. Aşama: VertexAI Prova Çalışması + +2. Aşama, altyapıyı doğrulamak ve uçtan uca testleri sağlamak için tek bir sağlayıcıda (VertexAI) akışı uygulamaktadır. + + +#### VertexAI Uygulaması + +**Modül:** `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` + +**Değişiklikler:** + +1. `supports_streaming()`'ı `True` değerini döndürecek şekilde geçersiz kılın. +2. `generate_content_stream()` asenkron oluşturucusunu uygulayın. +3. Hem Gemini hem de Claude modellerini (VertexAI Anthropic API aracılığıyla) işleyin. + +**Gemini Akışı:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + model_instance = self.get_model(model, temperature) + response = model_instance.generate_content( + [system, prompt], + stream=True # Enable streaming + ) + for chunk in response: + yield LlmChunk( + text=chunk.text, + in_token=None, # Available only in final chunk + out_token=None, + ) + # Final chunk includes token counts from response.usage_metadata +``` + +**Claude (VertexAI Anthropic) Akışı:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + with self.anthropic_client.messages.stream(...) as stream: + for text in stream.text_stream: + yield LlmChunk(text=text) + # Token counts from stream.get_final_message() +``` + +#### Test Etme + +Akış yanıtı birleştirme için birim testleri +VertexAI (Gemini ve Claude) ile entegrasyon testleri +Uçtan uca testler: CLI -> Ağ Geçidi -> Pulsar -> VertexAI -> geri +Geriye dönük uyumluluk testleri: Akış olmayan istekler hala çalışıyor + +-- + +### 3. Aşama: Tüm LLM Sağlayıcıları + +3. Aşama, akış desteğini sistemdeki tüm LLM sağlayıcılarına genişletir. + +#### Sağlayıcı Uygulama Durumu + +Her sağlayıcı aşağıdaki seçeneklerden birini uygulamalıdır: +1. **Tam Akış Desteği**: `generate_content_stream()`'ı uygulayın +2. **Uyumluluk Modu**: `end_of_stream` bayrağını doğru şekilde işleyin + (tek bir yanıt döndürün `end_of_stream=true` ile birlikte) + +| Sağlayıcı | Paket | Akış Desteği | +|----------|---------|-------------------| +| OpenAI | trustgraph-flow | Tam (yerel akış API'si) | +| Claude/Anthropic | trustgraph-flow | Tam (yerel akış API'si) | +| Ollama | trustgraph-flow | Tam (yerel akış API'si) | +| Cohere | trustgraph-flow | Tam (yerel akış API'si) | +| Mistral | trustgraph-flow | Tam (yerel akış API'si) | +| Azure OpenAI | trustgraph-flow | Tam (yerel akış API'si) | +| Google AI Studio | trustgraph-flow | Tam (yerel akış API'si) | +| VertexAI | trustgraph-vertexai | Tam (2. Aşama) | +| Bedrock | trustgraph-bedrock | Tam (yerel akış API'si) | +| LM Studio | trustgraph-flow | Tam (OpenAI ile uyumlu) | +| LlamaFile | trustgraph-flow | Tam (OpenAI ile uyumlu) | +| vLLM | trustgraph-flow | Tam (OpenAI ile uyumlu) | +| TGI | trustgraph-flow | Belirlenecek | +| Azure | trustgraph-flow | Belirlenecek | + +#### Uygulama Modeli + +OpenAI ile uyumlu sağlayıcılar (OpenAI, LM Studio, LlamaFile, vLLM) için: + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + response = await self.client.chat.completions.create( + model=model, + messages=[ + {"role": "system", "content": system}, + {"role": "user", "content": prompt} + ], + temperature=temperature, + stream=True + ) + async for chunk in response: + if chunk.choices[0].delta.content: + yield LlmChunk(text=chunk.choices[0].delta.content) +``` + +-- + +### 4. Aşama: Ajan API'si + +4. Aşama, akışı Ajan API'sine genişletmektedir. Bu, Ajan API'sinin doğası gereği zaten çok mesajlı olması nedeniyle daha karmaşıktır (düşünce → eylem → gözlem +→ tekrar → son yanıt). + + +#### Mevcut Ajan Şeması + +```python +class AgentStep(Record): + thought = String() + action = String() + arguments = Map(String()) + observation = String() + user = String() + +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + +class AgentResponse(Record): + answer = String() + error = Error() + thought = String() + observation = String() +``` + +#### Önerilen Ajan Şema Değişiklikleri + +**Değişiklik İstekleri:** + +```python +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + streaming = Boolean() # NEW: Default false +``` + +**Cevap Değişiklikleri:** + +Ajan, akıl yürütme döngüsü sırasında çeşitli türde çıktılar üretir: +Düşünceler (akıl yürütme) +Eylemler (araç çağrıları) +Gözlemler (araç sonuçları) +Cevap (sonuç yanıtı) +Hatalar + +`chunk_type`, gönderilen içeriğin türünü tanımladığı için, ayrı +`answer`, `error`, `thought` ve `observation` alanları tek bir alana dönüştürülebilir. +Tek bir `content` alanı: + +```python +class AgentResponse(Record): + chunk_type = String() # "thought", "action", "observation", "answer", "error" + content = String() # The actual content (interpretation depends on chunk_type) + end_of_message = Boolean() # Current thought/action/observation/answer is complete + end_of_dialog = Boolean() # Entire agent dialog is complete +``` + +**Alan Anlamı:** + +`chunk_type`: `content` alanında bulunan içeriğin türünü belirtir. + `"thought"`: Aracın muhakemesi/düşüncesi. + `"action"`: Çağrılan araç/eylem. + `"observation"`: Araç çalıştırmasından elde edilen sonuç. + `"answer"`: Kullanıcının sorusuna verilen nihai cevap. + `"error"`: Hata mesajı. + +`content`: `chunk_type`'e göre yorumlanan, gerçek akış içeriği. + +`end_of_message`: `true` olduğunda, mevcut parça türü tamamlanmıştır. + Örnek: Mevcut düşünce için tüm belirteçler gönderilmiştir. + İstemcilerin bir sonraki aşamaya ne zaman geçmeleri gerektiğini bilmesini sağlar. + +`end_of_dialog`: `true` olduğunda, tüm aracı etkileşimi tamamlanmıştır. + Bu, akıştaki son mesajdır. + +#### Aracı Akış Davranışı + +`streaming=true` olduğunda: + +1. **Düşünce akışı:** + `chunk_type="thought"` ve `end_of_message=false` ile birden fazla parça. + Son düşünce parçası `end_of_message=true`'a sahiptir. +2. **Eylem bildirimi:** + `chunk_type="action"` ve `end_of_message=true` ile tek bir parça. +3. **Gözlem:** + `chunk_type="observation"` ile parçalar, son parça `end_of_message=true`'e sahiptir. +4. Aracı muhakeme ederken 1-3 adımlarını tekrarlayın. +5. **Son cevap:** + `content` içindeki son yanıtla `chunk_type="answer"`. + Son parça `end_of_message=true` ve `end_of_dialog=true`'e sahiptir. + +**Örnek Akış Sırası:** + +``` +{chunk_type: "thought", content: "I need to", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " search for...", end_of_message: true, end_of_dialog: false} +{chunk_type: "action", content: "search", end_of_message: true, end_of_dialog: false} +{chunk_type: "observation", content: "Found: ...", end_of_message: true, end_of_dialog: false} +{chunk_type: "thought", content: "Based on this", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " I can answer...", end_of_message: true, end_of_dialog: false} +{chunk_type: "answer", content: "The answer is...", end_of_message: true, end_of_dialog: true} +``` + +`streaming=false` olduğunda: +Mevcut davranış korunmuştur +Tam bir cevap içeren tek bir yanıt +`end_of_message=true`, `end_of_dialog=true` + +#### Ağ Geçidi ve Python API'si + +Ağ Geçidi: Ajan akışı için yeni SSE/WebSocket uç noktası +Python API'si: Yeni `agent_stream()` asenkron oluşturucu metodu + +-- + +## Güvenlik Hususları + +**Yeni bir saldırı yüzeyi yok**: Akış, aynı kimlik doğrulama/yetkilendirme mekanizmalarını kullanır +**Hız sınırlaması**: Gerekirse, her jeton veya her parça için hız sınırları uygulayın +**Bağlantı yönetimi**: İstemci bağlantısının kesilmesi durumunda akışları düzgün bir şekilde sonlandırın +**Zaman aşımı yönetimi**: Akış istekleri için uygun zaman aşımı işleme gereklidir + +## Performans Hususları + +**Bellek**: Akış, tepe bellek kullanımını azaltır (tam yanıt tamponlama yok) +**Gecikme**: İlk jetona ulaşma süresi önemli ölçüde azaltılmıştır +**Bağlantı ek yükü**: SSE/WebSocket bağlantılarının devamlılık ek yükü vardır +**Pulsar verim**: Tek büyük mesaj yerine çok sayıda küçük mesaj + dengesi + +## Test Stratejisi + +### Birim Testleri +Yeni alanlarla şema serileştirme/deserileştirme +Geriye dönük uyumluluk (eksik alanlar için varsayılan değerler kullanılır) +Parça birleştirme mantığı + +### Entegrasyon Testleri +Her LLM sağlayıcısının akış uygulaması +Ağ Geçidi API akış uç noktaları +Python istemci akış metotları + +### Uçtan Uca Testler +CLI aracının akış çıktısı +Tam akış: İstemci → Ağ Geçidi → Pulsar → LLM → geri +Karışık akış/akış dışı iş yükleri + +### Geriye Dönük Uyumluluk Testleri +Mevcut istemciler değişiklik yapılmadan çalışır +Akış dışı istekler aynı şekilde davranır + +## Geçiş Planı + +### 1. Aşama: Altyapı +Şema değişikliklerini dağıtın (geriye dönük uyumlu) +Ağ Geçidi API güncellemelerini dağıtın +Python API güncellemelerini dağıtın +CLI aracı güncellemelerini yayınlayın + +### 2. Aşama: VertexAI +VertexAI akış uygulamasını dağıtın +Test iş yükleriyle doğrulayın + +### 3. Aşama: Tüm Sağlayıcılar +Sağlayıcı güncellemelerini aşamalı olarak yayınlayın +Sorunlar için izleyin + +### 4. Aşama: Ajan API'si +Ajan şema değişikliklerini dağıtın +Ajan akış uygulamasını dağıtın +Belgeleri güncelleyin + +## Zaman Çizelgesi + +| Aşama | Açıklama | Bağımlılıklar | +|-------|-------------|--------------| +| 1. Aşama | Altyapı | Yok | +| 2. Aşama | VertexAI PoC | 1. Aşama | +| 3. Aşama | Tüm Sağlayıcılar | 2. Aşama | +| 4. Aşama | Ajan API'si | 3. Aşama | + +## Tasarım Kararları + +Aşağıdaki sorular, belirtim sırasında çözülmüştür: + +1. **Akıştaki Jeton Sayıları**: Jeton sayıları, toplamlar değil, artışlardır. + Tüketiciler, gerekirse bunları toplayabilir. Bu, çoğu sağlayıcının kullanım + raporlama şekliyle eşleşir ve uygulamayı basitleştirir. + +2. **Akışlardaki Hata İşleme**: Bir hata oluşursa, `error` alanı + doldurulur ve diğer alanlara ihtiyaç duyulmaz. Bir hata her zaman son + iletişimdir; hata sonrasında başka mesajlara izin verilmez veya beklenmez. + LLM/İstem akışları için `end_of_stream=true`. Ajan akışları için, + `chunk_type="error"` ile `end_of_dialog=true`. + +3. **Kısmi Yanıt Kurtarma**: Mesajlaşma protokolü (Pulsar) dayanıklıdır, + bu nedenle mesaj düzeyinde yeniden deneme gerekli değildir. Bir istem, akışı + takip edemezse veya bağlantısı kesilirse, isteği baştan yeniden denemesi gerekir. + +4. **İstem Hizmeti Akışı**: Akış yalnızca metin (`text`) yanıtları için + desteklenir, yapılandırılmış (`object`) yanıtlar için değil. İstem hizmeti, + çıktının JSON mu yoksa metin tabanlı mı olacağını, istem şablonuna göre + önceden bilir. Bir akış isteği, JSON çıktılı bir istem için yapılırsa, + hizmet şunlardan birini yapmalıdır: + Tam JSON'ı tek bir yanıtla `end_of_stream=true` ile döndürün veya + Akış isteğini bir hata ile reddedin + +## Açık Sorular + +Şu anda yok. + +## Referanslar + +Mevcut LLM şeması: `trustgraph-base/trustgraph/schema/services/llm.py` +Mevcut istem şeması: `trustgraph-base/trustgraph/schema/services/prompt.py` +Mevcut ajan şeması: `trustgraph-base/trustgraph/schema/services/agent.py` +LLM hizmeti tabanı: `trustgraph-base/trustgraph/base/llm_service.py` +VertexAI sağlayıcısı: `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` +Ağ Geçidi API'si: `trustgraph-base/trustgraph/api/` +CLI araçları: `trustgraph-cli/trustgraph/cli/` diff --git a/docs/tech-specs/streaming-llm-responses.zh-cn.md b/docs/tech-specs/streaming-llm-responses.zh-cn.md new file mode 100644 index 00000000..4f17cb11 --- /dev/null +++ b/docs/tech-specs/streaming-llm-responses.zh-cn.md @@ -0,0 +1,570 @@ +# 流式LLM响应技术规范 + +## 概述 + +本规范描述了在TrustGraph中实现LLM响应的流式支持。流式传输允许实时交付由LLM生成的token,而不是等待完整的响应生成。 +流式传输允许实时交付由LLM生成的token,而不是等待完整的响应生成。 +流式传输允许实时交付由LLM生成的token,而不是等待完整的响应生成。 +流式传输允许实时交付由LLM生成的token,而不是等待完整的响应生成。 + +此实现支持以下用例: + +1. **实时用户界面**: 将生成的令牌流式传输到用户界面, + 从而提供即时的视觉反馈。 +2. **减少首次令牌时间**: 用户立即看到输出, + 而不是等待完整生成。 +3. **处理长响应**: 处理可能导致超时或超出内存限制的非常长的输出。 + 4. **交互式应用程序**: 启用响应迅速的聊天和代理界面。 + + +## 目标 + +**向后兼容性:** 现有的非流式客户端继续工作 + 无需修改。 +**一致的 API 设计:** 流式和非流式使用相同的模式,差异最小。 + +**提供商的灵活性:** 在可用时支持流式传输,在不可用时提供优雅的 + 回退方案。 +**分阶段推出:** 逐步实施以降低风险。 +**端到端支持:** 从 LLM 提供商到客户端 + 应用程序,通过 Pulsar、Gateway API 和 Python API 提供支持。 + +## 背景 + +### 当前架构 + +当前 LLM 文本补全流程如下: + +1. 客户端发送 `TextCompletionRequest`,包含 `system` 和 `prompt` 字段。 +2. LLM 服务处理请求并等待完整生成。 +3. 返回单个 `TextCompletionResponse`,包含完整的 `response` 字符串。 + +当前模式 (`trustgraph-base/trustgraph/schema/services/llm.py`): + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() +``` + +### 当前限制 + +**延迟:** 用户必须等待完整生成后才能看到任何输出。 +**超时风险:** 较长的生成过程可能超出客户端超时阈值。 +**糟糕的用户体验:** 在生成过程中没有反馈,会让人产生缓慢的感觉。 +**资源使用:** 完整的响应必须缓存在内存中。 + +本规范通过启用增量响应来解决这些限制,同时保持完全的向后兼容性。 + + +## 技术设计 + +### 第一阶段:基础设施 + +第一阶段通过修改模式、API 和 CLI 工具,为流式传输奠定基础。 + + +#### 模式更改 + +##### LLM 模式 (`trustgraph-base/trustgraph/schema/services/llm.py`) + +**请求更改:** + +```python +class TextCompletionRequest(Record): + system = String() + prompt = String() + streaming = Boolean() # NEW: Default false for backward compatibility +``` + +`streaming`:当 `true` 时,请求流式响应传输。 +默认:`false`(保留现有行为)。 + +**响应变更:** + +```python +class TextCompletionResponse(Record): + error = Error() + response = String() + in_token = Integer() + out_token = Integer() + model = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +`end_of_stream`:当 `true` 时,表示这是最终(或唯一的)响应。 +对于非流式请求:单个响应,包含 `end_of_stream=true`。 +对于流式请求:多个响应,全部包含 `end_of_stream=false`。 + 除了最后一个响应。 + +##### 提示模式 (`trustgraph-base/trustgraph/schema/services/prompt.py`) + +提示服务包装了文本补全功能,因此它遵循相同的模式: + +**请求更改:** + +```python +class PromptRequest(Record): + id = String() + terms = Map(String()) + streaming = Boolean() # NEW: Default false +``` + +**响应变更:** + +```python +class PromptResponse(Record): + error = Error() + text = String() + object = String() + end_of_stream = Boolean() # NEW: Indicates final message +``` + +#### 网关 API 变更 + +网关 API 必须向 HTTP/WebSocket 客户端暴露流式传输功能。 + +**REST API 更新:** + +`POST /api/v1/text-completion`: 接受请求体中的 `streaming` 参数 +响应行为取决于流式传输标志: + `streaming=false`: 单个 JSON 响应(当前行为) + `streaming=true`: 服务器发送事件 (SSE) 流或 WebSocket 消息 + +**响应格式(流式传输):** + +每个流式传输的数据块都遵循相同的模式结构: +```json +{ + "response": "partial text...", + "end_of_stream": false, + "model": "model-name" +} +``` + +最终部分: +```json +{ + "response": "final text chunk", + "end_of_stream": true, + "in_token": 150, + "out_token": 500, + "model": "model-name" +} +``` + +#### Python API 变更 + +Python 客户端 API 必须同时支持流式和非流式模式, +同时保持向后兼容性。 + +**LlmClient 更新** (`trustgraph-base/trustgraph/clients/llm_client.py`): + +```python +class LlmClient(BaseClient): + def request(self, system, prompt, timeout=300, streaming=False): + """ + Non-streaming request (backward compatible). + Returns complete response string. + """ + # Existing behavior when streaming=False + + async def request_stream(self, system, prompt, timeout=300): + """ + Streaming request. + Yields response chunks as they arrive. + """ + # New async generator method +``` + +**PromptClient 更新** (`trustgraph-base/trustgraph/base/prompt_client.py`): + +类似于使用 `streaming` 参数和异步生成器的变体。 + +#### CLI 工具更改 + +**tg-invoke-llm** (`trustgraph-cli/trustgraph/cli/invoke_llm.py`): + +``` +tg-invoke-llm [system] [prompt] [--no-streaming] [-u URL] [-f flow-id] +``` + +默认启用流式传输,以获得更好的交互式用户体验。 +`--no-streaming` 标志禁用流式传输。 +当启用流式传输时:将生成的 token 输出到标准输出,并在它们到达时立即输出。 +当禁用流式传输时:等待完整的响应,然后输出。 + +**tg-invoke-prompt** (`trustgraph-cli/trustgraph/cli/invoke_prompt.py`): + +``` +tg-invoke-prompt [template-id] [var=value...] [--no-streaming] [-u URL] [-f flow-id] +``` + +与 `tg-invoke-llm` 相同的模式。 + +#### LLM 服务基础类更改 + +**LlmService** (`trustgraph-base/trustgraph/base/llm_service.py`): + +```python +class LlmService(FlowProcessor): + async def on_request(self, msg, consumer, flow): + request = msg.value() + streaming = getattr(request, 'streaming', False) + + if streaming and self.supports_streaming(): + async for chunk in self.generate_content_stream(...): + await self.send_response(chunk, end_of_stream=False) + await self.send_response(final_chunk, end_of_stream=True) + else: + response = await self.generate_content(...) + await self.send_response(response, end_of_stream=True) + + def supports_streaming(self): + """Override in subclass to indicate streaming support.""" + return False + + async def generate_content_stream(self, system, prompt, model, temperature): + """Override in subclass to implement streaming.""" + raise NotImplementedError() +``` + +-- + +### 第二阶段:VertexAI 概念验证 + +第二阶段在单个提供商(VertexAI)中实现流式传输,以验证 +基础设施并实现端到端测试。 + +#### VertexAI 实施 + +**模块:** `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` + +**变更:** + +1. 覆盖 `supports_streaming()` 以返回 `True` +2. 实现 `generate_content_stream()` 异步生成器 +3. 处理 Gemini 和 Claude 模型(通过 VertexAI Anthropic API) + +**Gemini 流式传输:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + model_instance = self.get_model(model, temperature) + response = model_instance.generate_content( + [system, prompt], + stream=True # Enable streaming + ) + for chunk in response: + yield LlmChunk( + text=chunk.text, + in_token=None, # Available only in final chunk + out_token=None, + ) + # Final chunk includes token counts from response.usage_metadata +``` + +**Claude (通过 VertexAI Anthropic) 流式传输:** + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + with self.anthropic_client.messages.stream(...) as stream: + for text in stream.text_stream: + yield LlmChunk(text=text) + # Token counts from stream.get_final_message() +``` + +#### 测试 + +流式响应组装的单元测试 +与 VertexAI (Gemini 和 Claude) 的集成测试 +端到端测试:CLI -> 网关 -> Pulsar -> VertexAI -> 回调 +向后兼容性测试:非流式请求仍然有效 + +-- + +### 第三阶段:所有 LLM 提供商 + +第三阶段将流式支持扩展到系统中的所有 LLM 提供商。 + +#### 提供商实施状态 + +每个提供商必须: +1. **完全流式支持**: 实施 `generate_content_stream()` +2. **兼容模式**: 正确处理 `end_of_stream` 标志 + (返回单个响应,包含 `end_of_stream=true`) + +| 提供商 | 包 | 流式支持 | +|----------|---------|-------------------| +| OpenAI | trustgraph-flow | 完全 (原生流式 API) | +| Claude/Anthropic | trustgraph-flow | 完全 (原生流式 API) | +| Ollama | trustgraph-flow | 完全 (原生流式 API) | +| Cohere | trustgraph-flow | 完全 (原生流式 API) | +| Mistral | trustgraph-flow | 完全 (原生流式 API) | +| Azure OpenAI | trustgraph-flow | 完全 (原生流式 API) | +| Google AI Studio | trustgraph-flow | 完全 (原生流式 API) | +| VertexAI | trustgraph-vertexai | 完全 (第二阶段) | +| Bedrock | trustgraph-bedrock | 完全 (原生流式 API) | +| LM Studio | trustgraph-flow | 完全 (与 OpenAI 兼容) | +| LlamaFile | trustgraph-flow | 完全 (与 OpenAI 兼容) | +| vLLM | trustgraph-flow | 完全 (与 OpenAI 兼容) | +| TGI | trustgraph-flow | 待定 | +| Azure | trustgraph-flow | 待定 | + +#### 实施模式 + +对于与 OpenAI 兼容的提供商 (OpenAI, LM Studio, LlamaFile, vLLM): + +```python +async def generate_content_stream(self, system, prompt, model, temperature): + response = await self.client.chat.completions.create( + model=model, + messages=[ + {"role": "system", "content": system}, + {"role": "user", "content": prompt} + ], + temperature=temperature, + stream=True + ) + async for chunk in response: + if chunk.choices[0].delta.content: + yield LlmChunk(text=chunk.choices[0].delta.content) +``` + +-- + +### 第四阶段:代理 API + +第四阶段将流式传输扩展到代理 API。 这更加复杂,因为 +代理 API 本身就是多消息的(思考 → 行动 → 观察 +→ 重复 → 最终答案)。 + +#### 当前代理模式 + +```python +class AgentStep(Record): + thought = String() + action = String() + arguments = Map(String()) + observation = String() + user = String() + +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + +class AgentResponse(Record): + answer = String() + error = Error() + thought = String() + observation = String() +``` + +#### 建议的代理模式变更 + +**请求变更:** + +```python +class AgentRequest(Record): + question = String() + state = String() + group = Array(String()) + history = Array(AgentStep()) + user = String() + streaming = Boolean() # NEW: Default false +``` + +**响应变化:** + +代理在推理过程中会产生多种类型的输出: +想法(推理) +动作(工具调用) +观察结果(工具结果) +答案(最终回复) +错误 + +由于 `chunk_type` 标识了正在发送的内容类型,因此可以合并单独的 +`answer`、`error`、`thought` 和 `observation` 字段, +从而将其合并到一个 `content` 字段中: + +```python +class AgentResponse(Record): + chunk_type = String() # "thought", "action", "observation", "answer", "error" + content = String() # The actual content (interpretation depends on chunk_type) + end_of_message = Boolean() # Current thought/action/observation/answer is complete + end_of_dialog = Boolean() # Entire agent dialog is complete +``` + +**字段语义:** + +`chunk_type`: 指示 `content` 字段中包含的内容类型。 + `"thought"`: 代理的推理/思考。 + `"action"`: 正在调用的工具/动作。 + `"observation"`: 来自工具执行的结果。 + `"answer"`: 对用户问题的最终答案。 + `"error"`: 错误消息。 + +`content`: 实际的流式内容,根据 `chunk_type` 进行解释。 + +`end_of_message`: 当 `true` 时,当前块类型已完成。 + 示例:当前思考的所有 token 都已发送。 + 允许客户端知道何时进入下一个阶段。 + +`end_of_dialog`: 当 `true` 时,整个代理交互已完成。 + 这是一个流中的最终消息。 + +#### 代理流式行为 + +当 `streaming=true` 时: + +1. **思考流式传输:** + 具有 `chunk_type="thought"`、`end_of_message=false` 的多个块。 + 最终的思考块具有 `end_of_message=true`。 +2. **动作通知:** + 具有 `chunk_type="action"`、`end_of_message=true` 的单个块。 +3. **观察:** + 具有 `chunk_type="observation"` 的块(块),最终块具有 `end_of_message=true`。 +4. **重复** 1-3 步骤,直到代理完成推理。 +5. **最终答案:** + `chunk_type="answer"` 包含最终的响应,位于 `content` 中。 + 最后一个块具有 `end_of_message=true`、`end_of_dialog=true`。 + +**示例流序列:** + +``` +{chunk_type: "thought", content: "I need to", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " search for...", end_of_message: true, end_of_dialog: false} +{chunk_type: "action", content: "search", end_of_message: true, end_of_dialog: false} +{chunk_type: "observation", content: "Found: ...", end_of_message: true, end_of_dialog: false} +{chunk_type: "thought", content: "Based on this", end_of_message: false, end_of_dialog: false} +{chunk_type: "thought", content: " I can answer...", end_of_message: true, end_of_dialog: false} +{chunk_type: "answer", content: "The answer is...", end_of_message: true, end_of_dialog: true} +``` + +当 `streaming=false`: +当前行为保持不变 +提供完整的答案的单个响应 +`end_of_message=true`, `end_of_dialog=true` + +#### 网关和 Python API + +网关:用于代理流的新 SSE/WebSocket 端点 +Python API:新的 `agent_stream()` 异步生成器方法 + +-- + +## 安全注意事项 + +**没有新的攻击面**:流式传输使用相同的身份验证/授权机制 +**速率限制**:如果需要,请应用每个令牌或每个分块的速率限制 +**连接处理**:在客户端断开连接时,正确终止流 +**超时管理**:流式传输请求需要适当的超时处理 + +## 性能注意事项 + +**内存**:流式传输减少了峰值内存使用量(没有完整的响应缓冲) +**延迟**:首次令牌的时间显著减少 +**连接开销**:SSE/WebSocket 连接具有保活开销 +**Pulsar 吞吐量**:多个小消息与单个大消息之间的权衡 + tradeoff + +## 测试策略 + +### 单元测试 +使用新字段的模式序列化/反序列化 +向后兼容性(缺少字段使用默认值) +分块组装逻辑 + +### 集成测试 +每个 LLM 提供商的流式传输实现 +网关 API 流式传输端点 +Python 客户端流式传输方法 + +### 端到端测试 +CLI 工具的流式传输输出 +完整流程:客户端 → 网关 → Pulsar → LLM → 返回 +混合流式传输/非流式传输工作负载 + +### 向后兼容性测试 +现有客户端无需修改即可工作 +非流式传输请求的行为与之前相同 + +## 迁移计划 + +### 第一阶段:基础设施 +部署模式更改(向后兼容) +部署网关 API 更新 +部署 Python API 更新 +发布 CLI 工具更新 + +### 第二阶段:VertexAI +部署 VertexAI 流式实现。 +使用测试工作负载进行验证。 + +### 第三阶段:所有提供商 +逐步推广提供商更新。 +监控问题。 + +### 第四阶段:Agent API +部署 Agent 模式变更。 +部署 Agent 流式实现。 +更新文档。 + +## 时间线 + +| 阶段 | 描述 | 依赖项 | +|-------|-------------|--------------| +| 第一阶段 | 基础设施 | 无 | +| 第二阶段 | VertexAI 概念验证 | 第一阶段 | +| 第三阶段 | 所有提供商 | 第二阶段 | +| 第四阶段 | Agent API | 第三阶段 | + +## 设计决策 + +在规范过程中,解决了以下问题: + +1. **流式传输中的 Token 计数**: Token 计数是增量值,而不是累计总数。 + 消费者可以根据需要对其进行求和。这与大多数提供商报告的使用方式一致,并简化了实现。 + + +2. **流中的错误处理:** 如果发生错误,则会填充 `error` 字段,并且不需要填充其他字段。 错误始终是最终的 + 通信 - 在发生错误后,不允许也不期望发送任何后续消息。 + 通信 - 在此之后,不允许也不需要发送任何后续消息。 + 一个错误。对于 LLM/Prompt 流,`end_of_stream=true`。对于 Agent 流, + `chunk_type="error"` 与 `end_of_dialog=true`。 + +3. **部分响应恢复:** 消息协议(Pulsar)具有容错性, + 因此不需要消息级别的重试。如果客户端丢失了流的信息 + 或断开连接,则必须从头开始重试整个请求。 + +4. **快速响应流式传输**: 流式传输仅支持文本 (`text`) + 响应,不支持结构化 (`object`) 响应。 提示服务在开始时就知道输出将是 JSON 还是文本,这取决于提示 + 模板。 如果对 JSON 输出提示执行流式传输请求,则 + 会出现问题。 + 服务应该要么: + 返回完整的 JSON 数据,以单个响应的形式,包含 `end_of_stream=true`,或者 + 拒绝流式传输请求,并返回错误。 + +## 开放问题 + +目前没有。 + +## 参考文献 + +当前 LLM 模式:`trustgraph-base/trustgraph/schema/services/llm.py` +当前提示词模式:`trustgraph-base/trustgraph/schema/services/prompt.py` +当前代理模式:`trustgraph-base/trustgraph/schema/services/agent.py` +LLM 服务基础地址:`trustgraph-base/trustgraph/base/llm_service.py` +VertexAI 提供商:`trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py` +网关 API:`trustgraph-base/trustgraph/api/` +CLI 工具:`trustgraph-cli/trustgraph/cli/` diff --git a/docs/tech-specs/structured-data-2.ar.md b/docs/tech-specs/structured-data-2.ar.md new file mode 100644 index 00000000..43518854 --- /dev/null +++ b/docs/tech-specs/structured-data-2.ar.md @@ -0,0 +1,613 @@ +# المواصفات الفنية للبيانات المهيكلة (الجزء 2) + +## نظرة عامة + +تتناول هذه المواصفات المشكلات والفجوات التي تم تحديدها أثناء التنفيذ الأولي لدمج البيانات المهيكلة في TrustGraph، كما هو موضح في `structured-data.md`. + +## بيان المشكلات + +### 1. عدم اتساق في التسمية: "كائن" مقابل "صف" + +يستخدم التنفيذ الحالي مصطلح "كائن" في جميع أنحائه (على سبيل المثال، `ExtractedObject`، واستخراج الكائنات، وتضمينات الكائنات). هذا المصطلح عام جدًا ويسبب ارتباكًا: + +مصطلح "كائن" مصطلح عام ومزدحم في البرمجيات (كائنات بايثون، كائنات JSON، إلخ). +البيانات التي يتم التعامل معها هي في الأساس بيانات جدولية - صفوف في الجداول ذات المخططات المحددة. +مصطلح "صف" يصف نموذج البيانات بشكل أكثر دقة ويتوافق مع مصطلحات قواعد البيانات. + +يظهر هذا التناقض في أسماء الوحدات، وأسماء الفئات، وأنواع الرسائل، والوثائق. + +### 2. قيود استعلامات تخزين الصفوف + +يحتوي تنفيذ تخزين الصفوف الحالي على قيود استعلام كبيرة: + +**عدم تطابق مع اللغة الطبيعية**: تواجه الاستعلامات صعوبة في التعامل مع الاختلافات في البيانات الواقعية. على سبيل المثال: +من الصعب العثور على قاعدة بيانات الشوارع التي تحتوي على `"CHESTNUT ST"` عند السؤال عن `"Chestnut Street"`. +تكسر الاختصارات، والاختلافات في الأحرف الكبيرة والصغيرة، وتغيرات التنسيق استعلامات المطابقة التامة. +يتوقع المستخدمون فهمًا دلاليًا، لكن المستودع يوفر مطابقة حرفية. + +**مشكلات تطور المخطط**: يؤدي تغيير المخططات إلى حدوث مشكلات: +قد لا تتوافق البيانات الموجودة مع المخططات المحدثة. +يمكن أن تؤدي تغييرات هيكل الجدول إلى تعطيل الاستعلامات وتكامل البيانات. +لا توجد مسار ترحيل واضح لتحديثات المخطط. + +### 3. مطلوب تضمينات الصفوف + +بالإضافة إلى المشكلة رقم 2، يحتاج النظام إلى تضمينات متجهة لبيانات الصفوف لتمكين: + +البحث الدلالي عبر البيانات المهيكلة (العثور على "شارع تشيستنوت" عندما تحتوي البيانات على "CHESTNUT ST"). +مطابقة التشابه للاستعلامات الغامضة. +البحث الهجين الذي يجمع بين المرشحات المهيكلة ومطابقة التشابه الدلالي. +دعم أفضل للغة الطبيعية. + +تم تحديد خدمة التضمين ولكن لم يتم تنفيذها. + +### 4. استيعاب بيانات الصفوف غير مكتمل + +مسار استيعاب البيانات المهيكلة ليس فعالًا بالكامل: + +توجد مطالبات تشخيصية لتصنيف تنسيقات الإدخال (CSV، JSON، إلخ). +خدمة الاستيعاب التي تستخدم هذه المطالبات غير متصلة بالنظام. +لا يوجد مسار شامل لتحميل البيانات المهيكلة مسبقًا إلى مستودع الصفوف. + +## الأهداف + +**مرونة المخطط**: تمكين تطور المخطط دون تعطل البيانات الموجودة أو الحاجة إلى عمليات ترحيل. +**تسمية متسقة**: توحيد مصطلح "صف" في جميع أنحاء قاعدة التعليمات البرمجية. +**قابلية الاستعلام الدلالي**: دعم المطابقة الغامضة / الدلالية عبر تضمينات الصفوف. +**مسار استيعاب كامل**: توفير مسار شامل لتحميل البيانات المهيكلة. + +## التصميم الفني + +### مخطط تخزين صفوف موحد + +أنشأ التنفيذ السابق جدول Cassandra منفصل لكل مخطط. تسبب ذلك في حدوث مشكلات عند تطور المخططات، حيث تتطلب تغييرات هيكل الجدول عمليات ترحيل. + +يستخدم التصميم الجديد جدولًا موحدًا واحدًا لجميع بيانات الصفوف: + +```sql +CREATE TABLE rows ( + collection text, + schema_name text, + index_name text, + index_value frozen>, + data map, + source text, + PRIMARY KEY ((collection, schema_name, index_name), index_value) +) +``` + +#### تعريفات الأعمدة + +| العمود | النوع | الوصف | +|--------|------|-------------| +| `collection` | `text` | معرف جمع البيانات/الاستيراد (من البيانات الوصفية) | +| `schema_name` | `text` | اسم المخطط الذي يتوافق معه هذا الصف | +| `index_name` | `text` | اسم الحقل/الحقول المفهرسة، مفصولة بفاصلة للحقول المركبة | +| `index_value` | `frozen>` | قيم الفهرس كقائمة | +| `data` | `map` | بيانات الصف كأزواج مفتاح-قيمة | +| `source` | `text` | عنوان URI اختياري يربط بمعلومات المصدر في الرسم البياني المعرفي. السلسلة الفارغة أو NULL تشير إلى عدم وجود مصدر. | + +#### معالجة الفهرس + +يتم تخزين كل صف عدة مرات - مرة واحدة لكل حقل مفهرس معرف في المخطط. يتم التعامل مع حقول المفتاح الأساسي كفهرس بدون علامة خاصة، مما يوفر مرونة مستقبلية. + +**مثال على الفهرس ذي الحقل الواحد:** +يحدد المخطط `email` كحقل مفهرس +`index_name = "email"` +`index_value = ['foo@bar.com']` + +**مثال على الفهرس المركب:** +يحدد المخطط فهرسًا مركبًا على `region` و `status` +`index_name = "region,status"` (أسماء الحقول مرتبة ومفصولة بفاصلة) +`index_value = ['US', 'active']` (القيم بنفس ترتيب أسماء الحقول) + +**مثال على المفتاح الأساسي:** +يحدد المخطط `customer_id` كمفتاح أساسي +`index_name = "customer_id"` +`index_value = ['CUST001']` + +#### أنماط الاستعلام + +تتبع جميع الاستعلامات نفس النمط بغض النظر عن الفهرس المستخدم: + +```sql +SELECT * FROM rows +WHERE collection = 'import_2024' + AND schema_name = 'customers' + AND index_name = 'email' + AND index_value = ['foo@bar.com'] +``` + +#### المقايضات التصميمية + +**المزايا:** +التغييرات في المخطط لا تتطلب تغييرات في هيكل الجدول. +البيانات الموجودة في الصفوف غير مرئية لـ Cassandra - إضافة أو إزالة الحقول تكون شفافة. +نمط استعلام متسق لجميع طرق الوصول. +لا توجد فهارس ثانوية لـ Cassandra (والتي يمكن أن تكون بطيئة على نطاق واسع). +أنواع Cassandra الأصلية في جميع أنحاء النظام (`map`، `frozen`). + +**المقايضات:** +تضخيم الكتابة: كل إدخال صف = N إدخالات (واحد لكل حقل مفهرس). +تكلفة تخزين إضافية بسبب تكرار بيانات الصفوف. +يتم تخزين معلومات النوع في تكوين المخطط، ويتم التحويل في طبقة التطبيق. + +#### نموذج الاتساق + +التصميم يقبل بعض التبسيط: + +1. **لا توجد تحديثات للصفوف**: النظام مخصص للإضافة فقط. هذا يلغي مخاوف الاتساق المتعلقة بتحديث نسخ متعددة من نفس الصف. + +2. **تحمل تغيير المخطط**: عند تغيير المخططات (على سبيل المثال، إضافة أو إزالة الفهارس)، تحتفظ الصفوف الموجودة بفهرستها الأصلية. لن يتمكن المستخدمون من اكتشاف الصفوف القديمة عبر الفهارس الجديدة. يمكن للمستخدمين حذف وإعادة إنشاء مخطط لضمان الاتساق إذا لزم الأمر. + +### تتبع الأقسام والحذف + +#### المشكلة + +باستخدام مفتاح التقسيم `(collection, schema_name, index_name)`، يتطلب الحذف الفعال معرفة جميع مفاتيح التقسيم المراد حذفها. يتطلب الحذف باستخدام `collection` أو `collection + schema_name` معرفة جميع قيم `index_name` التي تحتوي على بيانات. + +#### جدول تتبع الأقسام + +جدول بحث ثانوي يتتبع الأقسام الموجودة: + +```sql +CREATE TABLE row_partitions ( + collection text, + schema_name text, + index_name text, + PRIMARY KEY ((collection), schema_name, index_name) +) +``` + +هذا يتيح اكتشافًا فعالًا للأقسام لعمليات الحذف. + +#### سلوك كاتب الصفوف + +يحتفظ كاتب الصفوف بخزن مؤقت في الذاكرة لأزواج `(collection, schema_name)` المسجلة. عند معالجة صف: + +1. تحقق مما إذا كانت `(collection, schema_name)` موجودة في الذاكرة المؤقتة. +2. إذا لم تكن موجودة في الذاكرة المؤقتة (أول صف لهذه الزوج): + ابحث في تكوين المخطط للحصول على جميع أسماء الفهارس. + أدخل إدخالات في `row_partitions` لكل `(collection, schema_name, index_name)`. + أضف الزوج إلى الذاكرة المؤقتة. +3. تابع بكتابة بيانات الصف. + +يراقب كاتب الصفوف أيضًا أحداث تغيير تكوين المخطط. عند حدوث تغيير في المخطط، يتم مسح إدخالات الذاكرة المؤقتة ذات الصلة بحيث يؤدي الصف التالي إلى إعادة التسجيل باستخدام أسماء الفهارس المحدثة. + +يضمن هذا النهج: +تتم كتابة جداول البحث مرة واحدة لكل زوج `(collection, schema_name)`، وليس لكل صف. +يعكس جدول البحث الفهارس التي كانت نشطة عند كتابة البيانات. +يتم اكتشاف تغييرات المخطط في منتصف الاستيراد بشكل صحيح. + +#### عمليات الحذف + +**حذف المجموعة:** +```sql +-- 1. Discover all partitions +SELECT schema_name, index_name FROM row_partitions WHERE collection = 'X'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = '...' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table +DELETE FROM row_partitions WHERE collection = 'X'; +``` + +**حذف المجموعة والمخطط:** +```sql +-- 1. Discover partitions for this schema +SELECT index_name FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = 'Y' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table entries +DELETE FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; +``` + +### تضمينات الصفوف + +تتيح تضمينات الصفوف المطابقة الدلالية/التقريبية على القيم المفهرسة، مما يحل مشكلة عدم تطابق اللغة الطبيعية (على سبيل المثال، العثور على "CHESTNUT ST" عند البحث عن "Chestnut Street"). + +#### نظرة عامة على التصميم + +يتم تضمين كل قيمة مفهرسة وتخزينها في مخزن متجه (Qdrant). في وقت الاستعلام، يتم تضمين الاستعلام، ويتم العثور على المتجهات المشابهة، ويتم استخدام البيانات الوصفية المرتبطة للبحث عن الصفوف الفعلية في Cassandra. + +#### هيكل مجموعة Qdrant + +مجموعة Qdrant واحدة لكل مجموعة `(user, collection, schema_name, dimension)`: + +**تسمية المجموعة:** `rows_{user}_{collection}_{schema_name}_{dimension}` +يتم تنظيف الأسماء (يتم استبدال الأحرف غير الأبجدية الرقمية بـ `_`، وتحويلها إلى أحرف صغيرة، وتتم إضافة بادئة رقمية بـ `r_`) +**السبب:** يتيح حذف مثيل `(user, collection, schema_name)` بشكل نظيف عن طريق حذف مجموعات Qdrant المطابقة؛ تسمح لاحقة الأبعاد لوجود نماذج تضمين مختلفة. + +#### ما الذي يتم تضمينه + +التمثيل النصي لقيم الفهرس: + +| نوع الفهرس | مثال `index_value` | النص المراد تضمينه | +|------------|----------------------|---------------| +| حقل واحد | `['foo@bar.com']` | `"foo@bar.com"` | +| مركب | `['US', 'active']` | `"US active"` (مفصولة بمسافات) | + +#### هيكل النقطة + +تحتوي كل نقطة Qdrant على: + +```json +{ + "id": "", + "vector": [0.1, 0.2, ...], + "payload": { + "index_name": "street_name", + "index_value": ["CHESTNUT ST"], + "text": "CHESTNUT ST" + } +} +``` + +| حقل الحمولة | الوصف | +|---------------|-------------| +| `index_name` | الحقول المفهرسة التي يمثلها هذا التضمين. | +| `index_value` | القائمة الأصلية للقيم (للبحث في Cassandra). | +| `text` | النص الذي تم تضمينه (للتصحيح/العرض). | + +ملاحظة: `user`، و `collection`، و `schema_name` مستمدة ضمنيًا من اسم مجموعة Qdrant. + +#### مسار الاستعلام + +1. يقوم المستخدم بالاستعلام عن "Chestnut Street" ضمن المستخدم U، والمجموعة X، والمخطط Y. +2. تضمين نص الاستعلام. +3. تحديد اسم(أسماء) مجموعة Qdrant التي تتطابق مع البادئة `rows_U_X_Y_`. +4. البحث في مجموعة(مجموعات) Qdrant المطابقة عن أقرب المتجهات. +5. الحصول على النقاط المطابقة التي تحتوي على حمولات تحتوي على `index_name` و `index_value`. +6. الاستعلام عن Cassandra: + ```sql + SELECT * FROM rows + WHERE collection = 'X' + AND schema_name = 'Y' + AND index_name = '' + AND index_value = + ``` +7. إرجاع الصفوف المطابقة. + +#### اختياري: التصفية حسب اسم الفهرس. + +يمكن للاستعلامات اختيارياً أن تقوم بالتصفية باستخدام `index_name` في Qdrant للبحث في حقول محددة فقط: + +**"ابحث عن أي حقل يطابق 'Chestnut'"** → ابحث في جميع المتجهات في المجموعة. +**"ابحث عن 'street_name' الذي يطابق 'Chestnut'"** → قم بالتصفية حيث `payload.index_name = 'street_name'`. + +#### البنية. + +تتبع تضمينات الصف النمط **المكون من مرحلتين** المستخدم في GraphRAG (تضمينات الرسم البياني، تضمينات المستندات): + +**المرحلة 1: حساب التضمين** (`trustgraph-flow/trustgraph/embeddings/row_embeddings/`) - تستهلك `ExtractedObject`، وتحسب التضمينات عبر خدمة التضمينات، وتُخرج `RowEmbeddings`. +**المرحلة 2: تخزين التضمين** (`trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/`) - تستهلك `RowEmbeddings`، وتكتب المتجهات إلى Qdrant. + +كاتب صف Cassandra هو مستهلك متوازي منفصل: + +**كاتب صف Cassandra** (`trustgraph-flow/trustgraph/storage/rows/cassandra`) - يستهلك `ExtractedObject`، ويكتب الصفوف إلى Cassandra. + +تستهلك جميع الخدمات الثلاثة من نفس التدفق، مما يحافظ عليها منفصلة. هذا يسمح: +بتوسيع نطاق كتابة Cassandra بشكل مستقل عن إنشاء التضمينات وتخزين المتجهات. +يمكن تعطيل خدمات التضمين إذا لم تكن مطلوبة. +لا تؤثر الأعطال في خدمة واحدة على الخدمات الأخرى. +بنية متسقة مع مسارات GraphRAG. + +#### مسار الكتابة. + +**المرحلة 1 (معالج تضمينات الصف):** عند استقبال `ExtractedObject`: + +1. ابحث عن المخطط للعثور على الحقول المفهرسة. +2. لكل حقل مفهرس: + قم بإنشاء التمثيل النصي لقيمة الفهرس. + احسب التضمين عبر خدمة التضمينات. +3. أخرج رسالة `RowEmbeddings` تحتوي على جميع المتجهات المحسوبة. + +**المرحلة 2 (كتابة تضمينات الصف إلى Qdrant):** عند استقبال `RowEmbeddings`: + +1. لكل تضمين في الرسالة: + حدد مجموعة Qdrant من `(user, collection, schema_name, dimension)`. + قم بإنشاء المجموعة إذا لزم الأمر (إنشاء كسول في الكتابة الأولى). + قم بتحديث النقطة باستخدام المتجه والحمولة. + +#### أنواع الرسائل. + +```python +@dataclass +class RowIndexEmbedding: + index_name: str # The indexed field name(s) + index_value: list[str] # The field value(s) + text: str # Text that was embedded + vectors: list[list[float]] # Computed embedding vectors + +@dataclass +class RowEmbeddings: + metadata: Metadata + schema_name: str + embeddings: list[RowIndexEmbedding] +``` + +#### دمج الحذف + +يتم اكتشاف مجموعات Qdrant من خلال مطابقة البادئة مع نمط اسم المجموعة: + +**حذف `(user, collection)`:** +1. قائمة بجميع مجموعات Qdrant التي تتطابق مع البادئة `rows_{user}_{collection}_` +2. حذف كل مجموعة مطابقة +3. حذف أقسام صفوف Cassandra (كما هو موثق أعلاه) +4. تنظيف إدخالات `row_partitions` + +**حذف `(user, collection, schema_name)`:** +1. قائمة بجميع مجموعات Qdrant التي تتطابق مع البادئة `rows_{user}_{collection}_{schema_name}_` +2. حذف كل مجموعة مطابقة (يتعامل مع أبعاد متعددة) +3. حذف أقسام صفوف Cassandra +4. تنظيف `row_partitions` + +#### مواقع الوحدات + +| المرحلة | الوحدة | نقطة الدخول | +|-------|--------|-------------| +| المرحلة 1 | `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | `row-embeddings` | +| المرحلة 2 | `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | `row-embeddings-write-qdrant` | + +### واجهة برمجة تطبيقات استعلام تضمينات الصفوف + +استعلام تضمينات الصفوف هو **واجهة برمجة تطبيقات منفصلة** عن خدمة استعلام الصفوف GraphQL: + +| واجهة برمجة التطبيقات | الغرض | الواجهة الخلفية | +|-----|---------|---------| +| استعلام الصفوف (GraphQL) | مطابقة دقيقة في الحقول المفهرسة | Cassandra | +| استعلام تضمينات الصفوف | مطابقة تقريبية/دلالية | Qdrant | + +هذا الفصل يحافظ على الفصل بين المهام: +خدمة GraphQL تركز على الاستعلامات الدقيقة والمنظمة +واجهة برمجة تطبيقات التضمينات تتعامل مع التشابه الدلالي +سير عمل المستخدم: بحث تقريبي عبر التضمينات للعثور على المرشحين، ثم استعلام دقيق للحصول على بيانات الصف الكاملة + +#### مخطط الطلب/الاستجابة + +```python +@dataclass +class RowEmbeddingsRequest: + vectors: list[list[float]] # Query vectors (pre-computed embeddings) + user: str = "" + collection: str = "" + schema_name: str = "" + index_name: str = "" # Optional: filter to specific index + limit: int = 10 # Max results per vector + +@dataclass +class RowIndexMatch: + index_name: str = "" # The matched index field(s) + index_value: list[str] = [] # The matched value(s) + text: str = "" # Original text that was embedded + score: float = 0.0 # Similarity score + +@dataclass +class RowEmbeddingsResponse: + error: Error | None = None + matches: list[RowIndexMatch] = [] +``` + +#### معالج الاستعلامات + +الوحدة: `trustgraph-flow/trustgraph/query/row_embeddings/qdrant` + +نقطة الدخول: `row-embeddings-query-qdrant` + +المعالج: +1. يتلقى `RowEmbeddingsRequest` مع متجهات الاستعلام. +2. يجد مجموعة Qdrant المناسبة عن طريق مطابقة البادئة. +3. يبحث عن أقرب المتجهات مع مرشح `index_name` اختياري. +4. يُرجع `RowEmbeddingsResponse` مع معلومات الفهرس المطابقة. + +#### تكامل بوابة واجهة برمجة التطبيقات (API Gateway) + +تعرض البوابة استعلامات تضمينات الصفوف عبر النمط القياسي للطلب/الاستجابة: + +| المكون | الموقع | +|-----------|----------| +| الموزع | `trustgraph-flow/trustgraph/gateway/dispatch/row_embeddings_query.py` | +| التسجيل | أضف `"row-embeddings"` إلى `request_response_dispatchers` في `manager.py` | + +اسم واجهة التدفق: `row-embeddings` + +تعريف الواجهة في مخطط التدفق: +```json +{ + "interfaces": { + "row-embeddings": { + "request": "non-persistent://tg/request/row-embeddings:{id}", + "response": "non-persistent://tg/response/row-embeddings:{id}" + } + } +} +``` + +#### دعم حزمة تطوير البرمجيات (SDK) الخاصة بـ Python + +توفر حزمة تطوير البرمجيات (SDK) طرقًا للاستعلام عن تضمينات الصفوف: + +```python +# Flow-scoped query (preferred) +api = Api(url) +flow = api.flow().id("default") + +# Query with text (SDK computes embeddings) +matches = flow.row_embeddings_query( + text="Chestnut Street", + collection="my_collection", + schema_name="addresses", + index_name="street_name", # Optional filter + limit=10 +) + +# Query with pre-computed vectors +matches = flow.row_embeddings_query( + vectors=[[0.1, 0.2, ...]], + collection="my_collection", + schema_name="addresses" +) + +# Each match contains: +for match in matches: + print(match.index_name) # e.g., "street_name" + print(match.index_value) # e.g., ["CHESTNUT ST"] + print(match.text) # e.g., "CHESTNUT ST" + print(match.score) # e.g., 0.95 +``` + +#### أداة سطر الأوامر + +الأمر: `tg-invoke-row-embeddings` + +```bash +# Query by text (computes embedding automatically) +tg-invoke-row-embeddings \ + --text "Chestnut Street" \ + --collection my_collection \ + --schema addresses \ + --index street_name \ + --limit 10 + +# Query by vector file +tg-invoke-row-embeddings \ + --vectors vectors.json \ + --collection my_collection \ + --schema addresses + +# Output formats +tg-invoke-row-embeddings --text "..." --format json +tg-invoke-row-embeddings --text "..." --format table +``` + +#### النمط النموذجي للاستخدام + +عادةً ما يتم استخدام استعلام تضمينات الصفوف كجزء من تدفق بحث تقريبي إلى دقيق: + +```python +# Step 1: Fuzzy search via embeddings +matches = flow.row_embeddings_query( + text="chestnut street", + collection="geo", + schema_name="streets" +) + +# Step 2: Exact lookup via GraphQL for full row data +for match in matches: + query = f''' + query {{ + streets(where: {{ {match.index_name}: {{ eq: "{match.index_value[0]}" }} }}) {{ + street_name + city + zip_code + }} + }} + ''' + rows = flow.rows_query(query, collection="geo") +``` + +هذا النمط المكون من خطوتين يمكّن: +العثور على "CHESTNUT ST" عندما يبحث المستخدم عن "Chestnut Street" +استرجاع بيانات الصف بأكملها مع جميع الحقول +الجمع بين التشابه الدلالي والوصول إلى البيانات المنظمة + +### استيعاب بيانات الصف + +سيتم تأجيله إلى مرحلة لاحقة. سيتم تصميمه جنبًا إلى جنب مع تغييرات الاستيعاب الأخرى. + +## التأثير على التنفيذ + +### تحليل الحالة الحالية + +يحتوي التنفيذ الحالي على مكونين رئيسيين: + +| المكون | الموقع | الأسطر | الوصف | +|-----------|----------|-------|-------------| +| خدمة الاستعلام | `trustgraph-flow/trustgraph/query/objects/cassandra/service.py` | ~740 | كتلة واحدة: توليد مخطط GraphQL، تحليل المرشحات، استعلامات Cassandra، معالجة الطلبات | +| الكاتب | `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` | ~540 | إنشاء جدول لكل مخطط، فهارس ثانوية، إدراج/حذف | + +**نمط الاستعلام الحالي:** +```sql +SELECT * FROM {keyspace}.o_{schema_name} +WHERE collection = 'X' AND email = 'foo@bar.com' +ALLOW FILTERING +``` + +**نمط استعلام جديد:** +```sql +SELECT * FROM {keyspace}.rows +WHERE collection = 'X' AND schema_name = 'customers' + AND index_name = 'email' AND index_value = ['foo@bar.com'] +``` + +### التغييرات الرئيسية + +1. **تبسيط دلالات الاستعلام**: المخطط الجديد يدعم فقط المطابقات الدقيقة على `index_value`. مرشحات GraphQL الحالية (`gt`، `lt`، `contains`، إلخ) إما: + تصبح تصفية لاحقة على البيانات المُرجعة (إذا كانت لا تزال مطلوبة) + يتم إزالتها لصالح استخدام واجهة برمجة تطبيقات التضمينات للمطابقة التقريبية + +2. **كود GraphQL مرتبط ارتباطًا وثيقًا**: يحتوي `service.py` الحالي على توليد أنواع Strawberry، وتحليل المرشحات، والاستعلامات الخاصة بـ Cassandra. إضافة قاعدة بيانات أخرى ستؤدي إلى تكرار حوالي 400 سطر من كود GraphQL. + +### إعادة الهيكلة المقترحة + +تتكون إعادة الهيكلة من جزأين: + +#### 1. فصل كود GraphQL + +استخراج مكونات GraphQL القابلة لإعادة الاستخدام إلى وحدة مشتركة: + +``` +trustgraph-flow/trustgraph/query/graphql/ +├── __init__.py +├── types.py # Filter types (IntFilter, StringFilter, FloatFilter) +├── schema.py # Dynamic schema generation from RowSchema +└── filters.py # Filter parsing utilities +``` + +هذا يتيح: +إعادة الاستخدام عبر خلفيات تخزين الصفوف المختلفة. +فصل أوضح للمسؤوليات. +اختبار منطق GraphQL بسهولة أكبر بشكل مستقل. + +#### 2. تنفيذ مخطط الجدول الجديد + +إعادة هيكلة التعليمات البرمجية الخاصة بـ Cassandra لاستخدام الجدول الموحد: + +**الكاتب** (`trustgraph-flow/trustgraph/storage/rows/cassandra/`): +جدول `rows` واحد بدلاً من الجداول الخاصة بكل مخطط. +كتابة N من النسخ لكل صف (واحد لكل فهرس). +التسجيل في جدول `row_partitions`. +إنشاء جدول أبسط (إعداد لمرة واحدة). + +**خدمة الاستعلام** (`trustgraph-flow/trustgraph/query/rows/cassandra/`): +الاستعلام عن جدول `rows` الموحد. +استخدام الوحدة النمطية GraphQL المستخرجة لإنشاء المخطط. +تبسيط معالجة المرشحات (مطابقة تامة فقط على مستوى قاعدة البيانات). + +### تغيير أسماء الوحدات النمطية + +كجزء من عملية تنظيف أسماء "object" → "row": + +| الحالي | الجديد | +|---------|-----| +| `storage/objects/cassandra/` | `storage/rows/cassandra/` | +| `query/objects/cassandra/` | `query/rows/cassandra/` | +| `embeddings/object_embeddings/` | `embeddings/row_embeddings/` | + +### وحدات نمطية جديدة + +| الوحدة النمطية | الغرض | +|--------|---------| +| `trustgraph-flow/trustgraph/query/graphql/` | أدوات GraphQL مشتركة | +| `trustgraph-flow/trustgraph/query/row_embeddings/qdrant/` | واجهة برمجة تطبيقات استعلام تضمينات الصفوف | +| `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | حساب تضمينات الصفوف (المرحلة 1) | +| `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | تخزين تضمينات الصفوف (المرحلة 2) | + +## المراجع + +[مواصفات البيانات المنظمة](structured-data.md) diff --git a/docs/tech-specs/structured-data-2.es.md b/docs/tech-specs/structured-data-2.es.md new file mode 100644 index 00000000..a1fb5483 --- /dev/null +++ b/docs/tech-specs/structured-data-2.es.md @@ -0,0 +1,613 @@ +# Especificación Técnica de Datos Estructurados (Parte 2) + +## Resumen + +Esta especificación aborda los problemas y las deficiencias identificadas durante la implementación inicial de la integración de datos estructurados de TrustGraph, como se describe en `structured-data.md`. + +## Declaraciones del Problema + +### 1. Inconsistencia en la Nomenclatura: "Objeto" vs "Fila" + +La implementación actual utiliza la terminología de "objeto" en todo (por ejemplo, `ExtractedObject`, extracción de objetos, incrustaciones de objetos). Esta nomenclatura es demasiado genérica y causa confusión: + +"Objeto" es un término ambiguo en el software (objetos de Python, objetos JSON, etc.) +Los datos que se están manejando son fundamentalmente tabulares: filas en tablas con esquemas definidos. +"Fila" describe con mayor precisión el modelo de datos y se alinea con la terminología de la base de datos. + +Esta inconsistencia aparece en los nombres de los módulos, los nombres de las clases, los tipos de mensajes y la documentación. + +### 2. Limitaciones de Consulta de la Tienda de Filas + +La implementación actual de la tienda de filas tiene limitaciones de consulta significativas: + +**Desajuste con el Lenguaje Natural**: Las consultas tienen dificultades con las variaciones de datos del mundo real. Por ejemplo: +Es difícil encontrar una base de datos de calles que contenga `"CHESTNUT ST"` cuando se pregunta por `"Chestnut Street"`. +Las abreviaturas, las diferencias de mayúsculas y minúsculas y las variaciones de formato interrumpen las consultas de coincidencia exacta. +Los usuarios esperan una comprensión semántica, pero la tienda proporciona una coincidencia literal. + +**Problemas de Evolución del Esquema**: Los cambios en los esquemas causan problemas: +Los datos existentes pueden no cumplir con los esquemas actualizados. +Los cambios en la estructura de la tabla pueden romper las consultas y la integridad de los datos. +No hay una ruta de migración clara para las actualizaciones del esquema. + +### 3. Se Requieren Incrustaciones de Filas + +Relacionado con el problema 2, el sistema necesita incrustaciones vectoriales para los datos de las filas para permitir: + +Búsqueda semántica en datos estructurados (encontrar "Chestnut Street" cuando los datos contienen "CHESTNUT ST"). +Coincidencia de similitud para consultas difusas. +Búsqueda híbrida que combina filtros estructurados con similitud semántica. +Mejor soporte para consultas en lenguaje natural. + +El servicio de incrustación se especificó pero no se implementó. + +### 4. Ingesta de Datos de Filas Incompleta + +La canalización de ingesta de datos estructurados no está completamente operativa: + +Existen indicaciones de diagnóstico para clasificar los formatos de entrada (CSV, JSON, etc.). +El servicio de ingesta que utiliza estas indicaciones no está integrado en el sistema. +No hay una ruta de extremo a extremo para cargar datos preestructurados en la tienda de filas. + +## Objetivos + +**Flexibilidad del Esquema**: Permitir la evolución del esquema sin romper los datos existentes ni requerir migraciones. +**Nomenclatura Consistente**: Estandarizar la terminología de "fila" en todo el código base. +**Consultas Semánticas**: Compatibilidad con la coincidencia difusa/semántica a través de incrustaciones de filas. +**Canalización de Ingesta Completa**: Proporcionar una ruta de extremo a extremo para cargar datos estructurados. + +## Diseño Técnico + +### Esquema Unificado de Almacenamiento de Filas + +La implementación anterior creó una tabla de Cassandra separada para cada esquema. Esto causó problemas cuando los esquemas evolucionaron, ya que los cambios en la estructura de la tabla requerían migraciones. + +El nuevo diseño utiliza una única tabla unificada para todos los datos de filas: + +```sql +CREATE TABLE rows ( + collection text, + schema_name text, + index_name text, + index_value frozen>, + data map, + source text, + PRIMARY KEY ((collection, schema_name, index_name), index_value) +) +``` + +#### Definiciones de columnas + +| Columna | Tipo | Descripción | +|--------|------|-------------| +| `collection` | `text` | Identificador de recolección/importación de datos (procedente de metadatos) | +| `schema_name` | `text` | Nombre del esquema al que se ajusta esta fila | +| `index_name` | `text` | Nombre del(los) campo(s) indexado(s), unidos por comas para compuestos | +| `index_value` | `frozen>` | Valor(es) del índice como una lista | +| `data` | `map` | Datos de la fila como pares clave-valor | +| `source` | `text` | URI opcional que enlaza a información de procedencia en el grafo de conocimiento. Una cadena vacía o NULL indica que no hay fuente. | + +#### Manejo de índices + +Cada fila se almacena varias veces: una vez por cada campo indexado definido en el esquema. Los campos de clave primaria se tratan como un índice sin un marcador especial, lo que proporciona flexibilidad futura. + +**Ejemplo de índice de un solo campo:** +El esquema define `email` como indexado +`index_name = "email"` +`index_value = ['foo@bar.com']` + +**Ejemplo de índice compuesto:** +El esquema define un índice compuesto en `region` y `status` +`index_name = "region,status"` (nombres de los campos ordenados y unidos por comas) +`index_value = ['US', 'active']` (valores en el mismo orden que los nombres de los campos) + +**Ejemplo de clave primaria:** +El esquema define `customer_id` como clave primaria +`index_name = "customer_id"` +`index_value = ['CUST001']` + +#### Patrones de consulta + +Todas las consultas siguen el mismo patrón, independientemente del índice que se utilice: + +```sql +SELECT * FROM rows +WHERE collection = 'import_2024' + AND schema_name = 'customers' + AND index_name = 'email' + AND index_value = ['foo@bar.com'] +``` + +#### Compensaciones de diseño + +**Ventajas:** +Los cambios de esquema no requieren cambios en la estructura de la tabla. +Los datos de las filas son opacos para Cassandra; las adiciones/eliminaciones de campos son transparentes. +Patrón de consulta consistente para todos los métodos de acceso. +No hay índices secundarios de Cassandra (que pueden ser lentos a escala). +Tipos nativos de Cassandra en todo momento (`map`, `frozen`). + +**Compensaciones:** +Amplificación de escritura: cada inserción de fila = N inserciones (una por cada campo indexado). +Sobrecarga de almacenamiento debido a la duplicación de datos de las filas. +La información del tipo se almacena en la configuración del esquema, la conversión se realiza en la capa de la aplicación. + +#### Modelo de consistencia + +El diseño acepta ciertas simplificaciones: + +1. **Sin actualizaciones de filas**: El sistema es de solo escritura. Esto elimina las preocupaciones de coherencia sobre la actualización de múltiples copias de la misma fila. + +2. **Tolerancia a los cambios de esquema**: Cuando los esquemas cambian (por ejemplo, se agregan o eliminan índices), las filas existentes conservan su indexación original. Las filas antiguas no se podrán descubrir a través de nuevos índices. Los usuarios pueden eliminar y recrear un esquema para garantizar la coherencia si es necesario. + +### Seguimiento y eliminación de particiones + +#### El problema + +Con la clave de partición `(collection, schema_name, index_name)`, la eliminación eficiente requiere conocer todas las claves de partición para eliminar. Eliminar solo por `collection` o `collection + schema_name` requiere conocer todos los valores de `index_name` que tienen datos. + +#### Tabla de seguimiento de particiones + +Una tabla de búsqueda secundaria realiza un seguimiento de qué particiones existen: + +```sql +CREATE TABLE row_partitions ( + collection text, + schema_name text, + index_name text, + PRIMARY KEY ((collection), schema_name, index_name) +) +``` + +Esto permite una detección eficiente de particiones para operaciones de eliminación. + +#### Comportamiento del Escritor de Filas + +El escritor de filas mantiene una caché en memoria de pares registrados de `(collection, schema_name)`. Al procesar una fila: + +1. Comprobar si `(collection, schema_name)` está en la caché. +2. Si no está en la caché (primera fila para este par): + Buscar la configuración del esquema para obtener todos los nombres de índice. + Insertar entradas en `row_partitions` para cada `(collection, schema_name, index_name)`. + Agregar el par a la caché. +3. Continuar con la escritura de los datos de la fila. + +El escritor de filas también supervisa los eventos de cambio de configuración del esquema. Cuando cambia un esquema, las entradas de caché relevantes se eliminan para que la siguiente fila active un nuevo registro con los nombres de índice actualizados. + +Este enfoque garantiza: +Las escrituras de la tabla de búsqueda se realizan una vez por par de `(collection, schema_name)`, no por fila. +La tabla de búsqueda refleja los índices que estaban activos cuando se escribieron los datos. +Los cambios de esquema durante la importación se detectan correctamente. + +#### Operaciones de Eliminación + +**Eliminar colección:** +```sql +-- 1. Discover all partitions +SELECT schema_name, index_name FROM row_partitions WHERE collection = 'X'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = '...' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table +DELETE FROM row_partitions WHERE collection = 'X'; +``` + +**Eliminar colección + esquema:** +```sql +-- 1. Discover partitions for this schema +SELECT index_name FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = 'Y' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table entries +DELETE FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; +``` + +### Incrustaciones de Filas + +Las incrustaciones de filas permiten la coincidencia semántica/difusa en los valores indexados, resolviendo el problema de la falta de coincidencia del lenguaje natural (por ejemplo, encontrar "CHESTNUT ST" al buscar "Chestnut Street"). + +#### Descripción General del Diseño + +Cada valor indexado se incrusta y se almacena en un almacén de vectores (Qdrant). En el momento de la consulta, la consulta se incrusta, se encuentran vectores similares y los metadatos asociados se utilizan para buscar las filas reales en Cassandra. + +#### Estructura de la Colección Qdrant + +Una colección Qdrant por tupla `(user, collection, schema_name, dimension)`: + +**Nombre de la colección:** `rows_{user}_{collection}_{schema_name}_{dimension}` +Los nombres se limpian (los caracteres no alfanuméricos se reemplazan con `_`, se convierten a minúsculas, los prefijos numéricos reciben el prefijo `r_`) +**Justificación:** Permite la eliminación limpia de una instancia `(user, collection, schema_name)` eliminando las colecciones Qdrant correspondientes; el sufijo de dimensión permite que diferentes modelos de incrustación coexistan. + +#### Qué se Incrusta + +La representación de texto de los valores de índice: + +| Tipo de Índice | Ejemplo `index_value` | Texto a Incrustar | +|------------|----------------------|---------------| +| Campo único | `['foo@bar.com']` | `"foo@bar.com"` | +| Compuesto | `['US', 'active']` | `"US active"` (unidos por espacios) | + +#### Estructura del Punto + +Cada punto Qdrant contiene: + +```json +{ + "id": "", + "vector": [0.1, 0.2, ...], + "payload": { + "index_name": "street_name", + "index_value": ["CHESTNUT ST"], + "text": "CHESTNUT ST" + } +} +``` + +| Campo de carga útil | Descripción | +|---------------|-------------| +| `index_name` | Los campos indexados que representa esta incrustación. | +| `index_value` | La lista original de valores (para la búsqueda en Cassandra). | +| `text` | El texto que se incrustó (para depuración/visualización). | + +Nota: `user`, `collection` y `schema_name` se derivan implícitamente del nombre de la colección de Qdrant. + +#### Flujo de consulta + +1. El usuario consulta "Chestnut Street" dentro del usuario U, la colección X, el esquema Y. +2. Incrusta el texto de la consulta. +3. Determina el(los) nombre(s) de la colección de Qdrant que coinciden con el prefijo `rows_U_X_Y_`. +4. Busca en la(s) colección(es) de Qdrant que coincidan para encontrar los vectores más cercanos. +5. Obtiene los puntos coincidentes con cargas útiles que contienen `index_name` y `index_value`. +6. Consulta Cassandra: + ```sql + SELECT * FROM rows + WHERE collection = 'X' + AND schema_name = 'Y' + AND index_name = '' + AND index_value = + ``` +7. Devolver filas coincidentes + +#### Opcional: Filtrado por Nombre de Índice + +Las consultas pueden filtrar opcionalmente por `index_name` en Qdrant para buscar solo campos específicos: + +**"Encontrar cualquier campo que coincida con 'Chestnut'"** → buscar todos los vectores en la colección +**"Encontrar street_name que coincida con 'Chestnut'"** → filtrar donde `payload.index_name = 'street_name'` + +#### Arquitectura + +Los incrustados de filas siguen el **patrón de dos etapas** utilizado por GraphRAG (incrustados de grafos, incrustados de documentos): + +**Etapa 1: Cálculo de incrustados** (`trustgraph-flow/trustgraph/embeddings/row_embeddings/`) - Consume `ExtractedObject`, calcula incrustados a través del servicio de incrustados, produce `RowEmbeddings` +**Etapa 2: Almacenamiento de incrustados** (`trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/`) - Consume `RowEmbeddings`, escribe vectores en Qdrant + +El escritor de filas de Cassandra es un consumidor paralelo separado: + +**Escritor de filas de Cassandra** (`trustgraph-flow/trustgraph/storage/rows/cassandra`) - Consume `ExtractedObject`, escribe filas en Cassandra + +Los tres servicios consumen del mismo flujo, manteniéndolos desacoplados. Esto permite: +Escalado independiente de las escrituras de Cassandra frente a la generación de incrustados frente al almacenamiento de vectores +Los servicios de incrustados se pueden desactivar si no son necesarios +Las fallas en un servicio no afectan a los demás +Arquitectura consistente con las canalizaciones de GraphRAG + +#### Ruta de Escritura + +**Etapa 1 (procesador de incrustados de filas):** Al recibir un `ExtractedObject`: + +1. Buscar el esquema para encontrar campos indexados +2. Para cada campo indexado: + Construir la representación de texto del valor del índice + Calcular el incrustado a través del servicio de incrustados +3. Producir un mensaje `RowEmbeddings` que contenga todos los vectores calculados + +**Etapa 2 (escritura de incrustados de filas en Qdrant):** Al recibir un `RowEmbeddings`: + +1. Para cada incrustado en el mensaje: + Determinar la colección de Qdrant a partir de `(user, collection, schema_name, dimension)` + Crear la colección si es necesario (creación perezosa en la primera escritura) + Insertar el punto con el vector y la carga útil + +#### Tipos de Mensajes + +```python +@dataclass +class RowIndexEmbedding: + index_name: str # The indexed field name(s) + index_value: list[str] # The field value(s) + text: str # Text that was embedded + vectors: list[list[float]] # Computed embedding vectors + +@dataclass +class RowEmbeddings: + metadata: Metadata + schema_name: str + embeddings: list[RowIndexEmbedding] +``` + +#### Integración de Eliminación + +Las colecciones de Qdrant se descubren mediante la comparación de prefijos en el patrón de nombre de la colección: + +**Eliminar `(user, collection)`:** +1. Listar todas las colecciones de Qdrant que coincidan con el prefijo `rows_{user}_{collection}_` +2. Eliminar cada colección que coincida +3. Eliminar particiones de filas de Cassandra (como se documenta anteriormente) +4. Limpiar las entradas de `row_partitions` + +**Eliminar `(user, collection, schema_name)`:** +1. Listar todas las colecciones de Qdrant que coincidan con el prefijo `rows_{user}_{collection}_{schema_name}_` +2. Eliminar cada colección que coincida (maneja múltiples dimensiones) +3. Eliminar particiones de filas de Cassandra +4. Limpiar `row_partitions` + +#### Ubicaciones de los Módulos + +| Etapa | Módulo | Punto de Entrada | +|-------|--------|-------------| +| Etapa 1 | `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | `row-embeddings` | +| Etapa 2 | `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | `row-embeddings-write-qdrant` | + +### API de Consulta de Incrustaciones de Filas + +La consulta de incrustaciones de filas es una **API separada** del servicio de consulta de filas GraphQL: + +| API | Propósito | Backend | +|-----|---------|---------| +| Consulta de Filas (GraphQL) | Coincidencia exacta en campos indexados | Cassandra | +| Consulta de Incrustaciones de Filas | Coincidencia difusa/semántica | Qdrant | + +Esta separación mantiene la claridad: +El servicio GraphQL se enfoca en consultas exactas y estructuradas +La API de incrustaciones maneja la similitud semántica +Flujo de trabajo del usuario: búsqueda difusa a través de incrustaciones para encontrar candidatos, luego una consulta exacta para obtener los datos completos de la fila + +#### Esquema de Solicitud/Respuesta + +```python +@dataclass +class RowEmbeddingsRequest: + vectors: list[list[float]] # Query vectors (pre-computed embeddings) + user: str = "" + collection: str = "" + schema_name: str = "" + index_name: str = "" # Optional: filter to specific index + limit: int = 10 # Max results per vector + +@dataclass +class RowIndexMatch: + index_name: str = "" # The matched index field(s) + index_value: list[str] = [] # The matched value(s) + text: str = "" # Original text that was embedded + score: float = 0.0 # Similarity score + +@dataclass +class RowEmbeddingsResponse: + error: Error | None = None + matches: list[RowIndexMatch] = [] +``` + +#### Procesador de Consultas + +Módulo: `trustgraph-flow/trustgraph/query/row_embeddings/qdrant` + +Punto de entrada: `row-embeddings-query-qdrant` + +El procesador: +1. Recibe `RowEmbeddingsRequest` con vectores de consulta +2. Encuentra la colección Qdrant apropiada mediante la coincidencia de prefijos +3. Busca los vectores más cercanos con un filtro opcional `index_name` +4. Devuelve `RowEmbeddingsResponse` con información del índice correspondiente + +#### Integración con la API Gateway + +La puerta de enlace expone consultas de incrustaciones de filas a través del patrón estándar de solicitud/respuesta: + +| Componente | Ubicación | +|-----------|----------| +| Despachador | `trustgraph-flow/trustgraph/gateway/dispatch/row_embeddings_query.py` | +| Registro | Agrega `"row-embeddings"` a `request_response_dispatchers` en `manager.py` | + +Nombre de la interfaz de flujo: `row-embeddings` + +Definición de la interfaz en el plano de flujo: +```json +{ + "interfaces": { + "row-embeddings": { + "request": "non-persistent://tg/request/row-embeddings:{id}", + "response": "non-persistent://tg/response/row-embeddings:{id}" + } + } +} +``` + +#### Soporte del SDK de Python + +El SDK proporciona métodos para consultas de incrustaciones de filas: + +```python +# Flow-scoped query (preferred) +api = Api(url) +flow = api.flow().id("default") + +# Query with text (SDK computes embeddings) +matches = flow.row_embeddings_query( + text="Chestnut Street", + collection="my_collection", + schema_name="addresses", + index_name="street_name", # Optional filter + limit=10 +) + +# Query with pre-computed vectors +matches = flow.row_embeddings_query( + vectors=[[0.1, 0.2, ...]], + collection="my_collection", + schema_name="addresses" +) + +# Each match contains: +for match in matches: + print(match.index_name) # e.g., "street_name" + print(match.index_value) # e.g., ["CHESTNUT ST"] + print(match.text) # e.g., "CHESTNUT ST" + print(match.score) # e.g., 0.95 +``` + +#### Utilidad de Línea de Comandos (CLI) + +Comando: `tg-invoke-row-embeddings` + +```bash +# Query by text (computes embedding automatically) +tg-invoke-row-embeddings \ + --text "Chestnut Street" \ + --collection my_collection \ + --schema addresses \ + --index street_name \ + --limit 10 + +# Query by vector file +tg-invoke-row-embeddings \ + --vectors vectors.json \ + --collection my_collection \ + --schema addresses + +# Output formats +tg-invoke-row-embeddings --text "..." --format json +tg-invoke-row-embeddings --text "..." --format table +``` + +#### Patrón de uso típico + +La consulta de incrustaciones de filas se utiliza típicamente como parte de un flujo de búsqueda difusa a exacta: + +```python +# Step 1: Fuzzy search via embeddings +matches = flow.row_embeddings_query( + text="chestnut street", + collection="geo", + schema_name="streets" +) + +# Step 2: Exact lookup via GraphQL for full row data +for match in matches: + query = f''' + query {{ + streets(where: {{ {match.index_name}: {{ eq: "{match.index_value[0]}" }} }}) {{ + street_name + city + zip_code + }} + }} + ''' + rows = flow.rows_query(query, collection="geo") +``` + +Este patrón de dos pasos permite: +Encontrar "CHESTNUT ST" cuando el usuario busca "Chestnut Street" +Recuperar datos de fila completos con todos los campos +Combinar la similitud semántica con el acceso a datos estructurados + +### Ingesta de Datos de Fila + +Se pospone a una fase posterior. Se diseñará junto con otros cambios de ingesta. + +## Impacto en la Implementación + +### Análisis del Estado Actual + +La implementación existente tiene dos componentes principales: + +| Componente | Ubicación | Líneas | Descripción | +|-----------|----------|-------|-------------| +| Servicio de Consulta | `trustgraph-flow/trustgraph/query/objects/cassandra/service.py` | ~740 | Monolítico: generación de esquema GraphQL, análisis de filtros, consultas de Cassandra, manejo de solicitudes | +| Escritor | `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` | ~540 | Creación de tablas por esquema, índices secundarios, inserción/eliminación | + +**Patrón de Consulta Actual:** +```sql +SELECT * FROM {keyspace}.o_{schema_name} +WHERE collection = 'X' AND email = 'foo@bar.com' +ALLOW FILTERING +``` + +**Nuevo Patrón de Consulta:** +```sql +SELECT * FROM {keyspace}.rows +WHERE collection = 'X' AND schema_name = 'customers' + AND index_name = 'email' AND index_value = ['foo@bar.com'] +``` + +### Cambios Clave + +1. **La semántica de las consultas se simplifica**: El nuevo esquema solo admite coincidencias exactas en `index_value`. Los filtros GraphQL actuales (`gt`, `lt`, `contains`, etc.) ya sea: + Se convierten en filtrado posterior de los datos devueltos (si es necesario) + Se eliminan en favor de usar la API de embeddings para la coincidencia difusa + +2. **El código GraphQL está fuertemente acoplado**: El código `service.py` actual incluye la generación de tipos de Strawberry, el análisis de filtros y las consultas específicas de Cassandra. Agregar otro backend de almacenamiento de filas duplicaría aproximadamente 400 líneas de código GraphQL. + +### Refactorización Propuesta + +La refactorización tiene dos partes: + +#### 1. Separar el Código GraphQL + +Extraer componentes GraphQL reutilizables en un módulo compartido: + +``` +trustgraph-flow/trustgraph/query/graphql/ +├── __init__.py +├── types.py # Filter types (IntFilter, StringFilter, FloatFilter) +├── schema.py # Dynamic schema generation from RowSchema +└── filters.py # Filter parsing utilities +``` + +Esto permite: +Reutilización en diferentes backends de almacenamiento de datos. +Una separación más clara de responsabilidades. +Pruebas más fáciles de la lógica de GraphQL de forma independiente. + +#### 2. Implementar el Nuevo Esquema de Tabla + +Refactorizar el código específico de Cassandra para utilizar la tabla unificada: + +**Escritor** (`trustgraph-flow/trustgraph/storage/rows/cassandra/`): +Una única tabla `rows` en lugar de tablas por esquema. +Escribir N copias por fila (una por índice). +Registrarse en la tabla `row_partitions`. +Creación de tabla más sencilla (configuración única). + +**Servicio de Consulta** (`trustgraph-flow/trustgraph/query/rows/cassandra/`): +Consultar la tabla `rows` unificada. +Utilizar el módulo GraphQL extraído para la generación de esquemas. +Manejo de filtros simplificado (solo coincidencia exacta a nivel de base de datos). + +### Cambios de Nombre de Módulos + +Como parte de la limpieza de nombres de "objeto" a "fila": + +| Actual | Nuevo | +|---------|-----| +| `storage/objects/cassandra/` | `storage/rows/cassandra/` | +| `query/objects/cassandra/` | `query/rows/cassandra/` | +| `embeddings/object_embeddings/` | `embeddings/row_embeddings/` | + +### Nuevos Módulos + +| Módulo | Propósito | +|--------|---------| +| `trustgraph-flow/trustgraph/query/graphql/` | Utilidades GraphQL compartidas | +| `trustgraph-flow/trustgraph/query/row_embeddings/qdrant/` | API de consulta de incrustaciones de filas | +| `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | Cálculo de incrustaciones de filas (Etapa 1) | +| `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | Almacenamiento de incrustaciones de filas (Etapa 2) | + +## Referencias + +[Especificación Técnica de Datos Estructurados](structured-data.md) diff --git a/docs/tech-specs/structured-data-2.he.md b/docs/tech-specs/structured-data-2.he.md new file mode 100644 index 00000000..46aa9be9 --- /dev/null +++ b/docs/tech-specs/structured-data-2.he.md @@ -0,0 +1,613 @@ +# מפרט טכני של נתונים מובנים (חלק 2) + +## סקירה כללית + +מפרט זה עוסק בנושאים ופערים שזוהו במהלך יישום ראשוני של שילוב נתונים מובנים של TrustGraph, כפי שמתואר ב-`structured-data.md`. + +## הצגת בעיות + +### 1. חוסר עקביות בשמות: "אובייקט" לעומת "שורה" + +יישום נוכחי משתמש בטרמינולוגיה של "אובייקט" בכל מקום (לדוגמה, `ExtractedObject`, חילוץ אובייקטים, הטמעות אובייקטים). שם זה כללי מדי וגורם לבלבול: + +"אובייקט" הוא מונח מוגדר מראש בתוכנה (אובייקטים בפייתון, אובייקטים ב-JSON, וכו') +הנתונים המטופלים הם למעשה טבלאיים - שורות בטבלאות עם סכימות מוגדרות +"שורה" מתארת ​​במדויק יותר את מודל הנתונים ומתאימה לטרמינולוגיה של מסדי נתונים + +חוסר עקביות זה מופיע בשמות מודולים, שמות מחלקות, סוגי הודעות ובתעוד. + +### 2. מגבלות שאילתות של אחסון שורות + +ליישום הנוכחי של אחסון שורות יש מגבלות שאילתות משמעותיות: + +**אי התאמה לשפה טבעית**: שאילתות מתקשות עם וריאציות של נתונים מהעולם האמיתי. לדוגמה: +קשה למצוא מסד נתונים של רחובות המכיל `"CHESTNUT ST"` כאשר שואלים על `"Chestnut Street"` +קיצורים, הבדלי רישיות ווריאציות בפורמט שוברים שאילתות התאמה מדויקת +משתמשים מצפים להבנה סמנטית, אך המאגר מספק התאמה מילולית + +**בעיות בהתפתחות סכימה**: שינוי סכימות גורם לבעיות: +נתונים קיימים עשויים שלא להתאים לסכימות מעודכנות +שינויים במבנה הטבלה עלולים לשבור שאילתות ושלמות נתונים +אין מסלול מעבר ברור לעדכוני סכימה + +### 3. הטמעות שורות נדרשות + +בהקשר לבעיה 2, המערכת זקוקה להטמעות וקטוריות עבור נתוני שורה כדי לאפשר: + +חיפוש סמנטי בנתונים מובנים (מציאת "Chestnut Street" כאשר הנתונים מכילים "CHESTNUT ST") +התאמת דמיון לשאילתות מעורפלות +חיפוש היברידי המשלב מסננים מובנים עם דמיון סמנטי +תמיכה טובה יותר בשפה טבעית + +שירות ההטמעה הוגדר אך לא יושם. + +### 4. הטמעה של נתוני שורה לא שלמה + +צינור ההטמעה של נתונים מובנים אינו פעיל במלואו: + +קיימות הנחיות אבחון כדי לסווג פורמטים של קלט (CSV, JSON, וכו') +שירות ההטמעה המשתמש בהנחיות אלה אינו מחובר למערכת +אין מסלול מקצה לקצה לטעינת נתונים מובנים לאחסון השורות + +## מטרות + +**גמישות סכימה**: לאפשר התפתחות סכימה מבלי לשבור נתונים קיימים או לדרוש מעברים +**שמות עקביים**: לתקנן על "שורה" בכל בסיס הקוד +**יכולת שאילתא סמנטית**: לתמוך בהתאמה מעורפלת/סמנטית באמצעות הטמעות שורות +**צינור הטמעה שלם**: לספק מסלול מקצה לקצה לטעינת נתונים מובנים + +## עיצוב טכני + +### סכימת אחסון שורות מאוחדת + +יישום קודם יצר טבלת Cassandra נפרדת עבור כל סכימה. זה גרם לבעיות כאשר הסכימות התפתחו, מכיוון ששינויים במבנה הטבלה דרשו מעברים. + +העיצוב החדש משתמש בטבלה מאוחדת אחת עבור כל נתוני שורה: + +```sql +CREATE TABLE rows ( + collection text, + schema_name text, + index_name text, + index_value frozen>, + data map, + source text, + PRIMARY KEY ((collection, schema_name, index_name), index_value) +) +``` + +#### הגדרות עמודות + +| עמודה | סוג | תיאור | +|--------|------|-------------| +| `collection` | `text` | מזהה איסוף/ייבוא נתונים (ממטא-נתונים) | +| `schema_name` | `text` | שם הסכימה אליה השורה הזו מתאימה | +| `index_name` | `text` | שם השדה/ים המאומדד, מחובר באמצעות פסיק עבור אינדקסים מורכבים | +| `index_value` | `frozen>` | ערכי האינדקס כרשימה | +| `data` | `map` | נתוני השורה כזוגות מפתח-ערך | +| `source` | `text` | URI אופציונלי המקשר למידע על מקור בגרף הידע. מחרוזת ריקה או NULL מציינים שאין מקור. | + +#### טיפול באינדקסים + +כל שורה מאוחסנת מספר פעמים - פעם אחת עבור כל שדה מאומדד המוגדר בסכימה. שדות המפתח הראשוניים מטופלים כאינדקס ללא סימון מיוחד, מה שמספק גמישות עתידית. + +**דוגמה לאינדקס של שדה בודד:** +הסכימה מגדירה את `email` כמאומדד +`index_name = "email"` +`index_value = ['foo@bar.com']` + +**דוגמה לאינדקס מורכב:** +הסכימה מגדירה אינדקס מורכב על `region` ו-`status` +`index_name = "region,status"` (שמות השדות ממוינים ומחוברים באמצעות פסיק) +`index_value = ['US', 'active']` (הערכים באותו סדר כמו שמות השדות) + +**דוגמה למפתח ראשי:** +הסכימה מגדירה את `customer_id` כמפתח ראשי +`index_name = "customer_id"` +`index_value = ['CUST001']` + +#### תבניות שאילתה + +כל השאילתות עוקבות אחר אותו תבנית, ללא קשר לאיזה אינדקס משתמשים: + +```sql +SELECT * FROM rows +WHERE collection = 'import_2024' + AND schema_name = 'customers' + AND index_name = 'email' + AND index_value = ['foo@bar.com'] +``` + +#### פשרות עיצוביות + +**יתרונות:** +שינויים בסכימה אינם מחייבים שינויים במבנה הטבלה +נתוני השורה אינם גלויים ל-Cassandra - הוספות/הסרות שדות הן שקופות +דפוס שאילתות עקבי לכל שיטות הגישה +אין אינדקסים משניים של Cassandra (שיכולים להיות איטיים בקנה מידה גדול) +סוגי Cassandra מקוריים בכל מקום (`map`, `frozen`) + +**פשרות:** +הגברה בכתיבה: כל הוספת שורה = N הוספות (אחת לכל שדה מועדן) +תקורה של אחסון עקב שכפול נתוני שורה +מידע על סוגים מאוחסן בתצורת הסכימה, המרה בשכבת האפליקציה + +#### מודל עקביות + +העיצוב מקבל מספר פישוטים: + +1. **אין עדכוני שורות**: המערכת היא רק להוספה. זה מבטל חששות לגבי עקביות בעדכון עותקים מרובים של אותה שורה. + +2. **סובלנות לשינויי סכימה**: כאשר הסכימות משתנות (לדוגמה, הוספת/הסרת אינדקסים), שורות קיימות שומרות על האינדוקס המקורי שלהן. שורות ישנות לא יהיו ניתנות לגילוי באמצעות אינדקסים חדשים. משתמשים יכולים למחוק וליצור מחדש סכימה כדי להבטיח עקביות במידת הצורך. + +### מעקב ומחיקת מחיצות + +#### הבעיה + +עם מפתח המחיצה `(collection, schema_name, index_name)`, מחיקה יעילה דורשת ידיעת כל מפתחות המחיצה למחיקה. מחיקה רק לפי `collection` או `collection + schema_name` דורשת ידיעת כל ערכי `index_name` שיש להם נתונים. + +#### טבלת מעקב מחיצות + +טבלת חיפוש משנית עוקבת אחר אילו מחיצות קיימות: + +```sql +CREATE TABLE row_partitions ( + collection text, + schema_name text, + index_name text, + PRIMARY KEY ((collection), schema_name, index_name) +) +``` + +זה מאפשר גילוי יעיל של מחיצות עבור פעולות מחיקה. + +#### התנהגות של כותב שורות + +כותב השורות שומר מטמון בזיכרון של זוגות `(collection, schema_name)` רשומים. בעת עיבוד שורה: + +1. בדוק אם `(collection, schema_name)` נמצא במטמון +2. אם לא שמור במטמון (השורה הראשונה עבור זוג זה): + חפש את תצורת הסכימה כדי לקבל את כל שמות האינדקסים + הכנס ערכים ל-`row_partitions` עבור כל `(collection, schema_name, index_name)` + הוסף את הזוג למטמון +3. המשך בכתיבת נתוני השורה + +כותב השורות גם עוקב אחר אירועי שינוי בתצורת הסכימה. כאשר סכימה משתנה, רשומות מטמון רלוונטיות נמחקים כך שהשורה הבאה תגרום לרישום מחדש עם שמות האינדקסים המעודכנים. + +גישה זו מבטיחה: +כתיבות לטבלת חיפוש מתרחשות פעם אחת לכל זוג `(collection, schema_name)`, ולא לכל שורה +טבלת החיפוש משקפת את האינדקסים שהיו פעילים בעת כתיבת הנתונים +שינויי סכימה במהלך הייבוא מזוהים כראוי + +#### פעולות מחיקה + +**מחיקת אוסף:** +```sql +-- 1. Discover all partitions +SELECT schema_name, index_name FROM row_partitions WHERE collection = 'X'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = '...' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table +DELETE FROM row_partitions WHERE collection = 'X'; +``` + +**מחיקת אוסף וסכימה:** +```sql +-- 1. Discover partitions for this schema +SELECT index_name FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = 'Y' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table entries +DELETE FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; +``` + +### הטמעות שורות + +הטמעות שורות מאפשרות התאמה סמנטית/עמומה על ערכים מוענקים, תוך פתרון בעיית אי ההתאמה בשפה טבעית (לדוגמה, מציאת "CHESTNUT ST" בעת חיפוש עבור "Chestnut Street"). + +#### סקירה כללית של העיצוב + +כל ערך מוענק מוטמע ונשמר במאגר וקטורים (Qdrant). בזמן שאילתה, השאילתה מוטמעת, וקטורים דומים נמצאים, ומטא-הנתונים המשויכים משמשים לאחזור השורות בפועל ב-Cassandra. + +#### מבנה אוסף Qdrant + +אוסף Qdrant אחד לכל טופל `(user, collection, schema_name, dimension)`: + +**שם האוסף:** `rows_{user}_{collection}_{schema_name}_{dimension}` +השמות עוברים סינון (תווים שאינם אלפא-נומריים מוחלפים ב-`_`, אותיות קטנות, קידומות מספריות מקבלות קידומת `r_`) +**ההצדקה:** מאפשר מחיקה נקייה של מופע `(user, collection, schema_name)` על ידי מחיקת אוספי Qdrant תואמים; הסיומת של הממד מאפשרת למודלי הטמעה שונים להתקיים יחד. + +#### מה מוטמע + +הייצוג הטקסטואלי של ערכי אינדקס: + +| סוג אינדקס | דוגמה `index_value` | טקסט להטמעה | +|------------|----------------------|---------------| +| שדה בודד | `['foo@bar.com']` | `"foo@bar.com"` | +| מורכב | `['US', 'active']` | `"US active"` (מחוברים באמצעות רווח) | + +#### מבנה נקודה + +כל נקודה ב-Qdrant מכילה: + +```json +{ + "id": "", + "vector": [0.1, 0.2, ...], + "payload": { + "index_name": "street_name", + "index_value": ["CHESTNUT ST"], + "text": "CHESTNUT ST" + } +} +``` + +| שדה מטען | תיאור | +|---------------|-------------| +| `index_name` | השדות המאופיינים בהטמעה זו | +| `index_value` | הרשימה המקורית של הערכים (לחיפוש בקסנדרה) | +| `text` | הטקסט שהוטמע (לצרכי ניפוי באגים/הצגה) | + +הערה: `user`, `collection` ו-`schema_name` משתמעים משם האוסף של Qdrant. + +#### זרימת שאילתה + +1. משתמש מבקש מידע על "Chestnut Street" בתוך משתמש U, אוסף X, סכימה Y. +2. הטמע את טקסט השאילתה. +3. קבע את שם/שמות האוסף של Qdrant התואמים לפריט `rows_U_X_Y_`. +4. חפש באוספי Qdrant התואמים את הווקטורים הקרובים ביותר. +5. קבל נקודות תואמות עם מטענים המכילים `index_name` ו-`index_value`. +6. שאילתת קסנדרה: + ```sql + SELECT * FROM rows + WHERE collection = 'X' + AND schema_name = 'Y' + AND index_name = '' + AND index_value = + ``` +7. החזרת שורות תואמות + +#### אופציונלי: סינון לפי שם אינדקס + +שאילתות יכולות, באופן אופציונלי, לסנן לפי `index_name` ב-Qdrant כדי לחפש רק שדות ספציפיים: + +**"מצא כל שדה התואם ל-'Chestnut'"** → חיפוש בכל הווקטורים באוסף +**"מצא את street_name התואם ל-'Chestnut'"** → סינון כאשר `payload.index_name = 'street_name'` + +#### ארכיטקטורה + +הטמעות שורות עוקבות את ה**תבנית בשני שלבים** המשמשת את GraphRAG (graph-embeddings, document-embeddings): + +**שלב 1: חישוב הטמעה** (`trustgraph-flow/trustgraph/embeddings/row_embeddings/`) - צורך `ExtractedObject`, מחשב הטמעות באמצעות שירות ההטמעות, מוציא `RowEmbeddings` +**שלב 2: אחסון הטמעה** (`trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/`) - צורך `RowEmbeddings`, כותב וקטורים ל-Qdrant + +כותב השורות של Cassandra הוא צרכן מקבילי נפרד: + +**כותב שורות Cassandra** (`trustgraph-flow/trustgraph/storage/rows/cassandra`) - צורך `ExtractedObject`, כותב שורות ל-Cassandra + +שלושת השירותים צורכים מאותו זרימה, תוך שמירה על הפרדה ביניהם. זה מאפשר: +התאמה עצמאית של כתיבת Cassandra לעומת יצירת הטמעות לעומת אחסון וקטורים +ניתן להשבית שירותי הטמעות אם אינם נחוצים +כשל בשירות אחד לא משפיע על השירותים האחרים +ארכיטקטורה עקבית עם צינורות GraphRAG + +#### נתיב כתיבה + +**שלב 1 (מעבד הטמעות שורות):** בעת קבלת `ExtractedObject`: + +1. חפש את הסכימה כדי למצוא שדות מודדים +2. עבור כל שדה מודד: + בנה את הייצוג הטקסטואלי של ערך האינדקס + חשב הטמעה באמצעות שירות ההטמעות +3. הפק פלט הודעה `RowEmbeddings` המכילה את כל הווקטורים שחושבו + +**שלב 2 (כתיבת הטמעות שורות ל-Qdrant):** בעת קבלת `RowEmbeddings`: + +1. עבור כל הטמעה בהודעה: + קבע את האוסף של Qdrant מ-`(user, collection, schema_name, dimension)` + צור אוסף אם יש צורך (יצירה עצלה בכתיבה הראשונה) + הוסף נקודה עם וקטור ו-payload + +#### סוגי הודעות + +```python +@dataclass +class RowIndexEmbedding: + index_name: str # The indexed field name(s) + index_value: list[str] # The field value(s) + text: str # Text that was embedded + vectors: list[list[float]] # Computed embedding vectors + +@dataclass +class RowEmbeddings: + metadata: Metadata + schema_name: str + embeddings: list[RowIndexEmbedding] +``` + +#### אינטגרציה של מחיקה + +אוספי Qdrant מתגלים באמצעות התאמה מקדימה של תבנית שם האוסף: + +**מחיקת `(user, collection)`:** +1. רשום את כל אוספי Qdrant התואמים לקידומת `rows_{user}_{collection}_` +2. מחק כל אוסף תואם +3. מחק מחיצות שורות Cassandra (כפי שמפורט לעיל) +4. נקה רשומות `row_partitions` + +**מחיקת `(user, collection, schema_name)`:** +1. רשום את כל אוספי Qdrant התואמים לקידומת `rows_{user}_{collection}_{schema_name}_` +2. מחק כל אוסף תואם (מטפל בממדים מרובים) +3. מחק מחיצות שורות Cassandra +4. נקה `row_partitions` + +#### מיקומי מודולים + +| שלב | מודול | נקודת כניסה | +|-------|--------|-------------| +| שלב 1 | `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | `row-embeddings` | +| שלב 2 | `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | `row-embeddings-write-qdrant` | + +### API לשאילתות הטמעות שורות + +שאילתת הטמעות השורות היא **API נפרד** משירות שאילתות השורות GraphQL: + +| API | מטרה | בסיס נתונים | +|-----|---------|---------| +| שאילתת שורות (GraphQL) | התאמה מדויקת בשדות מועדנים | Cassandra | +| שאילתת הטמעות שורות | התאמה מעורפלת/סמנטית | Qdrant | + +הפרדה זו שומרת על הפרדת אחריות: +שירות GraphQL מתמקד בשאילתות מדויקות ומובנות +ממשק הטמעות מטפל בדמיון סמנטי +זרימת עבודה של משתמש: חיפוש מעורפל באמצעות הטמעות כדי למצוא מועמדים, ולאחר מכן שאילתה מדויקת כדי לקבל את נתוני השורה המלאים + +#### סכימת בקשה/תגובה + +```python +@dataclass +class RowEmbeddingsRequest: + vectors: list[list[float]] # Query vectors (pre-computed embeddings) + user: str = "" + collection: str = "" + schema_name: str = "" + index_name: str = "" # Optional: filter to specific index + limit: int = 10 # Max results per vector + +@dataclass +class RowIndexMatch: + index_name: str = "" # The matched index field(s) + index_value: list[str] = [] # The matched value(s) + text: str = "" # Original text that was embedded + score: float = 0.0 # Similarity score + +@dataclass +class RowEmbeddingsResponse: + error: Error | None = None + matches: list[RowIndexMatch] = [] +``` + +#### מעבד שאילתות + +מודול: `trustgraph-flow/trustgraph/query/row_embeddings/qdrant` + +נקודת כניסה: `row-embeddings-query-qdrant` + +המעבד: +1. מקבל `RowEmbeddingsRequest` עם וקטורי שאילתה +2. מוצא את אוסף Qdrant המתאים באמצעות התאמה מקדימה +3. מחפש את הווקטורים הקרובים ביותר עם מסנן אופציונלי `index_name` +4. מחזיר `RowEmbeddingsResponse` עם מידע אינדקס תואם + +#### אינטגרציה עם שער API + +השער חושף שאילתות הטבעה של שורות באמצעות תבנית בקשה/תגובה סטנדרטית: + +| רכיב | מיקום | +|-----------|----------| +| מפזר | `trustgraph-flow/trustgraph/gateway/dispatch/row_embeddings_query.py` | +| רישום | הוסף `"row-embeddings"` ל-`request_response_dispatchers` ב-`manager.py` | + +שם ממשק זרימה: `row-embeddings` + +הגדרת ממשק בתרשים זרימה: +```json +{ + "interfaces": { + "row-embeddings": { + "request": "non-persistent://tg/request/row-embeddings:{id}", + "response": "non-persistent://tg/response/row-embeddings:{id}" + } + } +} +``` + +#### תמיכה ב-SDK של Python + +ה-SDK מספק שיטות לשאילתות הטמעות שורות: + +```python +# Flow-scoped query (preferred) +api = Api(url) +flow = api.flow().id("default") + +# Query with text (SDK computes embeddings) +matches = flow.row_embeddings_query( + text="Chestnut Street", + collection="my_collection", + schema_name="addresses", + index_name="street_name", # Optional filter + limit=10 +) + +# Query with pre-computed vectors +matches = flow.row_embeddings_query( + vectors=[[0.1, 0.2, ...]], + collection="my_collection", + schema_name="addresses" +) + +# Each match contains: +for match in matches: + print(match.index_name) # e.g., "street_name" + print(match.index_value) # e.g., ["CHESTNUT ST"] + print(match.text) # e.g., "CHESTNUT ST" + print(match.score) # e.g., 0.95 +``` + +#### כלי שורת הפקודה + +פקודה: `tg-invoke-row-embeddings` + +```bash +# Query by text (computes embedding automatically) +tg-invoke-row-embeddings \ + --text "Chestnut Street" \ + --collection my_collection \ + --schema addresses \ + --index street_name \ + --limit 10 + +# Query by vector file +tg-invoke-row-embeddings \ + --vectors vectors.json \ + --collection my_collection \ + --schema addresses + +# Output formats +tg-invoke-row-embeddings --text "..." --format json +tg-invoke-row-embeddings --text "..." --format table +``` + +#### דוגמה טיפוסית לשימוש + +שאילתת הטמעות השורות משמשת בדרך כלל כחלק מזרימת חיפוש "מעורפל" לחיפוש מדויק: + +```python +# Step 1: Fuzzy search via embeddings +matches = flow.row_embeddings_query( + text="chestnut street", + collection="geo", + schema_name="streets" +) + +# Step 2: Exact lookup via GraphQL for full row data +for match in matches: + query = f''' + query {{ + streets(where: {{ {match.index_name}: {{ eq: "{match.index_value[0]}" }} }}) {{ + street_name + city + zip_code + }} + }} + ''' + rows = flow.rows_query(query, collection="geo") +``` + +דפוס בן שני שלבים זה מאפשר: +מציאת "CHESTNUT ST" כאשר המשתמש מחפש "Chestnut Street" +שליפת נתוני שורה שלמים עם כל השדות +שילוב של דמיון סמנטי עם גישה לנתונים מובנים + +### קליטת נתוני שורה + +נדחה לשלב מאוחר יותר. יתוכנן יחד עם שינויי קליטה אחרים. + +## השפעה על יישום + +### ניתוח מצב נוכחי + +ליישום הקיים יש שני מרכיבים עיקריים: + +| רכיב | מיקום | שורות | תיאור | +|-----------|----------|-------|-------------| +| שירות שאילתות | `trustgraph-flow/trustgraph/query/objects/cassandra/service.py` | ~740 | מונוליטי: יצירת סכימת GraphQL, ניתוח פילטרים, שאילתות Cassandra, טיפול בבקשות | +| כותב | `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` | ~540 | יצירת טבלאות לפי סכימה, אינדקסים משניים, הוספה/מחיקה | + +**דפוס שאילתות נוכחי:** +```sql +SELECT * FROM {keyspace}.o_{schema_name} +WHERE collection = 'X' AND email = 'foo@bar.com' +ALLOW FILTERING +``` + +**תבנית שאילתה חדשה:** +```sql +SELECT * FROM {keyspace}.rows +WHERE collection = 'X' AND schema_name = 'customers' + AND index_name = 'email' AND index_value = ['foo@bar.com'] +``` + +### שינויים מרכזיים + +1. **הפשטת סמנטיקת שאילתות**: הסכימה החדשה תומכת רק בהתאמות מדויקות עבור `index_value`. מסנני ה-GraphQL הנוכחיים (`gt`, `lt`, `contains`, וכו') או: + הופכים לסינון לאחר קבלת הנתונים (אם עדיין נדרש) + מוסרים לטובת שימוש ב-API של הטמעות (embeddings) לביצוע התאמות משוערות + +2. **קוד GraphQL משולב הדוק**: ה-`service.py` הנוכחי כולל יצירת טיפוסים של Strawberry, ניתוח מסננים ושאילתות ספציפיות ל-Cassandra. הוספת בסיס נתונים טבלאי נוסף תכפיל כ-400 שורות של קוד GraphQL. + +### שינוי מבנה מוצע + +השינוי המבני כולל שני חלקים: + +#### 1. הפרדת קוד GraphQL + +חילוץ רכיבי GraphQL שניתן לעשות בהם שימוש חוזר למודול משותף: + +``` +trustgraph-flow/trustgraph/query/graphql/ +├── __init__.py +├── types.py # Filter types (IntFilter, StringFilter, FloatFilter) +├── schema.py # Dynamic schema generation from RowSchema +└── filters.py # Filter parsing utilities +``` + +זה מאפשר: +שימוש חוזר בין בסיסי נתונים שונים +הפרדה נקייה יותר של תחומים +בדיקה קלה יותר של לוגיקת GraphQL באופן עצמאי + +#### 2. יישום סכימת טבלה חדשה + +שינוי הקוד הספציפי ל-Cassandra לשימוש בטבלה המאוחדת: + +**כותב** (`trustgraph-flow/trustgraph/storage/rows/cassandra/`): +טבלה אחת של `rows` במקום טבלאות לכל סכימה +כתיבת N עותקים לשורה (אחד לכל אינדקס) +רישום לטבלה `row_partitions` +יצירת טבלה פשוטה יותר (הגדרה חד-פעמית) + +**שירות שאילתות** (`trustgraph-flow/trustgraph/query/rows/cassandra/`): +שאילתא של הטבלה המאוחדת `rows` +שימוש במודול GraphQL חלץ ליצירת סכימה +טיפול פשוט יותר בסינון (התאמה מדויקת בלבד ברמת מסד הנתונים) + +### שינוי שמות מודולים + +כחלק מניקוי השמות מ-"object" ל-"row": + +| נוכחי | חדש | +|---------|-----| +| `storage/objects/cassandra/` | `storage/rows/cassandra/` | +| `query/objects/cassandra/` | `query/rows/cassandra/` | +| `embeddings/object_embeddings/` | `embeddings/row_embeddings/` | + +### מודולים חדשים + +| מודול | מטרה | +|--------|---------| +| `trustgraph-flow/trustgraph/query/graphql/` | כלי GraphQL משותפים | +| `trustgraph-flow/trustgraph/query/row_embeddings/qdrant/` | ממשק API לשאילתות הטמעות שורות | +| `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | חישוב הטמעות שורות (שלב 1) | +| `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | אחסון הטמעות שורות (שלב 2) | + +## הפניות + +[מפרט טכני של נתונים מובנים](structured-data.md) diff --git a/docs/tech-specs/structured-data-2.hi.md b/docs/tech-specs/structured-data-2.hi.md new file mode 100644 index 00000000..4738fac7 --- /dev/null +++ b/docs/tech-specs/structured-data-2.hi.md @@ -0,0 +1,613 @@ +# संरचित डेटा तकनीकी विनिर्देश (भाग 2) + +## अवलोकन + +यह विनिर्देश उन मुद्दों और कमियों को संबोधित करता है जिन्हें ट्रस्टग्राफ के संरचित डेटा एकीकरण के प्रारंभिक कार्यान्वयन के दौरान पहचाना गया था, जैसा कि `structured-data.md` में वर्णित है। + +## समस्या विवरण + +### 1. नामकरण में असंगति: "ऑब्जेक्ट" बनाम "पंक्ति" + +वर्तमान कार्यान्वयन में पूरे समय "ऑब्जेक्ट" शब्दावली का उपयोग किया जाता है (उदाहरण के लिए, `ExtractedObject`, ऑब्जेक्ट निष्कर्षण, ऑब्जेक्ट एम्बेडिंग)। यह नामकरण बहुत सामान्य है और भ्रम पैदा करता है: + +"ऑब्जेक्ट" सॉफ्टवेयर में एक अतिव्यापी शब्द है (पायथन ऑब्जेक्ट, JSON ऑब्जेक्ट, आदि)। +संसाधित डेटा अनिवार्य रूप से सारणीबद्ध है - परिभाषित स्कीमा वाली तालिकाओं में पंक्तियाँ। +"पंक्ति" डेटा मॉडल का अधिक सटीक वर्णन है और यह डेटाबेस शब्दावली के साथ मेल खाता है। + +यह असंगति मॉड्यूल नामों, क्लास नामों, संदेश प्रकारों और दस्तावेज़ों में दिखाई देती है। + +### 2. पंक्ति भंडारण क्वेरी सीमाएँ + +वर्तमान पंक्ति भंडारण कार्यान्वयन में महत्वपूर्ण क्वेरी सीमाएँ हैं: + +**प्राकृतिक भाषा बेमेल**: क्वेरी वास्तविक दुनिया के डेटा विविधताओं के साथ संघर्ष करती हैं। उदाहरण के लिए: +`"CHESTNUT ST"` युक्त एक सड़क डेटाबेस को `"Chestnut Street"` के बारे में पूछने पर खोजना मुश्किल है। +संक्षिप्त नाम, केस अंतर और स्वरूपण भिन्नताएं सटीक-मेल क्वेरी को तोड़ देती हैं। +उपयोगकर्ताओं को सिमेंटिक समझ की उम्मीद होती है, लेकिन स्टोर शाब्दिक मिलान प्रदान करता है। + +**स्कीमा विकास मुद्दे**: स्कीमा में परिवर्तन समस्याएं पैदा करते हैं: +मौजूदा डेटा अद्यतन स्कीमा के अनुरूप नहीं हो सकता है। +तालिका संरचना में परिवर्तन क्वेरी और डेटा अखंडता को तोड़ सकते हैं। +स्कीमा अपडेट के लिए कोई स्पष्ट माइग्रेशन पथ नहीं है। + +### 3. पंक्ति एम्बेडिंग की आवश्यकता + +समस्या 2 से संबंधित, सिस्टम को पंक्ति डेटा के लिए वेक्टर एम्बेडिंग की आवश्यकता है ताकि: + +संरचित डेटा में सिमेंटिक खोज (जब डेटा में "CHESTNUT ST" हो तो "Chestnut Street" खोजना)। +धुंधली क्वेरी के लिए समानता मिलान। +संरचित फ़िल्टर को सिमेंटिक समानता के साथ मिलाने वाली हाइब्रिड खोज। +बेहतर प्राकृतिक भाषा क्वेरी समर्थन। + +एम्बेडिंग सेवा को निर्दिष्ट किया गया था लेकिन लागू नहीं किया गया था। + +### 4. पंक्ति डेटा अंतर्ग्रहण अधूरा + +संरचित डेटा अंतर्ग्रहण पाइपलाइन पूरी तरह से कार्यात्मक नहीं है: + +इनपुट प्रारूपों (CSV, JSON, आदि) को वर्गीकृत करने के लिए नैदानिक संकेत मौजूद हैं। +इन संकेतों का उपयोग करने वाली अंतर्ग्रहण सेवा को सिस्टम में प्लंब नहीं किया गया है। +पंक्ति स्टोर में पूर्व-संरचित डेटा लोड करने के लिए कोई एंड-टू-एंड पथ नहीं है। + +## लक्ष्य + +**स्कीमा लचीलापन**: मौजूदा डेटा को तोड़ने या माइग्रेशन की आवश्यकता के बिना स्कीमा विकास को सक्षम करें। +**संगत नामकरण**: पूरे कोडबेस में "पंक्ति" शब्दावली का मानकीकरण करें। +**सिमेंटिक क्वेरी क्षमता**: पंक्ति एम्बेडिंग के माध्यम से धुंधली/सिमेंटिक मिलान का समर्थन करें। +**पूर्ण अंतर्ग्रहण पाइपलाइन**: संरचित डेटा लोड करने के लिए एंड-टू-एंड पथ प्रदान करें। + +## तकनीकी डिजाइन + +### एकीकृत पंक्ति भंडारण स्कीमा + +पिछले कार्यान्वयन में प्रत्येक स्कीमा के लिए एक अलग कैसेंड्रा तालिका बनाई गई थी। इससे तब समस्याएं हुईं जब स्कीमा विकसित हुए, क्योंकि तालिका संरचना में परिवर्तन के लिए माइग्रेशन की आवश्यकता होती थी। + +नए डिज़ाइन में सभी पंक्ति डेटा के लिए एक एकल, एकीकृत तालिका का उपयोग किया जाता है: + +```sql +CREATE TABLE rows ( + collection text, + schema_name text, + index_name text, + index_value frozen>, + data map, + source text, + PRIMARY KEY ((collection, schema_name, index_name), index_value) +) +``` + +#### कॉलम परिभाषाएँ + +| कॉलम | प्रकार | विवरण | +|--------|------|-------------| +| `collection` | `text` | डेटा संग्रह/आयात पहचानकर्ता (मेटाडेटा से) | +| `schema_name` | `text` | स्कीमा का नाम जिससे यह पंक्ति मेल खाती है | +| `index_name` | `text` | अनुक्रमित फ़ील्ड का नाम, संयुक्त अल्पविराम के साथ (मिश्रित के लिए) | +| `index_value` | `frozen>` | अनुक्रमित मानों की सूची | +| `data` | `map` | पंक्ति डेटा कुंजी-मान जोड़े के रूप में | +| `source` | `text` | वैकल्पिक यूआरआई जो नॉलेज ग्राफ में मूल जानकारी से लिंक करता है। खाली स्ट्रिंग या NULL इंगित करता है कि कोई स्रोत नहीं है। | + +#### अनुक्रमण प्रबंधन + +प्रत्येक पंक्ति कई बार संग्रहीत की जाती है - स्कीमा में परिभाषित प्रत्येक अनुक्रमित फ़ील्ड के लिए एक बार। प्राथमिक कुंजी फ़ील्ड को किसी विशेष मार्कर के बिना एक अनुक्रमणिका के रूप में माना जाता है, जो भविष्य में लचीलापन प्रदान करता है। + +**सिंगल-फ़ील्ड अनुक्रमणिका का उदाहरण:** +स्कीमा `email` को अनुक्रमित के रूप में परिभाषित करता है +`index_name = "email"` +`index_value = ['foo@bar.com']` + +**मिश्रित अनुक्रमणिका का उदाहरण:** +स्कीमा `region` और `status` पर मिश्रित अनुक्रमणिका को परिभाषित करता है +`index_name = "region,status"` (फ़ील्ड नाम क्रमबद्ध और अल्पविराम से जुड़े हुए) +`index_value = ['US', 'active']` (फ़ील्ड नामों के समान क्रम में मान) + +**प्राथमिक कुंजी का उदाहरण:** +स्कीमा `customer_id` को प्राथमिक कुंजी के रूप में परिभाषित करता है +`index_name = "customer_id"` +`index_value = ['CUST001']` + +#### क्वेरी पैटर्न + +सभी क्वेरी एक ही पैटर्न का पालन करती हैं, चाहे कोई भी अनुक्रमणिका उपयोग की जाए: + +```sql +SELECT * FROM rows +WHERE collection = 'import_2024' + AND schema_name = 'customers' + AND index_name = 'email' + AND index_value = ['foo@bar.com'] +``` + +#### डिज़ाइन में संतुलन + +**लाभ:** +स्कीमा में बदलावों के लिए टेबल संरचना में बदलाव की आवश्यकता नहीं होती है। +पंक्ति डेटा कैसेंड्रा के लिए अस्पष्ट है - फ़ील्ड जोड़ने/हटाने से कोई फर्क नहीं पड़ता। +सभी एक्सेस विधियों के लिए सुसंगत क्वेरी पैटर्न। +कोई कैसेंड्रा सेकेंडरी इंडेक्स नहीं (जो बड़े पैमाने पर धीमे हो सकते हैं)। +पूरी तरह से देशी कैसेंड्रा प्रकार (`map`, `frozen`)। + +**गड़बड़ियाँ:** +राइट एम्प्लीफिकेशन: प्रत्येक पंक्ति डालने = N डालने (प्रत्येक इंडेक्स्ड फ़ील्ड के लिए एक)। +डुप्लिकेट पंक्ति डेटा के कारण स्टोरेज ओवरहेड। +प्रकार की जानकारी स्कीमा कॉन्फ़िगरेशन में संग्रहीत है, एप्लिकेशन लेयर पर रूपांतरण। + +#### संगति मॉडल + +डिज़ाइन कुछ सरलीकरणों को स्वीकार करता है: + +1. **कोई पंक्ति अपडेट नहीं**: सिस्टम केवल अपेंड-ओनली है। यह एक ही पंक्ति की कई प्रतियों को अपडेट करने के बारे में संगति संबंधी चिंताओं को समाप्त करता है। + +2. **स्कीमा परिवर्तन सहिष्णुता**: जब स्कीमा बदलते हैं (उदाहरण के लिए, इंडेक्स जोड़े/हटाए जाते हैं), तो मौजूदा पंक्तियाँ अपनी मूल इंडेक्सिंग को बनाए रखती हैं। पुराने पंक्तियों को नए इंडेक्स के माध्यम से खोजा नहीं जा सकता है। यदि आवश्यक हो, तो उपयोगकर्ता संगति सुनिश्चित करने के लिए एक स्कीमा को हटा और पुनः बना सकते हैं। + +### विभाजन ट्रैकिंग और हटाना + +#### समस्या + +विभाजन कुंजी `(collection, schema_name, index_name)` के साथ, कुशल हटाने के लिए सभी विभाजन कुंजियों को हटाने की आवश्यकता होती है। केवल `collection` या `collection + schema_name` द्वारा हटाना उन सभी `index_name` मानों को जानने की आवश्यकता होती है जिनमें डेटा है। + +#### विभाजन ट्रैकिंग टेबल + +एक सेकेंडरी लुकअप टेबल ट्रैक करती है कि कौन से विभाजन मौजूद हैं: + +```sql +CREATE TABLE row_partitions ( + collection text, + schema_name text, + index_name text, + PRIMARY KEY ((collection), schema_name, index_name) +) +``` + +यह हटाने के कार्यों के लिए विभाजनों की कुशल खोज को सक्षम बनाता है। + +#### पंक्ति लेखक व्यवहार + +पंक्ति लेखक पंजीकृत `(collection, schema_name)` युग्मों का एक इन-मेमोरी कैश बनाए रखता है। पंक्ति को संसाधित करते समय: + +1. जांचें कि `(collection, schema_name)` कैश में है या नहीं। +2. यदि कैश में नहीं है (इस युग्म के लिए पहली पंक्ति): + सभी इंडेक्स नामों को प्राप्त करने के लिए स्कीमा कॉन्फ़िगरेशन देखें। + प्रत्येक `(collection, schema_name, index_name)` के लिए `row_partitions` में प्रविष्टियाँ डालें। + युग्म को कैश में जोड़ें। +3. पंक्ति डेटा लिखने के साथ आगे बढ़ें। + +पंक्ति लेखक स्कीमा कॉन्फ़िगरेशन परिवर्तन घटनाओं की भी निगरानी करता है। जब कोई स्कीमा बदलता है, तो प्रासंगिक कैश प्रविष्टियाँ साफ़ कर दी जाती हैं ताकि अगली पंक्ति अपडेट किए गए इंडेक्स नामों के साथ पुनः पंजीकरण को ट्रिगर करे। + +इस दृष्टिकोण से यह सुनिश्चित होता है: +लुकअप तालिका लेखन प्रत्येक `(collection, schema_name)` युग्म के लिए एक बार होता है, प्रत्येक पंक्ति के लिए नहीं। +लुकअप तालिका उन इंडेक्स को दर्शाती है जो डेटा लिखे जाने पर सक्रिय थे। +आयात के दौरान होने वाले स्कीमा परिवर्तनों को सही ढंग से पहचाना जाता है। + +#### हटाने के कार्य + +**संग्रह हटाएं:** +```sql +-- 1. Discover all partitions +SELECT schema_name, index_name FROM row_partitions WHERE collection = 'X'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = '...' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table +DELETE FROM row_partitions WHERE collection = 'X'; +``` + +**संग्रह और स्कीमा हटाएं:** +```sql +-- 1. Discover partitions for this schema +SELECT index_name FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = 'Y' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table entries +DELETE FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; +``` + +### पंक्ति एम्बेडिंग + +पंक्ति एम्बेडिंग, अनुक्रमित मानों पर अर्थपूर्ण/अस्पष्ट मिलान को सक्षम करते हैं, जिससे प्राकृतिक भाषा में विसंगति की समस्या हल होती है (उदाहरण के लिए, "चेस्टनट स्ट्रीट" के लिए खोज करते समय "चेस्टनट एसटी" खोजना)। + +#### डिज़ाइन अवलोकन + +प्रत्येक अनुक्रमित मान को एम्बेड किया जाता है और एक वेक्टर स्टोर (क्यूड्रेंट) में संग्रहीत किया जाता है। क्वेरी के समय, क्वेरी को एम्बेड किया जाता है, समान वेक्टर पाए जाते हैं, और संबंधित मेटाडेटा का उपयोग कैसेंड्रा में वास्तविक पंक्तियों को देखने के लिए किया जाता है। + +#### क्यूड्रेंट संग्रह संरचना + +प्रत्येक `(user, collection, schema_name, dimension)` टपल के लिए एक क्यूड्रेंट संग्रह: + +**संग्रह नामकरण:** `rows_{user}_{collection}_{schema_name}_{dimension}` +नामों को साफ़ किया जाता है (गैर-अक्षरांकीय वर्णों को `_` से बदला जाता है, लोअरकेस किया जाता है, संख्यात्मक उपसर्गों को `r_` उपसर्ग मिलता है) +**तर्क:** एक `(user, collection, schema_name)` उदाहरण को मिलान वाले क्यूड्रेंट संग्रहों को हटाकर साफ-सुथरे तरीके से हटाने की अनुमति देता है; आयाम प्रत्यय विभिन्न एम्बेडिंग मॉडल को एक साथ मौजूद रहने की अनुमति देता है। + +#### क्या एम्बेड किया जाता है + +अनुक्रमण मानों का पाठ प्रतिनिधित्व: + +| अनुक्रमण प्रकार | उदाहरण `index_value` | एम्बेड करने के लिए पाठ | +|------------|----------------------|---------------| +| एकल-क्षेत्र | `['foo@bar.com']` | `"foo@bar.com"` | +| समग्र | `['US', 'active']` | `"US active"` (स्पेस-जोड़ा हुआ) | + +#### बिंदु संरचना + +प्रत्येक क्यूड्रेंट बिंदु में शामिल हैं: + +```json +{ + "id": "", + "vector": [0.1, 0.2, ...], + "payload": { + "index_name": "street_name", + "index_value": ["CHESTNUT ST"], + "text": "CHESTNUT ST" + } +} +``` + +| पेलोड फ़ील्ड | विवरण | +|---------------|-------------| +| `index_name` | यह एम्बेडिंग किस अनुक्रमित फ़ील्ड(s) का प्रतिनिधित्व करता है | +| `index_value` | मूल्यों की मूल सूची (कैसेंड्रा लुकअप के लिए) | +| `text` | वह पाठ जिसे एम्बेड किया गया था (डीबगिंग/प्रदर्शन के लिए) | + +ध्यान दें: `user`, `collection`, और `schema_name` Qdrant संग्रह नाम से निहित हैं। + +#### क्वेरी प्रवाह + +1. उपयोगकर्ता U, संग्रह X, स्कीमा Y के भीतर "चेस्टनट स्ट्रीट" के लिए क्वेरी करता है। +2. क्वेरी टेक्स्ट को एम्बेड करें। +3. उपसर्ग `rows_U_X_Y_` से मेल खाने वाले Qdrant संग्रह नाम(s) निर्धारित करें। +4. निकटतम वैक्टरों के लिए मिलान करने वाले Qdrant संग्रह(s) की खोज करें। +5. `index_name` और `index_value` युक्त पेलोड वाले मिलान करने वाले बिंदुओं को प्राप्त करें। +6. कैसेंड्रा को क्वेरी करें: + ```sql + SELECT * FROM rows + WHERE collection = 'X' + AND schema_name = 'Y' + AND index_name = '' + AND index_value = + ``` +7. मिलान किए गए पंक्तियों को वापस करना + +#### वैकल्पिक: इंडेक्स नाम द्वारा फ़िल्टरिंग + +क्वेरी वैकल्पिक रूप से Qdrant में `index_name` द्वारा फ़िल्टर की जा सकती हैं ताकि केवल विशिष्ट फ़ील्ड की खोज की जा सके: + +**"उन सभी फ़ील्ड को खोजें जो 'Chestnut' से मेल खाते हैं"** → संग्रह में सभी वैक्टर की खोज करें +**"उन सड़कों को खोजें जिनका नाम 'Chestnut' से मेल खाता है"** → उन पंक्तियों को फ़िल्टर करें जहाँ `payload.index_name = 'street_name'` + +#### आर्किटेक्चर + +पंक्ति एम्बेडिंग **दो-चरणीय पैटर्न** का पालन करते हैं जिसका उपयोग GraphRAG (ग्राफ-एम्बेडिंग, दस्तावेज़-एम्बेडिंग) द्वारा किया जाता है: + +**चरण 1: एम्बेडिंग गणना** (`trustgraph-flow/trustgraph/embeddings/row_embeddings/`) - `ExtractedObject` का उपयोग करता है, एम्बेडिंग सेवा के माध्यम से एम्बेडिंग की गणना करता है, `RowEmbeddings` आउटपुट करता है +**चरण 2: एम्बेडिंग भंडारण** (`trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/`) - `RowEmbeddings` का उपयोग करता है, वैक्टर को Qdrant में लिखता है + +कैसेंड्रा पंक्ति लेखक एक अलग समानांतर उपभोक्ता है: + +**कैसेंड्रा पंक्ति लेखक** (`trustgraph-flow/trustgraph/storage/rows/cassandra`) - `ExtractedObject` का उपयोग करता है, पंक्तियों को कैसेंड्रा में लिखता है + +तीनों सेवाएं एक ही प्रवाह से डेटा लेती हैं, जिससे वे अलग-अलग रहती हैं। यह अनुमति देता है: +कैसेंड्रा लेखन बनाम एम्बेडिंग पीढ़ी बनाम वेक्टर भंडारण का स्वतंत्र स्केलिंग +यदि आवश्यक न हो तो एम्बेडिंग सेवाओं को अक्षम किया जा सकता है +एक सेवा में विफलता अन्य सेवाओं को प्रभावित नहीं करती है +GraphRAG पाइपलाइनों के साथ सुसंगत आर्किटेक्चर + +#### लेखन पथ + +**चरण 1 (पंक्ति-एम्बेडिंग प्रोसेसर):** जब एक `ExtractedObject` प्राप्त होता है: + +1. अनुक्रमित फ़ील्ड खोजने के लिए स्कीमा देखें +2. प्रत्येक अनुक्रमित फ़ील्ड के लिए: + अनुक्रमण मान का पाठ प्रतिनिधित्व बनाएं + एम्बेडिंग सेवा के माध्यम से एम्बेडिंग की गणना करें +3. सभी गणना किए गए वैक्टर युक्त एक `RowEmbeddings` संदेश आउटपुट करें + +**चरण 2 (पंक्ति-एम्बेडिंग-लिखें-Qdrant):** जब एक `RowEmbeddings` प्राप्त होता है: + +1. संदेश में प्रत्येक एम्बेडिंग के लिए: + `(user, collection, schema_name, dimension)` से Qdrant संग्रह निर्धारित करें + यदि आवश्यक हो तो संग्रह बनाएं (पहली बार लिखने पर आलसी निर्माण) + वेक्टर और पेलोड के साथ पॉइंट अपサート करें + +#### संदेश प्रकार + +```python +@dataclass +class RowIndexEmbedding: + index_name: str # The indexed field name(s) + index_value: list[str] # The field value(s) + text: str # Text that was embedded + vectors: list[list[float]] # Computed embedding vectors + +@dataclass +class RowEmbeddings: + metadata: Metadata + schema_name: str + embeddings: list[RowIndexEmbedding] +``` + +#### विलोपन एकीकरण + +Qdrant संग्रह, संग्रह नाम पैटर्न पर उपसर्ग मिलान द्वारा खोजे जाते हैं: + +**`(user, collection)` हटाएं:** +1. `rows_{user}_{collection}_` उपसर्ग से मेल खाने वाले सभी Qdrant संग्रहों की सूची बनाएं +2. प्रत्येक मेल खाने वाले संग्रह को हटाएं +3. कैसेंड्रा पंक्तियों के विभाजन को हटाएं (जैसा कि ऊपर प्रलेखित है) +4. `row_partitions` प्रविष्टियों को साफ़ करें + +**`(user, collection, schema_name)` हटाएं:** +1. `rows_{user}_{collection}_{schema_name}_` उपसर्ग से मेल खाने वाले सभी Qdrant संग्रहों की सूची बनाएं +2. प्रत्येक मेल खाने वाले संग्रह को हटाएं (यह कई आयामों को संभालता है) +3. कैसेंड्रा पंक्तियों के विभाजन को हटाएं +4. `row_partitions` को साफ़ करें + +#### मॉड्यूल स्थान + +| चरण | मॉड्यूल | प्रवेश बिंदु | +|-------|--------|-------------| +| चरण 1 | `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | `row-embeddings` | +| चरण 2 | `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | `row-embeddings-write-qdrant` | + +### पंक्ति एम्बेडिंग क्वेरी एपीआई + +पंक्ति एम्बेडिंग क्वेरी, GraphQL पंक्ति क्वेरी सेवा से एक **अलग एपीआई** है: + +| एपीआई | उद्देश्य | बैकएंड | +|-----|---------|---------| +| पंक्ति क्वेरी (GraphQL) | अनुक्रमित फ़ील्ड पर सटीक मिलान | कैसेंड्रा | +| पंक्ति एम्बेडिंग क्वेरी | अस्पष्ट/अर्थ संबंधी मिलान | Qdrant | + +यह अलगाव चिंताओं को साफ रखता है: +GraphQL सेवा सटीक, संरचित प्रश्नों पर केंद्रित है +एम्बेडिंग एपीआई अर्थ संबंधी समानता को संभालता है +उपयोगकर्ता कार्यप्रवाह: उम्मीदवारों को खोजने के लिए एम्बेडिंग के माध्यम से अस्पष्ट खोज, फिर पूर्ण पंक्ति डेटा प्राप्त करने के लिए सटीक क्वेरी + +#### अनुरोध/प्रतिक्रिया स्कीमा + +```python +@dataclass +class RowEmbeddingsRequest: + vectors: list[list[float]] # Query vectors (pre-computed embeddings) + user: str = "" + collection: str = "" + schema_name: str = "" + index_name: str = "" # Optional: filter to specific index + limit: int = 10 # Max results per vector + +@dataclass +class RowIndexMatch: + index_name: str = "" # The matched index field(s) + index_value: list[str] = [] # The matched value(s) + text: str = "" # Original text that was embedded + score: float = 0.0 # Similarity score + +@dataclass +class RowEmbeddingsResponse: + error: Error | None = None + matches: list[RowIndexMatch] = [] +``` + +#### क्वेरी प्रोसेसर + +मॉड्यूल: `trustgraph-flow/trustgraph/query/row_embeddings/qdrant` + +प्रवेश बिंदु: `row-embeddings-query-qdrant` + +प्रोसेसर: +1. `RowEmbeddingsRequest` के साथ क्वेरी वेक्टर प्राप्त करता है +2. उपसर्ग मिलान के माध्यम से उपयुक्त Qdrant संग्रह ढूंढता है +3. वैकल्पिक `index_name` फ़िल्टर के साथ निकटतम वेक्टर खोजता है +4. मिलान किए गए इंडेक्स जानकारी के साथ `RowEmbeddingsResponse` लौटाता है + +#### एपीआई गेटवे एकीकरण + +गेटवे मानक अनुरोध/प्रतिक्रिया पैटर्न के माध्यम से पंक्ति एम्बेडिंग प्रश्नों को उजागर करता है: + +| घटक | स्थान | +|-----------|----------| +| डिस्पैचर | `trustgraph-flow/trustgraph/gateway/dispatch/row_embeddings_query.py` | +| पंजीकरण | `"row-embeddings"` को `request_response_dispatchers` में `manager.py` में जोड़ें | + +फ्लो इंटरफ़ेस नाम: `row-embeddings` + +फ्लो ब्लूप्रिंट में इंटरफ़ेस परिभाषा: +```json +{ + "interfaces": { + "row-embeddings": { + "request": "non-persistent://tg/request/row-embeddings:{id}", + "response": "non-persistent://tg/response/row-embeddings:{id}" + } + } +} +``` + +#### पायथन एसडीके समर्थन + +एसडीके पंक्ति एम्बेडिंग प्रश्नों के लिए विधियाँ प्रदान करता है: + +```python +# Flow-scoped query (preferred) +api = Api(url) +flow = api.flow().id("default") + +# Query with text (SDK computes embeddings) +matches = flow.row_embeddings_query( + text="Chestnut Street", + collection="my_collection", + schema_name="addresses", + index_name="street_name", # Optional filter + limit=10 +) + +# Query with pre-computed vectors +matches = flow.row_embeddings_query( + vectors=[[0.1, 0.2, ...]], + collection="my_collection", + schema_name="addresses" +) + +# Each match contains: +for match in matches: + print(match.index_name) # e.g., "street_name" + print(match.index_value) # e.g., ["CHESTNUT ST"] + print(match.text) # e.g., "CHESTNUT ST" + print(match.score) # e.g., 0.95 +``` + +#### कमांड लाइन यूटिलिटी + +कमांड: `tg-invoke-row-embeddings` + +```bash +# Query by text (computes embedding automatically) +tg-invoke-row-embeddings \ + --text "Chestnut Street" \ + --collection my_collection \ + --schema addresses \ + --index street_name \ + --limit 10 + +# Query by vector file +tg-invoke-row-embeddings \ + --vectors vectors.json \ + --collection my_collection \ + --schema addresses + +# Output formats +tg-invoke-row-embeddings --text "..." --format json +tg-invoke-row-embeddings --text "..." --format table +``` + +#### विशिष्ट उपयोग पैटर्न + +पंक्ति एम्बेडिंग क्वेरी का उपयोग आमतौर पर एक अस्पष्ट-से-सटीक लुकअप प्रवाह के हिस्से के रूप में किया जाता है: + +```python +# Step 1: Fuzzy search via embeddings +matches = flow.row_embeddings_query( + text="chestnut street", + collection="geo", + schema_name="streets" +) + +# Step 2: Exact lookup via GraphQL for full row data +for match in matches: + query = f''' + query {{ + streets(where: {{ {match.index_name}: {{ eq: "{match.index_value[0]}" }} }}) {{ + street_name + city + zip_code + }} + }} + ''' + rows = flow.rows_query(query, collection="geo") +``` + +यह दो-चरणीय पैटर्न निम्नलिखित को सक्षम करता है: +जब उपयोगकर्ता "Chestnut Street" खोजता है तो "CHESTNUT ST" खोजना। +सभी फ़ील्ड के साथ पूरी पंक्ति डेटा प्राप्त करना। +संरचित डेटा एक्सेस के साथ सिमेंटिक समानता को जोड़ना। + +### पंक्ति डेटा का अंतर्ग्रहण + +बाद के चरण में स्थगित। अन्य अंतर्ग्रहण परिवर्तनों के साथ मिलकर डिज़ाइन किया जाएगा। + +## कार्यान्वयन प्रभाव + +### वर्तमान स्थिति विश्लेषण + +मौजूदा कार्यान्वयन में दो मुख्य घटक हैं: + +| घटक | स्थान | लाइनें | विवरण | +|-----------|----------|-------|-------------| +| क्वेरी सेवा | `trustgraph-flow/trustgraph/query/objects/cassandra/service.py` | ~740 | एकरूप: GraphQL स्कीमा पीढ़ी, फ़िल्टर पार्सिंग, कैसेंड्रा क्वेरी, अनुरोध हैंडलिंग | +| लेखक | `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` | ~540 | प्रति-स्कीमा तालिका निर्माण, द्वितीयक अनुक्रमणिका, सम्मिलित/हटाना | + +**वर्तमान क्वेरी पैटर्न:** +```sql +SELECT * FROM {keyspace}.o_{schema_name} +WHERE collection = 'X' AND email = 'foo@bar.com' +ALLOW FILTERING +``` + +**नई क्वेरी पैटर्न:** +```sql +SELECT * FROM {keyspace}.rows +WHERE collection = 'X' AND schema_name = 'customers' + AND index_name = 'email' AND index_value = ['foo@bar.com'] +``` + +### मुख्य परिवर्तन + +1. **क्वेरी सिमेंटिक्स को सरल बनाया गया**: नया स्कीमा केवल `index_value` पर सटीक मिलान का समर्थन करता है। वर्तमान GraphQL फ़िल्टर (`gt`, `lt`, `contains`, आदि) या तो: + लौटाए गए डेटा पर पोस्ट-फ़िल्टरिंग बन जाते हैं (यदि अभी भी आवश्यक हैं) + अस्पष्ट मिलान के लिए एम्बेडिंग एपीआई का उपयोग करने के पक्ष में हटा दिए जाते हैं + +2. **GraphQL कोड दृढ़ता से युग्मित है**: वर्तमान `service.py` स्ट्रॉबेरी टाइप जनरेशन, फ़िल्टर पार्सिंग और कैसेंड्रा-विशिष्ट प्रश्नों को बंडल करता है। एक और रो स्टोर बैकएंड जोड़ने से ~400 लाइनों का GraphQL कोड दोहराया जाएगा। + +### प्रस्तावित रिफैक्टर + +रिफैक्टर में दो भाग हैं: + +#### 1. GraphQL कोड को अलग करें + +पुन: प्रयोज्य GraphQL घटकों को एक साझा मॉड्यूल में निकालें: + +``` +trustgraph-flow/trustgraph/query/graphql/ +├── __init__.py +├── types.py # Filter types (IntFilter, StringFilter, FloatFilter) +├── schema.py # Dynamic schema generation from RowSchema +└── filters.py # Filter parsing utilities +``` + +यह निम्नलिखित कार्य करता है: +विभिन्न रो स्टोर बैकएंड में पुन: उपयोग +चिंताओं का स्पष्ट अलगाव +GraphQL लॉजिक का स्वतंत्र रूप से परीक्षण करना आसान + +#### 2. नई टेबल स्कीमा को लागू करें + +कैसेंड्रा-विशिष्ट कोड को एकीकृत टेबल का उपयोग करने के लिए रिफैक्टर करें: + +**राइटर** (`trustgraph-flow/trustgraph/storage/rows/cassandra/`): +प्रति-स्कीमा टेबल के बजाय एक एकल `rows` टेबल +प्रति पंक्ति N प्रतियां लिखें (प्रत्येक इंडेक्स के लिए एक) +`row_partitions` टेबल में पंजीकरण करें +सरल टेबल निर्माण (एक बार सेटअप) + +**क्वेरी सर्विस** (`trustgraph-flow/trustgraph/query/rows/cassandra/`): +एकीकृत `rows` टेबल को क्वेरी करें +स्कीमा पीढ़ी के लिए निकाले गए GraphQL मॉड्यूल का उपयोग करें +सरलीकृत फ़िल्टर हैंडलिंग (केवल DB स्तर पर सटीक मिलान) + +### मॉड्यूल का नाम बदलना + +"ऑब्जेक्ट" से "रो" नामकरण को साफ करने के हिस्से के रूप में: + +| वर्तमान | नया | +|---------|-----| +| `storage/objects/cassandra/` | `storage/rows/cassandra/` | +| `query/objects/cassandra/` | `query/rows/cassandra/` | +| `embeddings/object_embeddings/` | `embeddings/row_embeddings/` | + +### नए मॉड्यूल + +| मॉड्यूल | उद्देश्य | +|--------|---------| +| `trustgraph-flow/trustgraph/query/graphql/` | साझा GraphQL उपयोगिताएँ | +| `trustgraph-flow/trustgraph/query/row_embeddings/qdrant/` | रो एम्बेडिंग क्वेरी एपीआई | +| `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | रो एम्बेडिंग गणना (स्टेज 1) | +| `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | रो एम्बेडिंग भंडारण (स्टेज 2) | + +## संदर्भ + +[स्ट्रक्चर्ड डेटा तकनीकी विनिर्देश](structured-data.md) diff --git a/docs/tech-specs/structured-data-2.pt.md b/docs/tech-specs/structured-data-2.pt.md new file mode 100644 index 00000000..8a260371 --- /dev/null +++ b/docs/tech-specs/structured-data-2.pt.md @@ -0,0 +1,613 @@ +# Especificação Técnica de Dados Estruturados (Parte 2) + +## Visão Geral + +Esta especificação aborda problemas e lacunas identificadas durante a implementação inicial da integração de dados estruturados do TrustGraph, conforme descrito em `structured-data.md`. + +## Declarações do Problema + +### 1. Inconsistência na Nomenclatura: "Objeto" vs "Linha" + +A implementação atual usa a terminologia "objeto" em todo o código (por exemplo, `ExtractedObject`, extração de objetos, incorporações de objetos). Essa nomenclatura é muito genérica e causa confusão: + +"Objeto" é um termo sobrecarregado em software (objetos Python, objetos JSON, etc.) +Os dados que estão sendo processados são fundamentalmente tabulares - linhas em tabelas com esquemas definidos +"Linha" descreve com mais precisão o modelo de dados e está alinhado com a terminologia de banco de dados + +Essa inconsistência aparece em nomes de módulos, nomes de classes, tipos de mensagens e documentação. + +### 2. Limitações de Consulta do Armazenamento de Linhas + +A implementação atual do armazenamento de linhas tem limitações significativas de consulta: + +**Incompatibilidade com a Linguagem Natural**: As consultas têm dificuldades com variações de dados do mundo real. Por exemplo: +É difícil encontrar uma base de dados de ruas contendo `"CHESTNUT ST"` quando se pergunta sobre `"Chestnut Street"` +Abreviaturas, diferenças de maiúsculas e minúsculas e variações de formatação interrompem as consultas de correspondência exata +Os usuários esperam compreensão semântica, mas o armazenamento fornece correspondência literal + +**Problemas de Evolução do Esquema**: Alterar os esquemas causa problemas: +Os dados existentes podem não estar em conformidade com os esquemas atualizados +Alterações na estrutura da tabela podem quebrar consultas e a integridade dos dados +Não há um caminho de migração claro para atualizações de esquema + +### 3. Incorporações de Linhas Necessárias + +Relacionado ao problema 2, o sistema precisa de incorporações vetoriais para dados de linha para permitir: + +Pesquisa semântica em dados estruturados (encontrando "Chestnut Street" quando os dados contêm "CHESTNUT ST") +Correspondência de similaridade para consultas aproximadas +Pesquisa híbrida combinando filtros estruturados com similaridade semântica +Melhor suporte para consultas em linguagem natural + +O serviço de incorporação foi especificado, mas não implementado. + +### 4. Ingestão de Dados de Linha Incompleta + +O pipeline de ingestão de dados estruturados não está totalmente operacional: + +Existem prompts de diagnóstico para classificar formatos de entrada (CSV, JSON, etc.) +O serviço de ingestão que usa esses prompts não está integrado ao sistema +Não há um caminho de ponta a ponta para carregar dados pré-estruturados no armazenamento de linhas + +## Objetivos + +**Flexibilidade de Esquema**: Permitir a evolução do esquema sem quebrar dados existentes ou exigir migrações +**Nomenclatura Consistente**: Padronizar na terminologia "linha" em todo o código +**Consultabilidade Semântica**: Suportar correspondência aproximada/semântica por meio de incorporações de linhas +**Pipeline de Ingestão Completo**: Fornecer um caminho de ponta a ponta para carregar dados estruturados + +## Design Técnico + +### Esquema de Armazenamento de Linhas Unificado + +A implementação anterior criou uma tabela Cassandra separada para cada esquema. Isso causou problemas quando os esquemas evoluíram, pois as alterações na estrutura da tabela exigiram migrações. + +O novo design usa uma única tabela unificada para todos os dados de linha: + +```sql +CREATE TABLE rows ( + collection text, + schema_name text, + index_name text, + index_value frozen>, + data map, + source text, + PRIMARY KEY ((collection, schema_name, index_name), index_value) +) +``` + +#### Definições das Colunas + +| Coluna | Tipo | Descrição | +|--------|------|-------------| +| `collection` | `text` | Identificador de coleta/importação de dados (a partir de metadados) | +| `schema_name` | `text` | Nome do esquema ao qual esta linha está em conformidade | +| `index_name` | `text` | Nome(s) do(s) campo(s) indexado(s), unidos por vírgula para compostos | +| `index_value` | `frozen>` | Valor(es) do índice como uma lista | +| `data` | `map` | Dados da linha como pares chave-valor | +| `source` | `text` | URI opcional que faz referência a informações de procedência no grafo de conhecimento. Uma string vazia ou NULL indica que não há fonte. | + +#### Tratamento de Índices + +Cada linha é armazenada várias vezes - uma vez por campo indexado definido no esquema. Os campos de chave primária são tratados como um índice sem um marcador especial, proporcionando flexibilidade futura. + +**Exemplo de índice de campo único:** +O esquema define `email` como indexado +`index_name = "email"` +`index_value = ['foo@bar.com']` + +**Exemplo de índice composto:** +O esquema define um índice composto em `region` e `status` +`index_name = "region,status"` (nomes dos campos ordenados e unidos por vírgula) +`index_value = ['US', 'active']` (valores na mesma ordem dos nomes dos campos) + +**Exemplo de chave primária:** +O esquema define `customer_id` como chave primária +`index_name = "customer_id"` +`index_value = ['CUST001']` + +#### Padrões de Consulta + +Todas as consultas seguem o mesmo padrão, independentemente de qual índice é usado: + +```sql +SELECT * FROM rows +WHERE collection = 'import_2024' + AND schema_name = 'customers' + AND index_name = 'email' + AND index_value = ['foo@bar.com'] +``` + +#### Compensações no Design + +**Vantagens:** +Alterações no esquema não exigem alterações na estrutura da tabela +Os dados das linhas são opacos para o Cassandra - adições/remoções de campos são transparentes +Padrão de consulta consistente para todos os métodos de acesso +Sem índices secundários do Cassandra (que podem ser lentos em grande escala) +Tipos nativos do Cassandra em todo o sistema (`map`, `frozen`) + +**Compensações:** +Amplificação de escrita: cada inserção de linha = N inserções (uma por campo indexado) +Sobrecarga de armazenamento devido à duplicação de dados das linhas +Informações de tipo armazenadas na configuração do esquema, conversão na camada de aplicação + +#### Modelo de Consistência + +O design aceita certas simplificações: + +1. **Sem atualizações de linha**: O sistema é somente de anexação. Isso elimina as preocupações com a consistência ao atualizar várias cópias da mesma linha. + +2. **Tolerância a alterações de esquema**: Quando os esquemas são alterados (por exemplo, índices adicionados/removidos), as linhas existentes mantêm seu índice original. Linhas antigas não serão encontradas por meio de novos índices. Os usuários podem excluir e recriar um esquema para garantir a consistência, se necessário. + +### Rastreamento e Exclusão de Partições + +#### O Problema + +Com a chave de partição `(collection, schema_name, index_name)`, a exclusão eficiente requer o conhecimento de todas as chaves de partição a serem excluídas. Excluir apenas por `collection` ou `collection + schema_name` requer o conhecimento de todos os valores de `index_name` que contêm dados. + +#### Tabela de Rastreamento de Partições + +Uma tabela de consulta secundária rastreia quais partições existem: + +```sql +CREATE TABLE row_partitions ( + collection text, + schema_name text, + index_name text, + PRIMARY KEY ((collection), schema_name, index_name) +) +``` + +Isso permite a descoberta eficiente de partições para operações de exclusão. + +#### Comportamento do Escritor de Linhas + +O escritor de linhas mantém um cache na memória de pares `(collection, schema_name)` registrados. Ao processar uma linha: + +1. Verifique se `(collection, schema_name)` está no cache. +2. Se não estiver no cache (primeira linha para este par): + Consulte a configuração do esquema para obter todos os nomes de índice. + Insira entradas em `row_partitions` para cada `(collection, schema_name, index_name)`. + Adicione o par ao cache. +3. Continue com a escrita dos dados da linha. + +O escritor de linhas também monitora eventos de alteração da configuração do esquema. Quando um esquema é alterado, as entradas relevantes do cache são limpas para que a próxima linha acione o re-registro com os nomes de índice atualizados. + +Essa abordagem garante: +As escritas na tabela de pesquisa ocorrem apenas uma vez por par `(collection, schema_name)`, e não por linha. +A tabela de pesquisa reflete os índices que estavam ativos quando os dados foram escritos. +As alterações no esquema durante a importação são detectadas corretamente. + +#### Operações de Exclusão + +**Excluir coleção:** +```sql +-- 1. Discover all partitions +SELECT schema_name, index_name FROM row_partitions WHERE collection = 'X'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = '...' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table +DELETE FROM row_partitions WHERE collection = 'X'; +``` + +**Excluir coleção + esquema:** +```sql +-- 1. Discover partitions for this schema +SELECT index_name FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = 'Y' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table entries +DELETE FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; +``` + +### Incorporações de Linhas + +As incorporações de linhas permitem a correspondência semântica/aproximada em valores indexados, resolvendo o problema de incompatibilidade de linguagem natural (por exemplo, encontrar "CHESTNUT ST" ao pesquisar por "Chestnut Street"). + +#### Visão Geral do Design + +Cada valor indexado é incorporado e armazenado em um armazenamento vetorial (Qdrant). No momento da consulta, a consulta é incorporada, vetores semelhantes são encontrados e os metadados associados são usados para pesquisar as linhas reais no Cassandra. + +#### Estrutura da Coleção Qdrant + +Uma coleção Qdrant por tupla `(user, collection, schema_name, dimension)`: + +**Nome da coleção:** `rows_{user}_{collection}_{schema_name}_{dimension}` +Os nomes são higienizados (caracteres não alfanuméricos substituídos por `_`, em letras minúsculas, os prefixos numéricos recebem o prefixo `r_`) +**Justificativa:** Permite a exclusão limpa de uma instância `(user, collection, schema_name)`, descartando as coleções Qdrant correspondentes; o sufixo de dimensão permite que diferentes modelos de incorporação coexistam. + +#### O Que é Incorporado + +A representação de texto dos valores do índice: + +| Tipo de Índice | Exemplo `index_value` | Texto a Incorporar | +|------------|----------------------|---------------| +| Campo único | `['foo@bar.com']` | `"foo@bar.com"` | +| Composto | `['US', 'active']` | `"US active"` (juntados por espaço) | + +#### Estrutura do Ponto + +Cada ponto Qdrant contém: + +```json +{ + "id": "", + "vector": [0.1, 0.2, ...], + "payload": { + "index_name": "street_name", + "index_value": ["CHESTNUT ST"], + "text": "CHESTNUT ST" + } +} +``` + +| Campo de Payload | Descrição | +|---------------|-------------| +| `index_name` | Os campos indexados que esta incorporação representa | +| `index_value` | A lista original de valores (para pesquisa no Cassandra) | +| `text` | O texto que foi incorporado (para depuração/exibição) | + +Nota: `user`, `collection` e `schema_name` são implícitos do nome da coleção Qdrant. + +#### Fluxo de Consulta + +1. O usuário consulta por "Chestnut Street" dentro do usuário U, coleção X, esquema Y +2. Incorpore o texto da consulta +3. Determine o(s) nome(s) da coleção Qdrant que correspondem ao prefixo `rows_U_X_Y_` +4. Pesquise na(s) coleção(ões) Qdrant correspondente(s) pelos vetores mais próximos +5. Obtenha os pontos correspondentes com payloads contendo `index_name` e `index_value` +6. Consulte o Cassandra: + ```sql + SELECT * FROM rows + WHERE collection = 'X' + AND schema_name = 'Y' + AND index_name = '' + AND index_value = + ``` +7. Retornar linhas correspondentes + +#### Opcional: Filtragem por Nome do Índice + +As consultas podem opcionalmente filtrar por `index_name` no Qdrant para pesquisar apenas campos específicos: + +**"Encontrar qualquer campo que corresponda a 'Chestnut'"** → pesquisa todos os vetores na coleção +**"Encontrar street_name que corresponda a 'Chestnut'"** → filtrar onde `payload.index_name = 'street_name'` + +#### Arquitetura + +Os embeddings das linhas seguem o **padrão de duas etapas** usado pelo GraphRAG (embeddings do grafo, embeddings do documento): + +**Etapa 1: Computação de embeddings** (`trustgraph-flow/trustgraph/embeddings/row_embeddings/`) - Consome `ExtractedObject`, calcula embeddings através do serviço de embeddings, gera `RowEmbeddings` +**Etapa 2: Armazenamento de embeddings** (`trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/`) - Consome `RowEmbeddings`, escreve vetores no Qdrant + +O escritor de linhas do Cassandra é um consumidor paralelo separado: + +**Escritor de linhas do Cassandra** (`trustgraph-flow/trustgraph/storage/rows/cassandra`) - Consome `ExtractedObject`, escreve linhas no Cassandra + +Todos os três serviços consomem do mesmo fluxo, mantendo-os desacoplados. Isso permite: +Escalonamento independente das escritas do Cassandra em relação à geração de embeddings em relação ao armazenamento de vetores +Os serviços de embeddings podem ser desativados se não forem necessários +Falhas em um serviço não afetam os outros +Arquitetura consistente com os pipelines do GraphRAG + +#### Caminho de Escrita + +**Etapa 1 (processador de embeddings das linhas):** Ao receber um `ExtractedObject`: + +1. Consultar o esquema para encontrar campos indexados +2. Para cada campo indexado: + Construir a representação de texto do valor do índice + Calcular o embedding através do serviço de embeddings +3. Gerar uma mensagem `RowEmbeddings` contendo todos os vetores calculados + +**Etapa 2 (escritor de embeddings-Qdrant):** Ao receber um `RowEmbeddings`: + +1. Para cada embedding na mensagem: + Determinar a coleção do Qdrant a partir de `(user, collection, schema_name, dimension)` + Criar a coleção, se necessário (criação preguiçosa na primeira escrita) + Inserir/atualizar o ponto com o vetor e o payload + +#### Tipos de Mensagens + +```python +@dataclass +class RowIndexEmbedding: + index_name: str # The indexed field name(s) + index_value: list[str] # The field value(s) + text: str # Text that was embedded + vectors: list[list[float]] # Computed embedding vectors + +@dataclass +class RowEmbeddings: + metadata: Metadata + schema_name: str + embeddings: list[RowIndexEmbedding] +``` + +#### Integração de Exclusão + +As coleções Qdrant são descobertas por correspondência de prefixo no padrão de nome da coleção: + +**Excluir `(user, collection)`:** +1. Listar todas as coleções Qdrant que correspondem ao prefixo `rows_{user}_{collection}_` +2. Excluir cada coleção correspondente +3. Excluir partições de linhas do Cassandra (como documentado acima) +4. Limpar as entradas `row_partitions` + +**Excluir `(user, collection, schema_name)`:** +1. Listar todas as coleções Qdrant que correspondem ao prefixo `rows_{user}_{collection}_{schema_name}_` +2. Excluir cada coleção correspondente (lida com múltiplas dimensões) +3. Excluir partições de linhas do Cassandra +4. Limpar `row_partitions` + +#### Localizações dos Módulos + +| Estágio | Módulo | Ponto de Entrada | +|-------|--------|-------------| +| Estágio 1 | `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | `row-embeddings` | +| Estágio 2 | `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | `row-embeddings-write-qdrant` | + +### API de Consulta de Incorporações de Linhas + +A consulta de incorporações de linhas é uma **API separada** do serviço de consulta de linhas GraphQL: + +| API | Propósito | Backend | +|-----|---------|---------| +| Consulta de Linhas (GraphQL) | Correspondência exata em campos indexados | Cassandra | +| Consulta de Incorporações de Linhas | Correspondência aproximada/semântica | Qdrant | + +Essa separação mantém as responsabilidades bem definidas: +O serviço GraphQL se concentra em consultas estruturadas e exatas +A API de incorporações lida com a similaridade semântica +Fluxo de trabalho do usuário: pesquisa aproximada por meio de incorporações para encontrar candidatos e, em seguida, consulta exata para obter os dados completos da linha + +#### Esquema de Solicitação/Resposta + +```python +@dataclass +class RowEmbeddingsRequest: + vectors: list[list[float]] # Query vectors (pre-computed embeddings) + user: str = "" + collection: str = "" + schema_name: str = "" + index_name: str = "" # Optional: filter to specific index + limit: int = 10 # Max results per vector + +@dataclass +class RowIndexMatch: + index_name: str = "" # The matched index field(s) + index_value: list[str] = [] # The matched value(s) + text: str = "" # Original text that was embedded + score: float = 0.0 # Similarity score + +@dataclass +class RowEmbeddingsResponse: + error: Error | None = None + matches: list[RowIndexMatch] = [] +``` + +#### Processador de Consultas + +Módulo: `trustgraph-flow/trustgraph/query/row_embeddings/qdrant` + +Ponto de entrada: `row-embeddings-query-qdrant` + +O processador: +1. Recebe `RowEmbeddingsRequest` com vetores de consulta +2. Encontra a coleção Qdrant apropriada por correspondência de prefixo +3. Procura os vetores mais próximos com filtro opcional `index_name` +4. Retorna `RowEmbeddingsResponse` com informações do índice correspondente + +#### Integração com o Gateway de API + +O gateway expõe consultas de incorporações de linhas através do padrão padrão de solicitação/resposta: + +| Componente | Localização | +|-----------|----------| +| Dispatcher | `trustgraph-flow/trustgraph/gateway/dispatch/row_embeddings_query.py` | +| Registro | Adicione `"row-embeddings"` a `request_response_dispatchers` em `manager.py` | + +Nome da interface do fluxo: `row-embeddings` + +Definição da interface no blueprint do fluxo: +```json +{ + "interfaces": { + "row-embeddings": { + "request": "non-persistent://tg/request/row-embeddings:{id}", + "response": "non-persistent://tg/response/row-embeddings:{id}" + } + } +} +``` + +#### Suporte ao SDK Python + +O SDK fornece métodos para consultas de incorporações de linhas: + +```python +# Flow-scoped query (preferred) +api = Api(url) +flow = api.flow().id("default") + +# Query with text (SDK computes embeddings) +matches = flow.row_embeddings_query( + text="Chestnut Street", + collection="my_collection", + schema_name="addresses", + index_name="street_name", # Optional filter + limit=10 +) + +# Query with pre-computed vectors +matches = flow.row_embeddings_query( + vectors=[[0.1, 0.2, ...]], + collection="my_collection", + schema_name="addresses" +) + +# Each match contains: +for match in matches: + print(match.index_name) # e.g., "street_name" + print(match.index_value) # e.g., ["CHESTNUT ST"] + print(match.text) # e.g., "CHESTNUT ST" + print(match.score) # e.g., 0.95 +``` + +#### Utilitário de Linha de Comando (CLI) + +Comando: `tg-invoke-row-embeddings` + +```bash +# Query by text (computes embedding automatically) +tg-invoke-row-embeddings \ + --text "Chestnut Street" \ + --collection my_collection \ + --schema addresses \ + --index street_name \ + --limit 10 + +# Query by vector file +tg-invoke-row-embeddings \ + --vectors vectors.json \ + --collection my_collection \ + --schema addresses + +# Output formats +tg-invoke-row-embeddings --text "..." --format json +tg-invoke-row-embeddings --text "..." --format table +``` + +#### Padrão de Uso Típico + +A consulta de incorporações de linhas é normalmente usada como parte de um fluxo de pesquisa aproximada para correspondência exata: + +```python +# Step 1: Fuzzy search via embeddings +matches = flow.row_embeddings_query( + text="chestnut street", + collection="geo", + schema_name="streets" +) + +# Step 2: Exact lookup via GraphQL for full row data +for match in matches: + query = f''' + query {{ + streets(where: {{ {match.index_name}: {{ eq: "{match.index_value[0]}" }} }}) {{ + street_name + city + zip_code + }} + }} + ''' + rows = flow.rows_query(query, collection="geo") +``` + +Este padrão de duas etapas permite: +Encontrar "CHESTNUT ST" quando o usuário pesquisa por "Chestnut Street" +Recuperar dados completos da linha com todos os campos +Combinar similaridade semântica com acesso a dados estruturados + +### Ingestão de Dados da Linha + +Será adiada para uma fase posterior. Será projetada juntamente com outras alterações de ingestão. + +## Impacto na Implementação + +### Análise do Estado Atual + +A implementação existente possui dois componentes principais: + +| Componente | Localização | Linhas | Descrição | +|-----------|----------|-------|-------------| +| Serviço de Consulta | `trustgraph-flow/trustgraph/query/objects/cassandra/service.py` | ~740 | Monolítico: geração de esquema GraphQL, análise de filtros, consultas Cassandra, tratamento de solicitações | +| Escritor | `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` | ~540 | Criação de tabelas por esquema, índices secundários, inserção/exclusão | + +**Padrão de Consulta Atual:** +```sql +SELECT * FROM {keyspace}.o_{schema_name} +WHERE collection = 'X' AND email = 'foo@bar.com' +ALLOW FILTERING +``` + +**Novo Padrão de Consulta:** +```sql +SELECT * FROM {keyspace}.rows +WHERE collection = 'X' AND schema_name = 'customers' + AND index_name = 'email' AND index_value = ['foo@bar.com'] +``` + +### Mudanças Principais + +1. **A semântica das consultas é simplificada**: O novo esquema suporta apenas correspondências exatas em `index_value`. Os filtros GraphQL atuais (`gt`, `lt`, `contains`, etc.) ou: + Tornam-se pós-filtragem nos dados retornados (se ainda forem necessários) + São removidos em favor do uso da API de embeddings para correspondências aproximadas + +2. **O código GraphQL está fortemente acoplado**: O código `service.py` atual combina a geração de tipos Strawberry, a análise de filtros e as consultas específicas do Cassandra. Adicionar outro backend de armazenamento de linhas duplicaria cerca de 400 linhas de código GraphQL. + +### Refatoração Proposta + +A refatoração tem duas partes: + +#### 1. Separar o Código GraphQL + +Extrair componentes GraphQL reutilizáveis para um módulo compartilhado: + +``` +trustgraph-flow/trustgraph/query/graphql/ +├── __init__.py +├── types.py # Filter types (IntFilter, StringFilter, FloatFilter) +├── schema.py # Dynamic schema generation from RowSchema +└── filters.py # Filter parsing utilities +``` + +Isso permite: +Reutilização em diferentes backends de armazenamento de dados. +Separação mais clara de responsabilidades. +Teste mais fácil da lógica GraphQL de forma independente. + +#### 2. Implementar Novo Esquema de Tabela + +Refatorar o código específico do Cassandra para usar a tabela unificada: + +**Escritor** (`trustgraph-flow/trustgraph/storage/rows/cassandra/`): +Uma única tabela `rows` em vez de tabelas por esquema. +Escrever N cópias por linha (uma por índice). +Registrar na tabela `row_partitions`. +Criação de tabela mais simples (configuração única). + +**Serviço de Consulta** (`trustgraph-flow/trustgraph/query/rows/cassandra/`): +Consultar a tabela `rows` unificada. +Usar o módulo GraphQL extraído para geração de esquema. +Tratamento de filtros simplificado (apenas correspondência exata no nível do banco de dados). + +### Renomeação de Módulos + +Como parte da limpeza de nomes de "objeto" para "linha": + +| Atual | Novo | +|---------|-----| +| `storage/objects/cassandra/` | `storage/rows/cassandra/` | +| `query/objects/cassandra/` | `query/rows/cassandra/` | +| `embeddings/object_embeddings/` | `embeddings/row_embeddings/` | + +### Novos Módulos + +| Módulo | Propósito | +|--------|---------| +| `trustgraph-flow/trustgraph/query/graphql/` | Utilitários GraphQL compartilhados | +| `trustgraph-flow/trustgraph/query/row_embeddings/qdrant/` | API de consulta de incorporações de linhas | +| `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | Cálculo de incorporações de linhas (Etapa 1) | +| `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | Armazenamento de incorporações de linhas (Etapa 2) | + +## Referências + +[Especificação Técnica de Dados Estruturados](structured-data.md) diff --git a/docs/tech-specs/structured-data-2.ru.md b/docs/tech-specs/structured-data-2.ru.md new file mode 100644 index 00000000..22f0dcf8 --- /dev/null +++ b/docs/tech-specs/structured-data-2.ru.md @@ -0,0 +1,613 @@ +# Техническая спецификация структурированных данных (часть 2) + +## Обзор + +Эта спецификация рассматривает проблемы и недостатки, выявленные в процессе первоначальной реализации интеграции структурированных данных TrustGraph, как описано в `structured-data.md`. + +## Описание проблем + +### 1. Несоответствие в наименованиях: "Объект" против "Строка" + +В текущей реализации используется терминология "объект" во всем коде (например, `ExtractedObject`, извлечение объектов, векторные представления объектов). Это наименование слишком общее и вызывает путаницу: + +Термин "объект" является перегруженным в программном обеспечении (объекты Python, объекты JSON и т.д.) +Данные, которые обрабатываются, по сути являются табличными - строки в таблицах с определенными схемами. +"Строка" более точно описывает модель данных и соответствует терминологии баз данных. + +Это несоответствие проявляется в названиях модулей, названиях классов, типах сообщений и документации. + +### 2. Ограничения запросов к хранилищу строк + +Текущая реализация хранилища строк имеет значительные ограничения по запросам: + +**Несоответствие с естественным языком**: Запросы испытывают трудности с вариациями реальных данных. Например: +Сложно найти базу данных улиц, содержащую `"CHESTNUT ST"`, при запросе информации о `"Chestnut Street"`. +Аббревиатуры, различия в регистре и вариации форматирования нарушают запросы точного соответствия. +Пользователи ожидают семантического понимания, но хранилище обеспечивает только буквальное сопоставление. + +**Проблемы с эволюцией схемы**: Изменение схем вызывает проблемы: +Существующие данные могут не соответствовать обновленным схемам. +Изменения структуры таблицы могут нарушить запросы и целостность данных. +Отсутствует четкий путь миграции для обновлений схемы. + +### 3. Требуются векторные представления строк + +В связи с проблемой 2, системе требуются векторные представления данных строк для обеспечения: + +Семантического поиска по структурированным данным (поиск "Chestnut Street", когда данные содержат "CHESTNUT ST"). +Сопоставления по сходству для нечетких запросов. +Гибридного поиска, сочетающего структурированные фильтры с семантическим сходством. +Лучшей поддержки запросов на естественном языке. + +Сервис создания векторных представлений был определен, но не реализован. + +### 4. Неполная загрузка данных строк + +Конвейер загрузки структурированных данных не полностью функционирует: + +Существуют диагностические подсказки для классификации форматов входных данных (CSV, JSON и т.д.). +Сервис загрузки, использующий эти подсказки, не подключен к системе. +Отсутствует сквозной путь для загрузки предварительно структурированных данных в хранилище строк. + +## Цели + +**Гибкость схемы**: Обеспечить эволюцию схемы без нарушения существующих данных или необходимости миграций. +**Согласованное наименование**: Стандартизировать использование термина "строка" во всем коде. +**Семантическая запросаемость**: Поддержка нечеткого/семантического сопоставления с помощью векторных представлений строк. +**Полный конвейер загрузки**: Предоставить сквозной путь для загрузки структурированных данных. + +## Технический дизайн + +### Унифицированная схема хранения строк + +В предыдущей реализации для каждой схемы создавалась отдельная таблица Cassandra. Это вызывало проблемы при эволюции схем, поскольку изменения структуры таблицы требовали миграций. + +В новой разработке используется единая унифицированная таблица для всех данных строк: + +```sql +CREATE TABLE rows ( + collection text, + schema_name text, + index_name text, + index_value frozen>, + data map, + source text, + PRIMARY KEY ((collection, schema_name, index_name), index_value) +) +``` + +#### Описание столбцов + +| Столбец | Тип | Описание | +|--------|------|-------------| +| `collection` | `text` | Идентификатор сбора/импорта данных (из метаданных) | +| `schema_name` | `text` | Название схемы, которой соответствует эта строка | +| `index_name` | `text` | Название индексируемого поля (полей), объединенное запятыми для составных индексов | +| `index_value` | `frozen>` | Значение(я) индекса в виде списка | +| `data` | `map` | Данные строки в виде пар ключ-значение | +| `source` | `text` | Необязательный URI, ссылающийся на информацию об источнике в графе знаний. Пустая строка или NULL указывает на отсутствие источника. | + +#### Обработка индексов + +Каждая строка хранится несколько раз - один раз для каждого индексируемого поля, определенного в схеме. Первичные ключи рассматриваются как индекс без специального маркера, что обеспечивает гибкость в будущем. + +**Пример индекса для одного поля:** +Схема определяет `email` как индексируемое +`index_name = "email"` +`index_value = ['foo@bar.com']` + +**Пример составного индекса:** +Схема определяет составной индекс для `region` и `status` +`index_name = "region,status"` (названия полей отсортированы и объединены запятыми) +`index_value = ['US', 'active']` (значения в том же порядке, что и названия полей) + +**Пример первичного ключа:** +Схема определяет `customer_id` как первичный ключ +`index_name = "customer_id"` +`index_value = ['CUST001']` + +#### Шаблоны запросов + +Все запросы следуют одной и той же схеме, независимо от того, какой индекс используется: + +```sql +SELECT * FROM rows +WHERE collection = 'import_2024' + AND schema_name = 'customers' + AND index_name = 'email' + AND index_value = ['foo@bar.com'] +``` + +#### Компромиссы в проектировании + +**Преимущества:** +Изменения схемы не требуют изменений структуры таблицы +Данные строк не видны Cassandra - добавление/удаление полей прозрачно +Единый шаблон запросов для всех методов доступа +Отсутствуют вторичные индексы Cassandra (которые могут быть медленными при больших масштабах) +Использование нативных типов Cassandra (`map`, `frozen`) + +**Компромиссы:** +Увеличение количества операций записи: каждая вставка строки = N вставок (по одной на каждое индексированное поле) +Дополнительные затраты памяти из-за дублирования данных строк +Информация о типах хранится в конфигурации схемы, преобразование происходит на уровне приложения + +#### Модель согласованности + +В проекте приняты определенные упрощения: + +1. **Отсутствие обновлений строк**: Система работает только на добавление данных. Это устраняет проблемы согласованности, связанные с обновлением нескольких копий одной и той же строки. + +2. **Толерантность к изменениям схемы**: При изменении схем (например, при добавлении/удалении индексов) существующие строки сохраняют свою первоначальную индексацию. Старые строки не будут доступны через новые индексы. Пользователи могут удалить и пересоздать схему для обеспечения согласованности, если это необходимо. + +### Отслеживание и удаление разделов + +#### Проблема + +При использовании ключа раздела `(collection, schema_name, index_name)`, для эффективного удаления необходимо знать все ключи разделов, которые нужно удалить. Удаление только по `collection` или `collection + schema_name` требует знания всех значений `index_name`, которые содержат данные. + +#### Таблица отслеживания разделов + +Вторичная таблица поиска отслеживает, какие разделы существуют: + +```sql +CREATE TABLE row_partitions ( + collection text, + schema_name text, + index_name text, + PRIMARY KEY ((collection), schema_name, index_name) +) +``` + +Это обеспечивает эффективное обнаружение разделов для операций удаления. + +#### Поведение модуля записи строк + +Модуль записи строк поддерживает кэш в памяти, содержащий зарегистрированные пары `(collection, schema_name)`. При обработке строки: + +1. Проверьте, есть ли `(collection, schema_name)` в кэше. +2. Если ⟦CODE_0⟧ не в кэше (первая строка для этой пары): + Найдите конфигурацию схемы, чтобы получить все имена индексов. + Вставьте записи в `row_partitions` для каждого `(collection, schema_name, index_name)`. + Добавьте пару в кэш. +3. Перейдите к записи данных строки. + +Модуль записи строк также отслеживает события изменения конфигурации схемы. При изменении схемы соответствующие записи кэша очищаются, чтобы следующая строка вызвала повторную регистрацию с обновленными именами индексов. + +Этот подход обеспечивает: +Записи в таблицу поиска происходят только один раз для каждой пары `(collection, schema_name)`, а не для каждой строки. +Таблица поиска отражает индексы, которые были активны во время записи данных. +Изменения схемы во время импорта обрабатываются правильно. + +#### Операции удаления + +**Удаление коллекции:** +```sql +-- 1. Discover all partitions +SELECT schema_name, index_name FROM row_partitions WHERE collection = 'X'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = '...' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table +DELETE FROM row_partitions WHERE collection = 'X'; +``` + +**Удалить коллекцию и схему:** +```sql +-- 1. Discover partitions for this schema +SELECT index_name FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = 'Y' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table entries +DELETE FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; +``` + +### Встраивания строк + +Встраивания строк обеспечивают семантическое/приближенное сопоставление проиндексированных значений, решая проблему несовместимости естественного языка (например, поиск "CHESTNUT ST", когда выполняется запрос "Chestnut Street"). + +#### Обзор архитектуры + +Каждое проиндексированное значение преобразуется во встраивание и хранится в векторной базе данных (Qdrant). Во время запроса запрос также преобразуется во встраивание, находятся похожие векторы, и связанная метаинформация используется для поиска фактических строк в Cassandra. + +#### Структура коллекции Qdrant + +Одна коллекция Qdrant для каждой кортежи `(user, collection, schema_name, dimension)`: + +**Именование коллекции:** `rows_{user}_{collection}_{schema_name}_{dimension}` +Имена очищаются (небуквенно-цифровые символы заменяются на `_`, приводятся к нижнему регистру, числовые префиксы получают префикс `r_`) +**Обоснование:** Позволяет чисто удалить экземпляр `(user, collection, schema_name)` путем удаления соответствующих коллекций Qdrant; суффикс измерения позволяет различным моделям встраивания сосуществовать. + +#### Что подвергается встраиванию + +Текстовое представление значений индекса: + +| Тип индекса | Пример `index_value` | Текст для встраивания | +|------------|----------------------|---------------| +| Одиночное поле | `['foo@bar.com']` | `"foo@bar.com"` | +| Композитный | `['US', 'active']` | `"US active"` (объединенные пробелами) | + +#### Структура точки + +Каждая точка Qdrant содержит: + +```json +{ + "id": "", + "vector": [0.1, 0.2, ...], + "payload": { + "index_name": "street_name", + "index_value": ["CHESTNUT ST"], + "text": "CHESTNUT ST" + } +} +``` + +| Поле полезной нагрузки | Описание | +|---------------|-------------| +| `index_name` | Индексированные поля, которые представляет эта вставка. | +| `index_value` | Исходный список значений (для поиска в Cassandra). | +| `text` | Текст, который был вставлен (для отладки/отображения). | + +Обратите внимание: `user`, `collection` и `schema_name` определяются неявно из имени коллекции Qdrant. + +#### Поток запросов + +1. Пользователь запрашивает "Chestnut Street" для пользователя U, коллекции X, схемы Y. +2. Вставьте текст запроса. +3. Определите имя(и) коллекции Qdrant, соответствующие префиксу `rows_U_X_Y_`. +4. Выполните поиск в соответствующих коллекциях Qdrant для поиска ближайших векторов. +5. Получите соответствующие точки с полезными нагрузками, содержащими `index_name` и `index_value`. +6. Запрос к Cassandra: + ```sql + SELECT * FROM rows + WHERE collection = 'X' + AND schema_name = 'Y' + AND index_name = '' + AND index_value = + ``` +7. Возврат соответствующих строк. + +#### Необязательно: Фильтрация по имени индекса. + +Запросы могут опционально фильтровать данные по `index_name` в Qdrant, чтобы искать только определенные поля: + +**"Найти любое поле, соответствующее 'Chestnut'"** → поиск по всем векторам в коллекции. +**"Найти поле street_name, соответствующее 'Chestnut'"** → фильтрация по `payload.index_name = 'street_name'`. + +#### Архитектура. + +Векторные представления строк следуют **двухступенчатой схеме**, используемой в GraphRAG (graph-embeddings, document-embeddings): + +**Этап 1: Вычисление векторных представлений** (`trustgraph-flow/trustgraph/embeddings/row_embeddings/`) - Использует `ExtractedObject`, вычисляет векторные представления через сервис векторных представлений, выдает `RowEmbeddings`. +**Этап 2: Хранение векторных представлений** (`trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/`) - Использует `RowEmbeddings`, записывает векторы в Qdrant. + +Модуль записи строк в Cassandra является отдельным параллельным компонентом: + +**Модуль записи строк в Cassandra** (`trustgraph-flow/trustgraph/storage/rows/cassandra`) - Использует `ExtractedObject`, записывает строки в Cassandra. + +Все три компонента используют один и тот же поток данных, что обеспечивает их независимость. Это позволяет: +Независимое масштабирование записи в Cassandra по сравнению с генерацией векторных представлений и хранением векторов. +Отключение сервисов генерации векторных представлений, если они не требуются. +Отказы в одном компоненте не влияют на другие. +Согласованная архитектура с конвейерами GraphRAG. + +#### Путь записи. + +**Этап 1 (процессор векторных представлений строк):** При получении `ExtractedObject`: + +1. Получение схемы для поиска индексированных полей. +2. Для каждого индексированного поля: + Создание текстового представления значения индекса. + Вычисление векторного представления через сервис векторных представлений. +3. Вывод сообщения `RowEmbeddings`, содержащего все вычисленные векторы. + +**Этап 2 (запись векторных представлений в Qdrant):** При получении `RowEmbeddings`: + +1. Для каждого векторного представления в сообщении: + Определение коллекции Qdrant из `(user, collection, schema_name, dimension)`. + Создание коллекции, если это необходимо (создание при первой записи). + Добавление точки с вектором и полезной нагрузкой. + +#### Типы сообщений. + +```python +@dataclass +class RowIndexEmbedding: + index_name: str # The indexed field name(s) + index_value: list[str] # The field value(s) + text: str # Text that was embedded + vectors: list[list[float]] # Computed embedding vectors + +@dataclass +class RowEmbeddings: + metadata: Metadata + schema_name: str + embeddings: list[RowIndexEmbedding] +``` + +#### Интеграция удаления + +Коллекции Qdrant обнаруживаются путем сопоставления префикса с шаблоном имени коллекции: + +**Удаление `(user, collection)`:** +1. Перечислить все коллекции Qdrant, соответствующие префиксу `rows_{user}_{collection}_` +2. Удалить каждую соответствующую коллекцию +3. Удалить разделы строк Cassandra (как описано выше) +4. Очистить записи `row_partitions` + +**Удаление `(user, collection, schema_name)`:** +1. Перечислить все коллекции Qdrant, соответствующие префиксу `rows_{user}_{collection}_{schema_name}_` +2. Удалить каждую соответствующую коллекцию (обрабатывает несколько измерений) +3. Удалить разделы строк Cassandra +4. Очистить `row_partitions` + +#### Расположение модулей + +| Этап | Модуль | Точка входа | +|-------|--------|-------------| +| Этап 1 | `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | `row-embeddings` | +| Этап 2 | `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | `row-embeddings-write-qdrant` | + +### API запросов для векторных представлений строк + +API запросов для векторных представлений строк является **отдельным API** от сервиса запросов строк GraphQL: + +| API | Назначение | Бэкенд | +|-----|---------|---------| +| Запрос строк (GraphQL) | Точное сопоставление с индексированными полями | Cassandra | +| Запрос векторных представлений строк | Нечеткое/семантическое сопоставление | Qdrant | + +Это разделение позволяет четко разделить функциональность: +Сервис GraphQL фокусируется на точных, структурированных запросах +API векторных представлений обрабатывает семантическую схожесть +Рабочий процесс пользователя: нечеткий поиск с помощью векторных представлений для поиска кандидатов, затем точный запрос для получения полных данных строки + +#### Схема запроса/ответа + +```python +@dataclass +class RowEmbeddingsRequest: + vectors: list[list[float]] # Query vectors (pre-computed embeddings) + user: str = "" + collection: str = "" + schema_name: str = "" + index_name: str = "" # Optional: filter to specific index + limit: int = 10 # Max results per vector + +@dataclass +class RowIndexMatch: + index_name: str = "" # The matched index field(s) + index_value: list[str] = [] # The matched value(s) + text: str = "" # Original text that was embedded + score: float = 0.0 # Similarity score + +@dataclass +class RowEmbeddingsResponse: + error: Error | None = None + matches: list[RowIndexMatch] = [] +``` + +#### Обработчик запросов + +Модуль: `trustgraph-flow/trustgraph/query/row_embeddings/qdrant` + +Точка входа: `row-embeddings-query-qdrant` + +Обработчик: +1. Получает `RowEmbeddingsRequest` с векторами запросов +2. Находит соответствующую коллекцию Qdrant путем сопоставления префикса +3. Ищет ближайшие векторы с необязательным фильтром `index_name` +4. Возвращает `RowEmbeddingsResponse` с информацией об индексе, соответствующем запросу + +#### Интеграция с API-шлюзом + +Шлюз предоставляет запросы на получение векторных представлений строк через стандартный шаблон запроса/ответа: + +| Компонент | Местоположение | +|-----------|----------| +| Диспетчер | `trustgraph-flow/trustgraph/gateway/dispatch/row_embeddings_query.py` | +| Регистрация | Добавьте `"row-embeddings"` в `request_response_dispatchers` в `manager.py` | + +Имя интерфейса потока: `row-embeddings` + +Определение интерфейса в шаблоне потока: +```json +{ + "interfaces": { + "row-embeddings": { + "request": "non-persistent://tg/request/row-embeddings:{id}", + "response": "non-persistent://tg/response/row-embeddings:{id}" + } + } +} +``` + +#### Поддержка Python SDK + +SDK предоставляет методы для запросов векторных представлений строк: + +```python +# Flow-scoped query (preferred) +api = Api(url) +flow = api.flow().id("default") + +# Query with text (SDK computes embeddings) +matches = flow.row_embeddings_query( + text="Chestnut Street", + collection="my_collection", + schema_name="addresses", + index_name="street_name", # Optional filter + limit=10 +) + +# Query with pre-computed vectors +matches = flow.row_embeddings_query( + vectors=[[0.1, 0.2, ...]], + collection="my_collection", + schema_name="addresses" +) + +# Each match contains: +for match in matches: + print(match.index_name) # e.g., "street_name" + print(match.index_value) # e.g., ["CHESTNUT ST"] + print(match.text) # e.g., "CHESTNUT ST" + print(match.score) # e.g., 0.95 +``` + +#### Утилита командной строки + +Команда: `tg-invoke-row-embeddings` + +```bash +# Query by text (computes embedding automatically) +tg-invoke-row-embeddings \ + --text "Chestnut Street" \ + --collection my_collection \ + --schema addresses \ + --index street_name \ + --limit 10 + +# Query by vector file +tg-invoke-row-embeddings \ + --vectors vectors.json \ + --collection my_collection \ + --schema addresses + +# Output formats +tg-invoke-row-embeddings --text "..." --format json +tg-invoke-row-embeddings --text "..." --format table +``` + +#### Типичная схема использования + +Запрос векторных представлений строк обычно используется как часть процесса поиска приблизительного соответствия для точного поиска: + +```python +# Step 1: Fuzzy search via embeddings +matches = flow.row_embeddings_query( + text="chestnut street", + collection="geo", + schema_name="streets" +) + +# Step 2: Exact lookup via GraphQL for full row data +for match in matches: + query = f''' + query {{ + streets(where: {{ {match.index_name}: {{ eq: "{match.index_value[0]}" }} }}) {{ + street_name + city + zip_code + }} + }} + ''' + rows = flow.rows_query(query, collection="geo") +``` + +Эта двухэтапная схема позволяет: +Находить "CHESTNUT ST", когда пользователь ищет "Chestnut Street" +Получать полные данные строки со всеми полями +Объединять семантическую схожесть с доступом к структурированным данным + +### Импорт данных строк + +Отложено до последующей фазы. Будет разработано вместе с другими изменениями импорта. + +## Влияние на реализацию + +### Анализ текущего состояния + +Существующая реализация имеет два основных компонента: + +| Компонент | Местоположение | Строк | Описание | +|-----------|----------|-------|-------------| +| Сервис запросов | `trustgraph-flow/trustgraph/query/objects/cassandra/service.py` | ~740 | Монолит: генерация схемы GraphQL, разбор фильтров, запросы Cassandra, обработка запросов | +| Записывающий модуль | `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` | ~540 | Создание таблиц для каждой схемы, вторичные индексы, вставка/удаление | + +**Текущая схема запросов:** +```sql +SELECT * FROM {keyspace}.o_{schema_name} +WHERE collection = 'X' AND email = 'foo@bar.com' +ALLOW FILTERING +``` + +**Новая схема запроса:** +```sql +SELECT * FROM {keyspace}.rows +WHERE collection = 'X' AND schema_name = 'customers' + AND index_name = 'email' AND index_value = ['foo@bar.com'] +``` + +### Ключевые изменения + +1. **Упрощение семантики запросов**: Новая схема поддерживает только точное соответствие для `index_value`. Текущие фильтры GraphQL (`gt`, `lt`, `contains` и т.д.) либо: + Становятся постобработкой возвращаемых данных (если это все еще необходимо) + Удаляются в пользу использования API для работы с эмбеддингами для нечеткого сопоставления. + +2. **Код GraphQL тесно связан**: Текущие сборки `service.py` включают генерацию типов Strawberry, разбор фильтров и запросы, специфичные для Cassandra. Добавление еще одного бэкенда для хранения данных потребует дублирования примерно 400 строк кода GraphQL. + +### Предлагаемая реструктуризация + +Реструктуризация состоит из двух частей: + +#### 1. Выделение кода GraphQL + +Извлеките многократно используемые компоненты GraphQL в общий модуль: + +``` +trustgraph-flow/trustgraph/query/graphql/ +├── __init__.py +├── types.py # Filter types (IntFilter, StringFilter, FloatFilter) +├── schema.py # Dynamic schema generation from RowSchema +└── filters.py # Filter parsing utilities +``` + +Это позволяет: +Повторное использование в различных системах хранения данных. +Более четкое разделение ответственности. +Более простое тестирование логики GraphQL независимо. + +#### 2. Реализация новой схемы таблицы + +Переработайте код, специфичный для Cassandra, для использования унифицированной таблицы: + +**Записывающий модуль** (`trustgraph-flow/trustgraph/storage/rows/cassandra/`): +Одна `rows` таблица вместо таблиц для каждой схемы. +Запись N копий на строку (по одной для каждого индекса). +Регистрация в `row_partitions` таблице. +Более простое создание таблицы (единоразовая настройка). + +**Сервис запросов** (`trustgraph-flow/trustgraph/query/rows/cassandra/`): +Запрос унифицированной `rows` таблицы. +Использование извлеченного модуля GraphQL для генерации схемы. +Упрощенная обработка фильтров (только точное соответствие на уровне базы данных). + +### Переименование модулей + +В рамках очистки наименований "object" → "row": + +| Текущее | Новое | +|---------|-----| +| `storage/objects/cassandra/` | `storage/rows/cassandra/` | +| `query/objects/cassandra/` | `query/rows/cassandra/` | +| `embeddings/object_embeddings/` | `embeddings/row_embeddings/` | + +### Новые модули + +| Модуль | Назначение | +|--------|---------| +| `trustgraph-flow/trustgraph/query/graphql/` | Общие утилиты GraphQL | +| `trustgraph-flow/trustgraph/query/row_embeddings/qdrant/` | API запросов для векторных представлений строк | +| `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | Вычисление векторных представлений строк (Этап 1) | +| `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | Хранение векторных представлений строк (Этап 2) | + +## Ссылки + +[Техническая спецификация структурированных данных](structured-data.md) diff --git a/docs/tech-specs/structured-data-2.sw.md b/docs/tech-specs/structured-data-2.sw.md new file mode 100644 index 00000000..e2d6a3fa --- /dev/null +++ b/docs/tech-specs/structured-data-2.sw.md @@ -0,0 +1,613 @@ +# Vipimo vya Kawaida vya Takwimu Zilizopangwa (Sehemu ya 2) + +## Muhtasari + +Maelezo haya yanaeleza masuala na pengo ambazo zimetambuliwa wakati wa utekelezaji wa awali wa ujumuishaji wa takwimu zilizopangwa wa TrustGraph, kama ilivyoelezwa katika `structured-data.md`. + +## Matatizo + +### 1. Utangamano Usio sawa wa Majina: "Kitu" dhidi ya "Rata" + +Utaratibu wa sasa hutumia neno "kitembele" katika kila sehemu (k.m., `ExtractedObject`, utoaji wa kitu, uwekaji wa kitu). Neno hili ni la jumla sana na husababisha mchanganyiko: + +"Kitembele" ni neno linalotumika kwa matumizi mengi katika programu (vitu vya Python, vitu vya JSON, n.k.) +Data inayoshughulikiwa ni ya aina ya meza - ratiba katika meza zilizo na muundo uliotofautishwa +"Rata" inaelezea vizuri zaidi mfumo wa data na inaendana na neno la hifadhi ya data + +Utangamano huu huonekana katika majina ya moduli, majina ya madarasa, aina za ujumbe, na nyaraka. + +### 2. Mipaka ya Ufuatiliaji wa Rata + +Utaratibu wa sasa wa hifadhi ya rata una mipaka muhimu ya ufuatiliaji: + +**Utangamano wa Lugha Asilia:** Ufuatiliaji unashindana na tofauti za ulimwengu halisi. Kwa mfano: +Ni vigumu kupata hifadhi ya barabara inayokuwa na `"CHESTNUT ST"` wakati unatafuta `"Chestnut Street"` +Marekebisho, tofauti za herufi, na tofauti za umbizo hufutilia ufuatiliaji wa usawizi +Watumiaji wanatarajia uelewa wa maana, lakini hifadhi hutoa mechi ya moja kwa moja + +**Masuala ya Mabadiliko ya Muundo:** Mabadiliko ya muundo husababisha matatizo: +Data iliyopo inaweza kutosana na muundo uliosasishwa +Mabadiliko ya muundo wa meza yanaweza kuvunja ufuatiliaji na uadilifu wa data +Hakuna njia wazi ya kusonga muundo kwa mabadiliko ya muundo + +### 3. Uwekaji wa Rata Unahitajika + +Kuhusiana na tatizo la 2, mfumo unahitaji uwekaji wa vector kwa data ya rata ili kuwezesha: + +Ufuatiliaji wa maana katika data iliyopangwa (kupata "Chestnut Street" wakati data ina "CHESTNUT ST") +Mechi ya ufanano kwa ufuatiliaji wa uwazi +Ufuatiliaji wa mchanganyiko unaounganisha vichujio vilivyopangwa na ufanano wa maana +Usaidizi bora wa lugha asilia ya ufuatiliaji + +Huduma ya uwekaji ilikuwa imeelezwa lakini haijatekelezwa. + +### 4. Uongezaji wa Data ya Rata hajakamilika + +Mnyororo wa data ya takwimu zilizopangwa haujafanya kazi kikamilifu: + +Mawazo ya uchunguzi yanapatikana ili kuainisha muundo wa pembejeo (CSV, JSON, n.k.) +Huduma ya uongezaji ambayo hutumia mawazo haya haijunganishwa kwenye mfumo +Hakuna njia kamili ya kupakia data iliyopangwa tayari kwenye hifadhi ya rata + +## Lengo + +**Unyumbufu wa Muundo:** Kuwezesha mabadiliko ya muundo bila kuvunja data iliyopo au kuhitaji uhamisho +**Utangamano wa Majina:** Kuweka "rata" kama neno la kawaida katika kila sehemu ya programu +**Ufuatiliaji wa Maana:** Kusaidia mechi ya maana/uwazi kupitia uwekaji wa rata +**Mnyororo Kamili wa Uongezaji:** Kutoa njia kamili ya kupakia data iliyopangwa + +## Muundo wa Kiufundi + +### Muundo Uliounganishwa wa Hifadhi ya Rata + +Utaratibu wa awali uliunda meza tofauti ya Cassandra kwa kila muundo. Hii ilisababisha matatizo wakati muundo ulibadilika, kwa sababu mabadiliko ya muundo wa meza yalihitaji uhamisho. + +Muundo mpya hutumia meza moja iliyounganishwa kwa data yote ya rata: + +```sql +CREATE TABLE rows ( + collection text, + schema_name text, + index_name text, + index_value frozen>, + data map, + source text, + PRIMARY KEY ((collection, schema_name, index_name), index_value) +) +``` + +#### Ufafanuzi wa Safu + +| Safu | Aina | Maelezo | +|--------|------|-------------| +| `collection` | `text` | Kitambulisho cha ukusanyaji/kuingiza data (kutoka kwa metadata) | +| `schema_name` | `text` | Jina la mpango ambao safu hii inafuata | +| `index_name` | `text` | Majina ya sehemu zilizopangiliwa, yameunganishwa kwa mkato kwa sehemu mbalimbali | +| `index_value` | `frozen>` | Maadili ya kifunguo kama orodha | +| `data` | `map` | Data ya safu kama jozi za ufunguo-thamani | +| `source` | `text` | URI ya hiari inayounganisha na maelezo ya asili katika mfumo wa maarifa. Mnyororo tupu au NULL inaonyesha kuwa hakuna chanzo. | + +#### Usimamizi wa Faharasa + +Kila safu huhifadhiwa mara nyingi - mara moja kwa kila sehemu iliyopangiliwa iliyobainishwa katika mpango. Sehemu kuu za ufunguo zinatibiwa kama faharasa bila alama maalum, ambayo hutoa uwezekano wa kubadilika katika siku zijazo. + +**Mfano wa faharasa ya sehemu moja:** +Mpango unafafanua `email` kuwa iliyopangiliwa +`index_name = "email"` +`index_value = ['foo@bar.com']` + +**Mfano wa faharasa mchanganyiko:** +Mpango unafafanua faharasa mchanganyiko kwenye `region` na `status` +`index_name = "region,status"` (majina ya sehemu yamepangwa na yameunganishwa kwa mkato) +`index_value = ['US', 'active']` (maadili katika utaratibu sawa na majina ya sehemu) + +**Mfano wa ufunguo mkuu:** +Mpango unafafanua `customer_id` kuwa ufunguo mkuu +`index_name = "customer_id"` +`index_value = ['CUST001']` + +#### Mfano wa Maswali + +Maswali yote yanafuata muundo sawa bila kujali faharasa gani inayotumika: + +```sql +SELECT * FROM rows +WHERE collection = 'import_2024' + AND schema_name = 'customers' + AND index_name = 'email' + AND index_value = ['foo@bar.com'] +``` + +#### Mizunguko ya Ubunifu + +**Faida:** +Mabadiliko ya schema hayahitaji mabadiliko ya muundo wa jedwali +Data ya mstari ni ya siri kwa Cassandra - ongezeko/ondoano la nafasi ni wazi +Mfumo thabiti wa swali kwa njia zote za upatikanaji +Hakuna fahirisi za sekondari za Cassandra (ambazo zinaweza kuwa polepole kwa kiwango kikubwa) +Aina za asili za Cassandra katika kila sehemu (`map`, `frozen`) + +**Utofauti:** +Kuongezeka kwa uandishi: kila kuingizwa kwa mstari = ongezeko la N (moja kwa kila nafasi iliyofichwa) +Gharama ya kuhifadhi kutokana na data ya mstari iliyorudiwa +Habari ya aina huhifadhiwa katika usanidi wa schema, ubadilishaji katika safu ya programu + +#### Mfumo wa Ulinganisho + +Ubunifu huu unapokea uboreshaji fulani: + +1. **Hakuna sasisho za mstari**: Mfumo huu ni wa kuongeza tu. Hii inazuia wasiwasi wa ulinganisho kuhusu kusasisha nakala nyingi za mstari mmoja. + +2. **Uvumilivu wa mabadiliko ya schema**: Wakati schemas hubadilika (k.m., fahirisi zinaongezwa/kuondolewa), mistari iliyopo inaendelea kuwa na uwekaji wa fahirisi wake wa awali. Mistari ya zamani haitaweza kupatikana kupitia fahirisi mpya. Watumiaji wanaweza kufuta na kuunda tena schema ili kuhakikisha ulinganisho ikiwa ni lazima. + +### Ufuatiliaji na Ufutilishaji wa Sehemu + +#### Tatizo + +Kwa ufunguo wa sehemu `(collection, schema_name, index_name)`, ufutaji bora unahitaji kujua ufunguo wote wa sehemu ili kufutwa. Ufutilishaji kwa `collection` au `collection + schema_name` pekee unahitaji kujua maadili yote ya `index_name` ambayo yana data. + +#### Jedwali la Ufuatiliaji wa Sehemu + +Jedwali la ziada la utafutaji linafuatilia sehemu zipi zilizo. + +```sql +CREATE TABLE row_partitions ( + collection text, + schema_name text, + index_name text, + PRIMARY KEY ((collection), schema_name, index_name) +) +``` + +Hii inaruhusu ugunduzi bora wa sehemu za kufutwa. + +#### Tabia ya Kifaa cha Kuandika Mistari + +Kifaa cha kuandika mistari kinahifadhi kumbukumbu ya jozi zilizosajiliwa za `(collection, schema_name)`. Wakati wa kuchakata mstari: + +1. Angalia ikiwa `(collection, schema_name)` iko kwenye kumbukumbu +2. Ikiwa haijahifadhiwa (mstari wa kwanza kwa jozi hii): + Tafuta usanidi wa schema ili kupata majina yote ya index + Ingiza vipengele katika `row_partitions` kwa kila `(collection, schema_name, index_name)` + Ongeza jozi kwenye kumbukumbu +3. Endelea na kuandika data ya mstari + +Kifaa cha kuandika mistari pia kinachunguza mabadiliko ya usanidi wa schema. Wakati schema inabadilika, vipengele muhimu vya kumbukumbu vinafutwa ili mstari unaofuata usisababishwe tena usajili na majina mapya ya index. + +Mbinu hii inahakikisha: +Uandikaji wa jedwali la utafutaji hutokea mara moja kwa kila jozi ya `(collection, schema_name)`, sio kwa kila mstari +Jedwali la utafutaji linaonyesha indexes ambazo zilikuwa zinafanya kazi wakati data ilipoandikwa +Mabadiliko ya schema wakati wa uingizaji yanaonekana kwa usahihi + +#### Operesheni za Ufute + +**Futa mkusanyiko:** +```sql +-- 1. Discover all partitions +SELECT schema_name, index_name FROM row_partitions WHERE collection = 'X'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = '...' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table +DELETE FROM row_partitions WHERE collection = 'X'; +``` + +**Futa mkusanyiko na schema:** +```sql +-- 1. Discover partitions for this schema +SELECT index_name FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = 'Y' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table entries +DELETE FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; +``` + +### Uelekezaji wa Data + +Uelekezaji wa data unawezesha utambuzi wa maana/ufanano kwenye maadili yaliyohifadhiwa, na kutatua tatizo la kutofautiana kwa lugha (k.m., kutafuta "CHESTNUT ST" wakati unatafuta "Chestnut Street"). + +#### Muhtasari wa Ubunifu + +Kila jambo lililohifadhiwa limeelekezwa na kuhifadhiwa katika hifadhi ya vekta (Qdrant). Wakati wa utafutaji, swali linaelekezwa, vekta sawa zinafanywa, na metadata inayohusiana hutumiwa kutafuta mistari halisi katika Cassandra. + +#### Muundo wa Mkusanyiko wa Qdrant + +Mkusanyiko mmoja wa Qdrant kwa kila jozi ya `(user, collection, schema_name, dimension)`: + +**Jina la mkusanyiko:** `rows_{user}_{collection}_{schema_name}_{dimension}` +Majina husafishwa (herufi ambazo sio alfabeti hubadilishwa na `_`, yamebadilishwa kuwa herufi ndogo, prefixes za namba hupata prefix ya `r_`) +**Sababu:** Inaruhusu kufutwa kwa jozi ya `(user, collection, schema_name)` kwa kufuta makusanyiko yanayolingana ya Qdrant; kiambishi cha kipimo huruhusu modeli tofauti za uelekezaji kuwepo. + +#### Kile Kinachoelekezwa + +Uwazi wa maandishi wa maadili ya index: + +| Aina ya Index | Mfano wa `index_value` | Maandishi ya Kuelekeza | +|------------|----------------------|---------------| +| Uwanja mmoja | `['foo@bar.com']` | `"foo@bar.com"` | +| Mchanganyiko | `['US', 'active']` | `"US active"` (imeunganishwa na nafasi) | + +#### Muundo wa Pointi + +Kila pointi ya Qdrant ina: + +```json +{ + "id": "", + "vector": [0.1, 0.2, ...], + "payload": { + "index_name": "street_name", + "index_value": ["CHESTNUT ST"], + "text": "CHESTNUT ST" + } +} +``` + +| Uwanja wa Data | Maelezo | +|---------------|-------------| +| `index_name` | Uwanja(s) ulio(o) ambao embedding hii inawakilisha | +| `index_value` | Orodha ya awali ya maadili (kwa utafutaji wa Cassandra) | +| `text` | Nakala iliyoingizwa (kwa ajili ya utatuzi/kuonyesha) | + +Kumbuka: `user`, `collection`, na `schema_name` zinaonyeshwa moja kwa moja kutoka kwa jina la mkusanyiko wa Qdrant. + +#### Mtiririko wa Utafiti + +1. Mtumiaji anatafuta "Chestnut Street" ndani ya mtumiaji U, mkusanyiko X, schema Y +2. Ingiza nakala ya utafutaji +3. Tambua jina(s) la mkusanyiko wa Qdrant linalolingana na kielelezo `rows_U_X_Y_` +4. Tafuta mkusanyiko(s) unaolingana wa Qdrant kwa vectori za karibu +5. Pata pointi zinazolingana zilizo na data zinazozingatia `index_name` na `index_value` +6. Tafuta Cassandra: + ```sql + SELECT * FROM rows + WHERE collection = 'X' + AND schema_name = 'Y' + AND index_name = '' + AND index_value = + ``` +7. Kurudisha mistari iliyolingana. + +#### Hiari: Kuchuja kwa Jina la Index + +Maswali yanaweza hiari kuchuja kwa `index_name` katika Qdrant ili kutafuta tu sehemu maalum: + +**"Tafuta sehemu yoyote inayolingana na 'Chestnut'"** → tafuta vectori zote katika mkusanyiko. +**"Tafuta 'street_name' inayolingana na 'Chestnut'"** → chuja ambapo `payload.index_name = 'street_name'`. + +#### Muundo + +Uwekaji wa mistari unafuata **muundo wa hatua mbili** unaotumika na GraphRAG (uwekaji wa grafu, uwekaji wa hati): + +**Hatua ya 1: Hesabu ya uwekaji** (`trustgraph-flow/trustgraph/embeddings/row_embeddings/`) - Hutumia `ExtractedObject`, huhesabu uwekaji kupitia huduma ya uwekaji, hutoka `RowEmbeddings`. +**Hatua ya 2: Uhifadhi wa uwekaji** (`trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/`) - Hutumia `RowEmbeddings`, huandika vectori kwenye Qdrant. + +Mwandishi wa mistari wa Cassandra ni mtumiaji wa ziada unaoendeshwa kwa njia fiche: + +**Mwandishi wa mistari wa Cassandra** (`trustgraph-flow/trustgraph/storage/rows/cassandra`) - Hutumia `ExtractedObject`, huandika mistari kwenye Cassandra. + +Huduma zote tatu hutumia kutoka kwa mtiririko mmoja, na hivyo kuzifanya kuwa huru. Hii inaruhusu: +Uongezaji wa kasi wa kujitegemea wa uandishi wa Cassandra dhidi ya utengenezaji wa uwekaji dhidi ya uhifadhi wa vectori. +Huduma za uwekaji zinaweza kuzimwa ikiwa hazihitajiki. +Hitilafu katika huduma moja hazisababishi athari kwa huduma zingine. +Muundo thabiti na mabomba ya GraphRAG. + +#### Njia ya Kuandika + +**Hatua ya 1 (mchakato wa uwekaji wa mistari):** Unapopokea `ExtractedObject`: + +1. Tafuta schema ili kupata sehemu zilizoidishwa. +2. Kwa kila sehemu iliyoidishwa: + Jenga uwakilishi wa maandishi wa thamani ya index. + Hesabu uwekaji kupitia huduma ya uwekaji. +3. Toa ujumbe wa `RowEmbeddings` unao na vectori zote zilizohitajiwa. + +**Hatua ya 2 (uandishi wa uwekaji wa mistari-qdrant):** Unapopokea `RowEmbeddings`: + +1. Kwa kila uwekaji katika ujumbe: + Tambua mkusanyiko wa Qdrant kutoka `(user, collection, schema_name, dimension)`. + Unda mkusanyiko ikiwa unahitajika (utengenezaji wa polepole katika uandishi wa kwanza). + Ongeza pointi na vector na mzigo. + +#### Aina za Ujumbe + +```python +@dataclass +class RowIndexEmbedding: + index_name: str # The indexed field name(s) + index_value: list[str] # The field value(s) + text: str # Text that was embedded + vectors: list[list[float]] # Computed embedding vectors + +@dataclass +class RowEmbeddings: + metadata: Metadata + schema_name: str + embeddings: list[RowIndexEmbedding] +``` + +#### Jumuisho la Ufuteaji + +Makusanyo ya Qdrant hugunduliwa kwa kutumia utangamano wa jina la makusanyo: + +**Futa `(user, collection)`:** +1. Orodha makusanyo yote ya Qdrant yanayolingana na utangamano `rows_{user}_{collection}_` +2. Futa kila makusanyo yanayolingana +3. Futa sehemu za mistari ya Cassandra (kama ilivyoelezwa hapo juu) +4. Safisha maingizo ya `row_partitions` + +**Futa `(user, collection, schema_name)`:** +1. Orodha makusanyo yote ya Qdrant yanayolingana na utangamano `rows_{user}_{collection}_{schema_name}_` +2. Futa kila makusanyo yanayolingana (inashughulikia vipimo vingi) +3. Futa sehemu za mistari ya Cassandra +4. Safisha `row_partitions` + +#### Maeneo ya Moduli + +| Hatua | Moduli | Kituo cha Kuanzia | +|-------|--------|-------------| +| Hatua 1 | `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | `row-embeddings` | +| Hatua 2 | `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | `row-embeddings-write-qdrant` | + +### API ya Uchunguzi wa Uelekezo + +Uchunguzi wa uelekezo ni **API tofauti** kutoka kwa huduma ya uchunguzi wa mstari wa GraphQL: + +| API | Madhumuni | Nyuma | +|-----|---------|---------| +| Uchunguzi wa Mstari (GraphQL) | Utangamano kamili kwenye sehemu zilizofichwa | Cassandra | +| Uchunguzi wa Uelekezo | Utangamano wa dhana/maneno | Qdrant | + +Tofauti hii huweka masuala tofauti: +Huduma ya GraphQL inazingatia maswali kamili na yaliyo na muundo +API ya uelekezo inashughulikia ufanano wa dhana +Mchakato wa mtumiaji: utafutaji wa dhana kupitia uelekezo ili kupata wagombea, kisha uchunguzi kamili ili kupata data kamili ya mstari + +#### Mfumo wa Ombi/Jibu + +```python +@dataclass +class RowEmbeddingsRequest: + vectors: list[list[float]] # Query vectors (pre-computed embeddings) + user: str = "" + collection: str = "" + schema_name: str = "" + index_name: str = "" # Optional: filter to specific index + limit: int = 10 # Max results per vector + +@dataclass +class RowIndexMatch: + index_name: str = "" # The matched index field(s) + index_value: list[str] = [] # The matched value(s) + text: str = "" # Original text that was embedded + score: float = 0.0 # Similarity score + +@dataclass +class RowEmbeddingsResponse: + error: Error | None = None + matches: list[RowIndexMatch] = [] +``` + +#### Mchakato wa Uchunguzi + +Moduli: `trustgraph-flow/trustgraph/query/row_embeddings/qdrant` + +Kuanzia: `row-embeddings-query-qdrant` + +Mchakato: +1. Hupokea `RowEmbeddingsRequest` pamoja na vektor za swali +2. Hutafuta mkusanyiko unaofaa wa Qdrant kwa kutumia utangamano wa nenosiri +3. Hutafuta vektor za karibu pamoja na kipengele cha `index_name` cha hiari +4. Hurudisha `RowEmbeddingsResponse` pamoja na maelezo ya fahirisi yanayolingana + +#### Uunganisho wa Milango ya API + +Lango huonyesha maswali ya uelekezo wa mstari kupitia muundo wa kawaida wa ombi/jibu: + +| Sehemu | Mahali | +|-----------|----------| +| Msambazaji | `trustgraph-flow/trustgraph/gateway/dispatch/row_embeddings_query.py` | +| Usajili | Ongeza `"row-embeddings"` kwenye `request_response_dispatchers` katika `manager.py` | + +Jina la kiungo cha mtiririko: `row-embeddings` + +Ufafanuzi wa kiungo katika mpango wa mtiririko: +```json +{ + "interfaces": { + "row-embeddings": { + "request": "non-persistent://tg/request/row-embeddings:{id}", + "response": "non-persistent://tg/response/row-embeddings:{id}" + } + } +} +``` + +#### Usaidizi wa SDK ya Python + +SDK hutoa njia za kuuliza kuhusu uwekaji wa data katika mistari: + +```python +# Flow-scoped query (preferred) +api = Api(url) +flow = api.flow().id("default") + +# Query with text (SDK computes embeddings) +matches = flow.row_embeddings_query( + text="Chestnut Street", + collection="my_collection", + schema_name="addresses", + index_name="street_name", # Optional filter + limit=10 +) + +# Query with pre-computed vectors +matches = flow.row_embeddings_query( + vectors=[[0.1, 0.2, ...]], + collection="my_collection", + schema_name="addresses" +) + +# Each match contains: +for match in matches: + print(match.index_name) # e.g., "street_name" + print(match.index_value) # e.g., ["CHESTNUT ST"] + print(match.text) # e.g., "CHESTNUT ST" + print(match.score) # e.g., 0.95 +``` + +#### Utumizi wa Kamba ya Amri + +Amri: `tg-invoke-row-embeddings` + +```bash +# Query by text (computes embedding automatically) +tg-invoke-row-embeddings \ + --text "Chestnut Street" \ + --collection my_collection \ + --schema addresses \ + --index street_name \ + --limit 10 + +# Query by vector file +tg-invoke-row-embeddings \ + --vectors vectors.json \ + --collection my_collection \ + --schema addresses + +# Output formats +tg-invoke-row-embeddings --text "..." --format json +tg-invoke-row-embeddings --text "..." --format table +``` + +#### Mfano wa Matumizi ya Kawaida + +Uchunguzi wa pembejeo za mstari kwa kawaida hutumika kama sehemu ya mtiririko wa utafutaji wa "vunjifu" hadi "sahihi": + +```python +# Step 1: Fuzzy search via embeddings +matches = flow.row_embeddings_query( + text="chestnut street", + collection="geo", + schema_name="streets" +) + +# Step 2: Exact lookup via GraphQL for full row data +for match in matches: + query = f''' + query {{ + streets(where: {{ {match.index_name}: {{ eq: "{match.index_value[0]}" }} }}) {{ + street_name + city + zip_code + }} + }} + ''' + rows = flow.rows_query(query, collection="geo") +``` + +Mfumo huu wa hatua mbili huruhusu: +Kugundua "CHESTNUT ST" wakati mtumiaji anatafuta "Chestnut Street" +Kuchukua data kamili ya mstari pamoja na sehemu zote +Kuchanganya utambulisho wa maana na ufikiaji wa data iliyopangwa + +### Uingizaji wa Data ya Mstari + +Itarefushwa hadi hatua ya baadaye. Itaundwa pamoja na mabadiliko mengine ya uingizaji. + +## Athari ya Utendaji + +### Uchambuzi wa Hali ya Sasa + +Utendaji uliopo una vipengele viwili mikuu: + +| Kipengele | Mahali | Mistari | Maelezo | +|-----------|----------|-------|-------------| +| Huduma ya Utafutaji | `trustgraph-flow/trustgraph/query/objects/cassandra/service.py` | ~740 | Moja kwa moja: Uundaji wa schema ya GraphQL, uchanganuzi wa vichujio, maswali ya Cassandra, usimamizi wa ombi | +| Mwandishi | `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` | ~540 | Uundaji wa jedwali kwa kila schema, fahirisi za sekondari, kuingiza/kufuta | + +**Mfumo wa Sasa wa Utafutaji:** +```sql +SELECT * FROM {keyspace}.o_{schema_name} +WHERE collection = 'X' AND email = 'foo@bar.com' +ALLOW FILTERING +``` + +**Muundo Mpya wa Ulizaji:** +```sql +SELECT * FROM {keyspace}.rows +WHERE collection = 'X' AND schema_name = 'customers' + AND index_name = 'email' AND index_value = ['foo@bar.com'] +``` + +### Mabadiliko Muhimu + +1. **Uboreshaji wa maana ya maswali**: Mfumo mpya unaunga mkono tu mechi kamili kwenye `index_value`. Vifiltrishi vya GraphQL ya sasa (`gt`, `lt`, `contains`, n.k.) ama: + Yanakuwa uchujaji wa ziada kwenye data iliyorudishwa (ikiwa bado inahitajika) + Yanondolewa ili kutumia API ya embeddings kwa mechi zisizo sahihi + +2. **Msimbo wa GraphQL umeunganishwa sana**: Mfumo wa sasa wa `service.py` unajumuisha utengenezaji wa aina za Strawberry, uchanganuzi wa vifiltrishi, na maswali maalum ya Cassandra. Kuongeza mfumo mwingine wa kuhifadhi data ingeongeza mistari ~400 ya msimbo wa GraphQL. + +### Pendekezo la Urekebishaji + +Urekebishaji una sehemu mbili: + +#### 1. Tenganisha Msimbo wa GraphQL + +Toa vipengele vya GraphQL ambavyo vinaweza kutumika tena katika moduli iliyoshirikiwa: + +``` +trustgraph-flow/trustgraph/query/graphql/ +├── __init__.py +├── types.py # Filter types (IntFilter, StringFilter, FloatFilter) +├── schema.py # Dynamic schema generation from RowSchema +└── filters.py # Filter parsing utilities +``` + +Hii inawezesha: +Matumizi upya katika mifumo tofauti ya kuhifadhi data. +Tofauti wazi zaidi ya majukumu. +Uchunguzi rahisi zaidi wa mantiki ya GraphQL kwa kujitegemea. + +#### 2. Tengeneza Mpango Mpya wa Jedwali + +Badilisha msimbo maalum wa Cassandra ili kutumia jedwali lililo na mpango mmoja: + +**Mwandishi** (`trustgraph-flow/trustgraph/storage/rows/cassandra/`): +Jedwali moja la `rows` badala ya jedwali kila mpango. +Andika nakala N kwa kila mstari (moja kwa kila fahirisi). +Jisajili kwenye jedwali la `row_partitions`. +Uundaji rahisi zaidi wa jedwali (usanidi wa mara moja). + +**Huduma ya Utafiti** (`trustgraph-flow/trustgraph/query/rows/cassandra/`): +Tafuta kwenye jedwali lililo na mpango mmoja la `rows`. +Tumia moduli iliyochimbwa ya GraphQL kwa uundaji wa mpango. +Usimamizi ulioboreshwa wa vichujio (mechi kamili tu kwenye kiwango cha hifadhidata). + +### Mabadiliko ya Majina ya Moduli + +Kama sehemu ya usafi wa majina kutoka "object" hadi "row": + +| Sasa | Mpya | +|---------|-----| +| `storage/objects/cassandra/` | `storage/rows/cassandra/` | +| `query/objects/cassandra/` | `query/rows/cassandra/` | +| `embeddings/object_embeddings/` | `embeddings/row_embeddings/` | + +### Moduli Mpya + +| Moduli | Lengo | +|--------|---------| +| `trustgraph-flow/trustgraph/query/graphql/` | Utumizi wa pamoja wa GraphQL. | +| `trustgraph-flow/trustgraph/query/row_embeddings/qdrant/` | API ya utafiti wa uingishaji wa mstari. | +| `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | Hesabu ya uingishaji wa mstari (Hatua ya 1). | +| `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | Uhifadhi wa uingishaji wa mstari (Hatua ya 2). | + +## Marejeleo + +[Maelezo ya Kiufundi ya Data Iliyopangwa](structured-data.md) diff --git a/docs/tech-specs/structured-data-2.tr.md b/docs/tech-specs/structured-data-2.tr.md new file mode 100644 index 00000000..274f748d --- /dev/null +++ b/docs/tech-specs/structured-data-2.tr.md @@ -0,0 +1,613 @@ +# Yapılandırılmış Veri Teknik Özellikleri (Bölüm 2) + +## Genel Bakış + +Bu özellik, TrustGraph'ın yapılandırılmış veri entegrasyonunun ilk uygulamasının ilk aşamalarında tespit edilen sorunları ve eksiklikleri ele almaktadır, bu da `structured-data.md`'da açıklanmıştır. + +## Sorun Tanımları + +### 1. İsimlendirme Tutarsızlığı: "Nesne" vs "Satır" + +Mevcut uygulama, "nesne" terimini tüm alanlarda kullanmaktadır (örneğin, `ExtractedObject`, nesne çıkarma, nesne gömme). Bu isimlendirme çok genel olup kafa karışıklığına neden olmaktadır: + +"Nesne" terimi, yazılımda (Python nesneleri, JSON nesneleri vb.) aşırı kullanılan bir terimdir. +İşlenen veri temelde tablolardır; tanımlı şemalara sahip satırlar. +"Satır", veri modelini daha doğru bir şekilde tanımlar ve veritabanı terminolojisiyle uyumludur. + +Bu tutarsızlık, modül adlarında, sınıf adlarında, mesaj türlerinde ve belgelerde görülmektedir. + +### 2. Satır Depolama Sorgu Sınırlamaları + +Mevcut satır depolama uygulamasının önemli sorgu sınırlamaları bulunmaktadır: + +**Doğal Dil Uyumsuzluğu**: Sorgular, gerçek dünya verilerindeki değişikliklerle başa çıkmakta zorlanmaktadır. Örneğin: +`"CHESTNUT ST"` içeren bir sokak veritabanını sorgulamak, `"Chestnut Street"` hakkında bilgi almak için zordur. +Kısaltmalar, büyük/küçük harf farklılıkları ve biçimlendirme değişiklikleri, tam eşleşme sorgularını bozmaktadır. +Kullanıcılar semantik bir anlayış beklemekte, ancak depolama literal eşleşme sağlamaktadır. + +**Şema Evrimi Sorunları**: Şemaların değiştirilmesi sorunlara neden olmaktadır: +Mevcut veriler, güncellenmiş şemalara uygun olmayabilir. +Tablo yapısındaki değişiklikler, sorguları ve veri bütünlüğünü bozabilir. +Şema güncellemeleri için net bir geçiş yolu bulunmamaktadır. + +### 3. Satır Gömme Gerekliliği + +2. soruna bağlı olarak, sistemin satır verileri için vektör gömmelere ihtiyacı vardır, bu da şunları sağlamak için gereklidir: + +Yapılandırılmış veriler arasında semantik arama (örneğin, "Chestnut Street" verisinin "CHESTNUT ST" olarak bulunduğu durumlarda) +Bulanık sorgular için benzerlik eşleştirme +Yapılandırılmış filtreleri semantik benzerlikle birleştiren hibrit arama +Daha iyi doğal dil sorgu desteği + +Gömme hizmeti belirtilmiş, ancak uygulanmamıştır. + +### 4. Satır Veri Alımı Eksikliği + +Yapılandırılmış veri alım hattı henüz tam olarak çalışır durumda değildir: + +Giriş formatlarını (CSV, JSON vb.) sınıflandırmak için tanısal istemler bulunmaktadır. +Bu istemleri kullanan alım hizmeti, sisteme entegre edilmemiştir. +Önceden yapılandırılmış verileri satır deposuna yüklemek için uçtan uca bir yol bulunmamaktadır. + +## Hedefler + +**Şema Esnekliği**: Mevcut verileri bozmadan veya geçişler gerektirmeden şema evrimini etkinleştirin. +**Tutarlı İsimlendirme**: Kod tabanında "satır" terimini standartlaştırın. +**Semantik Sorgulanabilirlik**: Satır gömmeleri aracılığıyla bulanık/semantik eşleştirmeyi destekleyin. +**Tam Alım Hattı**: Yapılandırılmış verileri yüklemek için uçtan uca bir yol sağlayın. + +## Teknik Tasarım + +### Birleşik Satır Depolama Şeması + +Önceki uygulamada, her şema için ayrı bir Cassandra tablosu oluşturulmuştur. Bu, şema evrimleri sırasında tablo yapısındaki değişikliklerin geçişler gerektirmesine neden olmuştur. + +Yeni tasarım, tüm satır verileri için tek birleşik bir tablo kullanmaktadır: + +```sql +CREATE TABLE rows ( + collection text, + schema_name text, + index_name text, + index_value frozen>, + data map, + source text, + PRIMARY KEY ((collection, schema_name, index_name), index_value) +) +``` + +#### Sütun Tanımları + +| Sütun | Tür | Açıklama | +|--------|------|-------------| +| `collection` | `text` | Veri toplama/içe aktarma tanımlayıcısı (metaveriden) | +| `schema_name` | `text` | Bu satırın uyduğu şema adı | +| `index_name` | `text` | Birleştirilmiş virgülle indekslenen alan(lar) adı | +| `index_value` | `frozen>` | Liste olarak indeks değerleri | +| `data` | `map` | Satır verisi, anahtar-değer çiftleri olarak | +| `source` | `text` | Bilgi grafiğindeki kaynak bilgisine bağlanan isteğe bağlı URI. Boş bir dize veya NULL, kaynak olmadığını gösterir. | + +#### İndeks Yönetimi + +Her satır, şemada tanımlanan her indeks için bir kez olmak üzere birden çok kez saklanır. Birincil anahtar alanları, özel bir işaretçi olmadan bir indeks olarak kabul edilir ve bu, gelecekteki esnekliği sağlar. + +**Tek alanlı indeks örneği:** +Şema, `email`'ı indeks olarak tanımlar +`index_name = "email"` +`index_value = ['foo@bar.com']` + +**Bileşik indeks örneği:** +Şema, `region` ve `status` üzerinde bileşik bir indeks tanımlar +`index_name = "region,status"` (alan adları sıralanır ve virgülle birleştirilir) +`index_value = ['US', 'active']` (değerler, alan adları sırasıyla aynı sırada) + +**Birincil anahtar örneği:** +Şema, `customer_id`'ı birincil anahtar olarak tanımlar +`index_name = "customer_id"` +`index_value = ['CUST001']` + +#### Sorgu Desenleri + +Tüm sorgular, kullanılan indeksten bağımsız olarak aynı deseni izler: + +```sql +SELECT * FROM rows +WHERE collection = 'import_2024' + AND schema_name = 'customers' + AND index_name = 'email' + AND index_value = ['foo@bar.com'] +``` + +#### Tasarım Uzlaşmaları + +**Avantajları:** +Şema değişiklikleri, tablo yapısı değişiklikleri gerektirmez. +Satır verileri Cassandra için şeffaftır; alan ekleme/çıkarma işlemleri şeffaftır. +Tüm erişim yöntemleri için tutarlı sorgu kalıbı. +Cassandra'nın ikincil indeksleri (ki bunlar ölçekte yavaş olabilir). +Tüm yerel Cassandra türleri (`map`, `frozen`). + +**Uzlaşmalar:** +Yazma çoğaltması: her satır eklemesi = N eklemesi (dizinlenmiş alan başına bir tane). +Tekrarlanan satır verilerinden kaynaklanan depolama ek yükü. +Tür bilgisi şema yapılandırmasında saklanır, dönüşüm uygulama katmanında yapılır. + +#### Tutarlılık Modeli + +Bu tasarım, belirli basitleştirmeleri kabul eder: + +1. **Satır güncellemeleri yok:** Sistem yalnızca eklemelerle çalışır. Bu, aynı satırın birden çok kopyasının güncellenmesiyle ilgili tutarlılık sorunlarını ortadan kaldırır. + +2. **Şema değişikliği toleransı:** Şemalar değiştiğinde (örneğin, indeksler eklendi/çıkarıldı), mevcut satırlar orijinal dizinlemelerini korur. Eski satırlar, gerektiğinde kullanıcılar tutarlılığı sağlamak için bir şemayı silebilir ve yeniden oluşturabilir, ancak yeni indeksler aracılığıyla bulunamaz. + +### Bölüm Takibi ve Silme + +#### Sorun + +Bölüm anahtarı `(collection, schema_name, index_name)` ile, verimli silme, silinecek tüm bölüm anahtarlarını bilmeyi gerektirir. Yalnızca `collection` veya `collection + schema_name` ile silmek, veriye sahip olan tüm `index_name` değerlerini bilmeyi gerektirir. + +#### Bölüm Takip Tablosu + +Birincil olmayan bir arama tablosu, hangi bölümlerin mevcut olduğunu izler: + +```sql +CREATE TABLE row_partitions ( + collection text, + schema_name text, + index_name text, + PRIMARY KEY ((collection), schema_name, index_name) +) +``` + +Bu, silme işlemleri için bölümlerin verimli bir şekilde bulunmasını sağlar. + +#### Satır Yazıcı Davranışı + +Satır yazıcı, kaydedilen `(collection, schema_name)` çiftlerinin bellek içi bir önbelleğini tutar. Bir satırı işlerken: + +1. `(collection, schema_name)`'ın önbellekte olup olmadığını kontrol edin. +2. Önbellekte yoksa (bu çift için ilk satır): + Tüm indeks adlarını almak için şema yapılandırmasını arayın. + Her `(collection, schema_name, index_name)` için `row_partitions`'a girişler ekleyin. + Çifti önbelleğe ekleyin. +3. Satır verilerini yazmaya devam edin. + +Satır yazıcı ayrıca şema yapılandırma değişiklik olaylarını da izler. Bir şema değiştiğinde, ilgili önbellek girişleri temizlenir, böylece sonraki satır, güncellenmiş indeks adlarıyla yeniden kayda alınmasını sağlar. + +Bu yaklaşım şunları sağlar: +Arama tablosu yazmaları, satır başına değil, her `(collection, schema_name)` çifti için bir kez gerçekleşir. +Arama tablosu, verilerin yazıldığı sırada aktif olan indeksleri yansıtır. +İçe aktarma sırasında yapılan şema değişiklikleri doğru şekilde algılanır. + +#### Silme İşlemleri + +**Koleksiyonu sil:** +```sql +-- 1. Discover all partitions +SELECT schema_name, index_name FROM row_partitions WHERE collection = 'X'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = '...' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table +DELETE FROM row_partitions WHERE collection = 'X'; +``` + +**Koleksiyonu ve şemayı sil:** +```sql +-- 1. Discover partitions for this schema +SELECT index_name FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = 'Y' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table entries +DELETE FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; +``` + +### Satır Gömme İşlemleri + +Satır gömme işlemleri, indeksli değerlerde semantik/bulanık eşleşme sağlayarak, doğal dil uyumsuzluğu sorununu çözer (örneğin, "Chestnut Street" için arama yaparken "CHESTNUT ST" bulmak). + +#### Tasarım Genel Bakışı + +Her indeksli değer gömülür ve bir vektör deposunda (Qdrant) saklanır. Sorgu zamanında, sorgu gömülür, benzer vektörler bulunur ve ilişkili meta veriler, Cassandra'daki gerçek satırları bulmak için kullanılır. + +#### Qdrant Koleksiyonu Yapısı + +Her `(user, collection, schema_name, dimension)` tuple'ı için bir Qdrant koleksiyonu: + +**Koleksiyon adı:** `rows_{user}_{collection}_{schema_name}_{dimension}` +İsimler temizlenir (alfanumerik olmayan karakterler `_` ile değiştirilir, küçük harfe dönüştürülür, sayısal önekler `r_` öneki alır) +**Gerekçe:** Bir `(user, collection, schema_name)` örneğini, eşleşen Qdrant koleksiyonlarını silerek temiz bir şekilde silmeyi sağlar; boyut soneki, farklı gömme modellerinin birlikte var olmasına olanak tanır. + +#### Nelerin Gömüldüğü + +İndeks değerlerinin metin gösterimi: + +| İndeks Tipi | Örnek `index_value` | Gömülecek Metin | +|------------|----------------------|---------------| +| Tek Alan | `['foo@bar.com']` | `"foo@bar.com"` | +| Birleşik | `['US', 'active']` | `"US active"` (boşluklarla birleştirilmiş) | + +#### Nokta Yapısı + +Her Qdrant noktası şunları içerir: + +```json +{ + "id": "", + "vector": [0.1, 0.2, ...], + "payload": { + "index_name": "street_name", + "index_value": ["CHESTNUT ST"], + "text": "CHESTNUT ST" + } +} +``` + +| Yük Verisi Alanı | Açıklama | +|---------------|-------------| +| `index_name` | Bu gömme işleminin temsil ettiği indeksli alan(lar). | +| `index_value` | Cassandra araması için orijinal değer listesi. | +| `text` | Gömülen metin (hata ayıklama/görüntüleme için). | + +Not: `user`, `collection` ve `schema_name`, Qdrant koleksiyon adı aracılığıyla örtülüdür. | + +#### Sorgu Akışı | + +1. Kullanıcı, kullanıcı U, koleksiyon X ve şema Y içinde "Chestnut Street" için sorgu yapar. | +2. Sorgu metnini gömün. | +3. Önekle eşleşen Qdrant koleksiyon adı(larını) belirleyin: `rows_U_X_Y_`. | +4. En yakın vektörler için eşleşen Qdrant koleksiyonları içinde arama yapın. | +5. `index_name` ve `index_value` içeren yük verilerine sahip eşleşen noktaları alın. | +6. Cassandra'ya sorgu yapın: | + ```sql + SELECT * FROM rows + WHERE collection = 'X' + AND schema_name = 'Y' + AND index_name = '' + AND index_value = + ``` +7. Eşleşen satırları döndür. + +#### İsteğe Bağlı: İndeks Adı ile Filtreleme + +Sorgular, Qdrant'ta yalnızca belirli alanları aramak için isteğe bağlı olarak `index_name` ile filtrelenebilir: + +**" 'Chestnut' ile eşleşen herhangi bir alanı bul"** → koleksiyondaki tüm vektörleri arayın. +**" 'Chestnut' ile eşleşen 'street_name' alanını bul"** → `payload.index_name = 'street_name'` alanını filtreleyin. + +#### Mimari + +Satır gömüleri, GraphRAG tarafından kullanılan **iki aşamalı yapılandırmaya** sahiptir (grafik-gömüleri, belge-gömüleri): + +**1. Aşama: Gömü hesaplama** (`trustgraph-flow/trustgraph/embeddings/row_embeddings/`) - `ExtractedObject`'i tüketir, gömü hizmeti aracılığıyla gömüleri hesaplar, `RowEmbeddings` çıktısını üretir. +**2. Aşama: Gömü depolama** (`trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/`) - `RowEmbeddings`'i tüketir, vektörleri Qdrant'a yazar. + +Cassandra satır yazarı, ayrı bir paralel tüketici işlemidir: + +**Cassandra satır yazarı** (`trustgraph-flow/trustgraph/storage/rows/cassandra`) - `ExtractedObject`'i tüketir, satırları Cassandra'ya yazar. + +Tüm üç hizmet de aynı akıştan tüketir, böylece bunlar birbirinden ayrılır. Bu, şunları sağlar: +Cassandra yazma işlemlerinin, gömü oluşturma işlemlerine ve vektör depolama işlemlerine göre bağımsız olarak ölçeklenebilmesi. +Gerekli değilse gömü hizmetleri devre dışı bırakılabilir. +Bir hizmetteki hatalar diğerlerini etkilemez. +GraphRAG işlem hatları ile tutarlı bir mimari. + +#### Yazma Yolu + +**1. Aşama (satır-gömü işlemcisi):** Bir `ExtractedObject` aldığında: + +1. İndeksli alanları bulmak için şemayı arayın. +2. Her indeksli alan için: + İndeks değerinin metin gösterimini oluşturun. + Gömü hizmeti aracılığıyla gömüyü hesaplayın. +3. Tüm hesaplanan vektörleri içeren bir `RowEmbeddings` mesajı çıktısını verin. + +**2. Aşama (satır-gömü-yaz-qdrant):** Bir `RowEmbeddings` aldığında: + +1. Mesajdaki her gömü için: + `(user, collection, schema_name, dimension)`'dan Qdrant koleksiyonunu belirleyin. + Gerekirse koleksiyonu oluşturun (ilk yazmada tembel oluşturma). + Vektör ve yük ile noktayı ekleyin/güncelleyin. + +#### Mesaj Türleri + +```python +@dataclass +class RowIndexEmbedding: + index_name: str # The indexed field name(s) + index_value: list[str] # The field value(s) + text: str # Text that was embedded + vectors: list[list[float]] # Computed embedding vectors + +@dataclass +class RowEmbeddings: + metadata: Metadata + schema_name: str + embeddings: list[RowIndexEmbedding] +``` + +#### Silme Entegrasyonu + +Qdrant koleksiyonları, koleksiyon adı kalıbına göre önek eşleştirmesiyle bulunur: + +**`(user, collection)`'ı Silin:** +1. Önek `rows_{user}_{collection}_` ile eşleşen tüm Qdrant koleksiyonlarını listeleyin +2. Her eşleşen koleksiyonu silin +3. Cassandra satır bölümlerini silin (yukarıda belirtildiği gibi) +4. `row_partitions` girişlerini temizleyin + +**`(user, collection, schema_name)`'ı Silin:** +1. Önek `rows_{user}_{collection}_{schema_name}_` ile eşleşen tüm Qdrant koleksiyonlarını listeleyin +2. Her eşleşen koleksiyonu silin (çoklu boyutları işler) +3. Cassandra satır bölümlerini silin +4. `row_partitions`'ı temizleyin + +#### Modül Konumları + +| Aşama | Modül | Giriş Noktası | +|-------|--------|-------------| +| Aşama 1 | `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | `row-embeddings` | +| Aşama 2 | `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | `row-embeddings-write-qdrant` | + +### Satır Gömme Sorgu API'si + +Satır gömme sorgusu, GraphQL satır sorgu hizmetinden **ayrı bir API'dir**: + +| API | Amaç | Arka Uç | +|-----|---------|---------| +| Satır Sorgusu (GraphQL) | İndekslenmiş alanlarda tam eşleşme | Cassandra | +| Satır Gömme Sorgusu | Bulanık/anlamsal eşleşme | Qdrant | + +Bu ayrım, işlevleri net tutar: +GraphQL hizmeti, tam ve yapılandırılmış sorgulara odaklanır +Gömme API'si, anlamsal benzerliği işler +Kullanıcı iş akışı: adayları bulmak için gömmeler aracılığıyla bulanık arama, ardından tam satır verilerini almak için tam sorgu + +#### İstek/Yanıt Şeması + +```python +@dataclass +class RowEmbeddingsRequest: + vectors: list[list[float]] # Query vectors (pre-computed embeddings) + user: str = "" + collection: str = "" + schema_name: str = "" + index_name: str = "" # Optional: filter to specific index + limit: int = 10 # Max results per vector + +@dataclass +class RowIndexMatch: + index_name: str = "" # The matched index field(s) + index_value: list[str] = [] # The matched value(s) + text: str = "" # Original text that was embedded + score: float = 0.0 # Similarity score + +@dataclass +class RowEmbeddingsResponse: + error: Error | None = None + matches: list[RowIndexMatch] = [] +``` + +#### Sorgu İşleyici + +Modül: `trustgraph-flow/trustgraph/query/row_embeddings/qdrant` + +Giriş noktası: `row-embeddings-query-qdrant` + +İşleyici: +1. `RowEmbeddingsRequest` ile sorgu vektörlerini alır. +2. Önek eşleştirmesiyle uygun Qdrant koleksiyonunu bulur. +3. İsteğe bağlı `index_name` filtresiyle en yakın vektörleri arar. +4. Eşleşen indeks bilgileriyle `RowEmbeddingsResponse` döndürür. + +#### API Ağ Geçidi Entegrasyonu + +Ağ geçidi, standart istek/yanıt kalıbı aracılığıyla satır gömme sorgularını sunar: + +| Bileşen | Konum | +|-----------|----------| +| Yönlendirici | `trustgraph-flow/trustgraph/gateway/dispatch/row_embeddings_query.py` | +| Kayıt | `"row-embeddings"`'ı `request_response_dispatchers`'e `manager.py` içinde ekleyin | + +Akış arayüz adı: `row-embeddings` + +Akış şablonundaki arayüz tanımı: +```json +{ + "interfaces": { + "row-embeddings": { + "request": "non-persistent://tg/request/row-embeddings:{id}", + "response": "non-persistent://tg/response/row-embeddings:{id}" + } + } +} +``` + +#### Python SDK Desteği + +SDK, satır gömme sorguları için yöntemler sağlar: + +```python +# Flow-scoped query (preferred) +api = Api(url) +flow = api.flow().id("default") + +# Query with text (SDK computes embeddings) +matches = flow.row_embeddings_query( + text="Chestnut Street", + collection="my_collection", + schema_name="addresses", + index_name="street_name", # Optional filter + limit=10 +) + +# Query with pre-computed vectors +matches = flow.row_embeddings_query( + vectors=[[0.1, 0.2, ...]], + collection="my_collection", + schema_name="addresses" +) + +# Each match contains: +for match in matches: + print(match.index_name) # e.g., "street_name" + print(match.index_value) # e.g., ["CHESTNUT ST"] + print(match.text) # e.g., "CHESTNUT ST" + print(match.score) # e.g., 0.95 +``` + +#### CLI Yardımcı Programı + +Komut: `tg-invoke-row-embeddings` + +```bash +# Query by text (computes embedding automatically) +tg-invoke-row-embeddings \ + --text "Chestnut Street" \ + --collection my_collection \ + --schema addresses \ + --index street_name \ + --limit 10 + +# Query by vector file +tg-invoke-row-embeddings \ + --vectors vectors.json \ + --collection my_collection \ + --schema addresses + +# Output formats +tg-invoke-row-embeddings --text "..." --format json +tg-invoke-row-embeddings --text "..." --format table +``` + +#### Tipik Kullanım Şekli + +Satır gömme sorgusu genellikle bulanık aramadan kesin aramaya geçiş akışının bir parçası olarak kullanılır: + +```python +# Step 1: Fuzzy search via embeddings +matches = flow.row_embeddings_query( + text="chestnut street", + collection="geo", + schema_name="streets" +) + +# Step 2: Exact lookup via GraphQL for full row data +for match in matches: + query = f''' + query {{ + streets(where: {{ {match.index_name}: {{ eq: "{match.index_value[0]}" }} }}) {{ + street_name + city + zip_code + }} + }} + ''' + rows = flow.rows_query(query, collection="geo") +``` + +Bu iki aşamalı yapı şu olanakları sağlar: +Kullanıcı "Chestnut Street" araması yaptığında "CHESTNUT ST" ifadesinin bulunması +Tüm alanlarıyla birlikte eksiksiz satır verilerinin alınması +Anlamsal benzerliği yapılandırılmış veri erişimiyle birleştirme + +### Satır Veri Alımı + +Daha sonraki bir aşamaya ertelenmiştir. Diğer veri alım değişiklikleriyle birlikte tasarlanacaktır. + +## Uygulama Etkisi + +### Mevcut Durum Analizi + +Mevcut uygulama iki ana bileşenden oluşmaktadır: + +| Bileşen | Konum | Satır Sayısı | Açıklama | +|-----------|----------|-------|-------------| +| Sorgu Servisi | `trustgraph-flow/trustgraph/query/objects/cassandra/service.py` | ~740 | Tek bir blok: GraphQL şema oluşturma, filtre ayrıştırma, Cassandra sorguları, istek işleme | +| Yazıcı | `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` | ~540 | Şema başına tablo oluşturma, ikincil indeksler, ekleme/silme | + +**Mevcut Sorgu Modeli:** +```sql +SELECT * FROM {keyspace}.o_{schema_name} +WHERE collection = 'X' AND email = 'foo@bar.com' +ALLOW FILTERING +``` + +**Yeni Sorgu Deseni:** +```sql +SELECT * FROM {keyspace}.rows +WHERE collection = 'X' AND schema_name = 'customers' + AND index_name = 'email' AND index_value = ['foo@bar.com'] +``` + +### Önemli Değişiklikler + +1. **Sorgu anlamları basitleştirildi**: Yeni şema, yalnızca `index_value` üzerindeki tam eşleşmeleri desteklemektedir. Mevcut GraphQL filtreleri (`gt`, `lt`, `contains`, vb.): + Gerekliyse, döndürülen veriler üzerinde arka filtreleme olarak kullanılır. + Bulanık eşleştirme için gömülü API'nin kullanılması lehine kaldırılır. + +2. **GraphQL kodu sıkı bir şekilde birleştirilmiş durumda**: Mevcut `service.py`, Strawberry türü oluşturma, filtre ayrıştırma ve Cassandra'ya özgü sorguları bir araya getirmektedir. Başka bir satır depolama arka ucunun eklenmesi, yaklaşık 400 satır GraphQL kodunun çoğaltılmasına neden olacaktır. + +### Önerilen Yeniden Düzenleme + +Yeniden düzenleme iki bölümden oluşmaktadır: + +#### 1. GraphQL Kodunu Ayırmak + +Yeniden kullanılabilir GraphQL bileşenlerini, paylaşılan bir modüle çıkarın: + +``` +trustgraph-flow/trustgraph/query/graphql/ +├── __init__.py +├── types.py # Filter types (IntFilter, StringFilter, FloatFilter) +├── schema.py # Dynamic schema generation from RowSchema +└── filters.py # Filter parsing utilities +``` + +Bu, şunları sağlar: +Farklı satır depolama arka uçlarında yeniden kullanılabilirlik +Daha temiz bir sorumluluk ayrımı +GraphQL mantığının bağımsız olarak daha kolay test edilebilmesi + +#### 2. Yeni Tablo Şemasını Uygulayın + +Cassandra'ya özgü kodu, birleşik tabloyu kullanacak şekilde yeniden düzenleyin: + +**Yazıcı** (`trustgraph-flow/trustgraph/storage/rows/cassandra/`): +Her şema için ayrı tablolar yerine tek bir `rows` tablosu +Her satır için N kopyası yazın (her indeks için bir tane) +`row_partitions` tablosuna kaydolun +Daha basit tablo oluşturma (tek seferlik kurulum) + +**Sorgu Hizmeti** (`trustgraph-flow/trustgraph/query/rows/cassandra/`): +Birleşik `rows` tablosunu sorgulayın +Şema oluşturma için çıkarılan GraphQL modülünü kullanın +Basitleştirilmiş filtre işleme (yalnızca veritabanı düzeyinde tam eşleşme) + +### Modül Yeniden Adlandırmaları + +"nesne" → "satır" adlandırma temizliği kapsamında: + +| Mevcut | Yeni | +|---------|-----| +| `storage/objects/cassandra/` | `storage/rows/cassandra/` | +| `query/objects/cassandra/` | `query/rows/cassandra/` | +| `embeddings/object_embeddings/` | `embeddings/row_embeddings/` | + +### Yeni Modüller + +| Modül | Amaç | +|--------|---------| +| `trustgraph-flow/trustgraph/query/graphql/` | Paylaşılan GraphQL yardımcı programları | +| `trustgraph-flow/trustgraph/query/row_embeddings/qdrant/` | Satır gömme sorgu API'si | +| `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | Satır gömme hesaplama (1. Aşama) | +| `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | Satır gömme depolama (2. Aşama) | + +## Referanslar + +[Yapılandırılmış Veri Teknik Özellikleri](structured-data.md) diff --git a/docs/tech-specs/structured-data-2.zh-cn.md b/docs/tech-specs/structured-data-2.zh-cn.md new file mode 100644 index 00000000..71d42cc5 --- /dev/null +++ b/docs/tech-specs/structured-data-2.zh-cn.md @@ -0,0 +1,613 @@ +# 结构化数据技术规范 (第二部分) + +## 概述 + +本规范解决了在 TrustGraph 结构化数据集成初始实施过程中发现的问题和差距,如 `structured-data.md` 中所述。 + +## 问题陈述 + +### 1. 命名不一致:"对象" 与 "行" + +当前实现方案在整个代码中使用 "对象" 术语 (例如,`ExtractedObject`,对象提取,对象嵌入)。 这种命名方式过于通用,容易造成混淆: + +"对象" 在软件中是一个 overloaded 的术语 (Python 对象,JSON 对象等)。 +正在处理的数据本质上是表格数据,即具有定义模式的表格中的行。 +"行" 更准确地描述了数据模型,并且与数据库术语一致。 + +这种不一致性出现在模块名称、类名称、消息类型和文档中。 + +### 2. 行存储查询限制 + +当前的行存储实现方案存在重大的查询限制: + +**自然语言匹配问题**: 查询难以处理真实世界数据的变化。 例如: +很难在包含 `"CHESTNUT ST"` 的街道数据库中找到关于 `"Chestnut Street"` 的信息。 +缩写、大小写差异和格式变化会破坏精确匹配查询。 +用户期望语义理解,但存储系统只提供字面匹配。 + +**模式演化问题**: 更改模式会导致问题: +现有数据可能不符合更新后的模式。 +表结构的变化可能会破坏查询和数据完整性。 +没有明确的模式更新迁移路径。 + +### 3. 需要行嵌入 + +与问题 2 相关,系统需要行数据的向量嵌入,以便: + +在结构化数据上进行语义搜索 (找到 "Chestnut Street" 时,数据包含 "CHESTNUT ST")。 +模糊查询的相似性匹配。 +结合结构化过滤器和语义相似性的混合搜索。 +更好的自然语言查询支持。 + +嵌入服务已指定,但尚未实施。 + +### 4. 行数据摄取不完整 + +结构化数据摄取管道尚未完全投入使用: + +存在诊断提示,用于对输入格式进行分类 (CSV,JSON 等)。 +使用这些提示的摄取服务尚未集成到系统中。 +没有将预结构化数据加载到行存储的端到端路径。 + +## 目标 + +**模式灵活性**: 允许模式演化,而不会破坏现有数据或需要迁移。 +**命名一致性**: 在整个代码库中采用 "行" 术语。 +**语义可查询性**: 通过行嵌入支持模糊/语义匹配。 +**完整的摄取管道**: 提供将结构化数据加载到存储的端到端路径。 + +## 技术设计 + +### 统一的行存储模式 + +之前的实现方案为每个模式创建了一个单独的 Cassandra 表。 这在模式演化时会导致问题,因为表结构的变化需要迁移。 + +新的设计使用一个统一的表来存储所有行数据: + +```sql +CREATE TABLE rows ( + collection text, + schema_name text, + index_name text, + index_value frozen>, + data map, + source text, + PRIMARY KEY ((collection, schema_name, index_name), index_value) +) +``` + +#### 列定义 + +| 列 | 类型 | 描述 | +|--------|------|-------------| +| `collection` | `text` | 数据收集/导入标识符(来自元数据)| +| `schema_name` | `text` | 此行所遵循的模式名称 | +| `index_name` | `text` | 索引字段名称,以逗号分隔的字符串表示复合索引 | +| `index_value` | `frozen>` | 索引值列表 | +| `data` | `map` | 行数据,以键值对形式存储 | +| `source` | `text` | 可选的 URI,链接到知识图谱中的来源信息。空字符串或 NULL 表示没有来源。| + +#### 索引处理 + +每行数据会被存储多次,对于模式中定义的每个索引字段,都会存储一次。主键字段被视为索引,没有特殊的标记,以提供未来的灵活性。 + +**单字段索引示例:** +模式定义 `email` 为索引 +`index_name = "email"` +`index_value = ['foo@bar.com']` + +**复合索引示例:** +模式定义在 `region` 和 `status` 上创建复合索引 +`index_name = "region,status"` (字段名称按排序方式连接) +`index_value = ['US', 'active']` (值与字段名称的顺序相同) + +**主键示例:** +模式定义 `customer_id` 为主键 +`index_name = "customer_id"` +`index_value = ['CUST001']` + +#### 查询模式 + +无论使用哪个索引,所有查询都遵循相同的模式: + +```sql +SELECT * FROM rows +WHERE collection = 'import_2024' + AND schema_name = 'customers' + AND index_name = 'email' + AND index_value = ['foo@bar.com'] +``` + +#### 设计权衡 + +**优点:** +模式更改不需要更改表结构 +行数据对 Cassandra 隐藏 - 字段的添加/删除是透明的 +所有访问方法都具有一致的查询模式 +不需要 Cassandra 的二级索引(这在大型环境中可能会很慢) +整个过程中都使用 Cassandra 的原生类型(`map`,`frozen`) + +**权衡:** +写入放大:每个行插入 = N 次插入(每个索引字段一次) +重复行数据带来的存储开销 +类型信息存储在模式配置中,应用程序层进行转换 + +#### 一致性模型 + +该设计接受某些简化: + +1. **没有行更新**:系统是只追加的。这消除了关于更新同一行的多个副本的一致性问题。 + +2. **模式更改容错性**:当模式发生更改(例如,添加/删除索引)时,现有行保留其原始索引。旧行将无法通过新索引发现。如果需要,用户可以删除并重新创建模式以确保一致性。 + +### 分区跟踪和删除 + +#### 问题 + +借助分区键 `(collection, schema_name, index_name)`,高效删除需要知道所有要删除的分区键。仅通过 `collection` 或 `collection + schema_name` 删除需要知道所有具有数据的 `index_name` 值。 + +#### 分区跟踪表 + +一个辅助查找表跟踪哪些分区存在: + +```sql +CREATE TABLE row_partitions ( + collection text, + schema_name text, + index_name text, + PRIMARY KEY ((collection), schema_name, index_name) +) +``` + +这使得能够高效地发现用于删除操作的分区。 + +#### 行写入器行为 + +行写入器维护一个已注册的 `(collection, schema_name)` 对的内存缓存。 在处理一行时: + +1. 检查 `(collection, schema_name)` 是否在缓存中 +2. 如果未缓存(对于此对的第一个行): + 查找模式配置以获取所有索引名称 + 将条目插入到 `row_partitions` 中,对于每个 `(collection, schema_name, index_name)` + 将该对添加到缓存中 +3. 继续写入行数据 + +行写入器还监视模式配置更改事件。 当模式发生更改时,相关的缓存条目将被清除,以便下一行触发使用更新的索引名称重新注册。 + +这种方法确保: +查找表写入仅针对每个 `(collection, schema_name)` 对发生一次,而不是针对每行。 +查找表反映了数据写入时活动的索引。 +导入过程中发生的模式更改可以正确处理。 + +#### 删除操作 + +**删除集合:** +```sql +-- 1. Discover all partitions +SELECT schema_name, index_name FROM row_partitions WHERE collection = 'X'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = '...' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table +DELETE FROM row_partitions WHERE collection = 'X'; +``` + +**删除集合 + 模式:** +```sql +-- 1. Discover partitions for this schema +SELECT index_name FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; + +-- 2. Delete each partition from rows table +DELETE FROM rows WHERE collection = 'X' AND schema_name = 'Y' AND index_name = '...'; +-- (repeat for each discovered partition) + +-- 3. Clean up the lookup table entries +DELETE FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y'; +``` + +### 行嵌入 + +行嵌入允许对索引值进行语义/模糊匹配,从而解决自然语言不匹配的问题(例如,在搜索“Chestnut Street”时找到“CHESTNUT ST”)。 + +#### 设计概述 + +每个索引值都会被嵌入,并存储在向量存储中(Qdrant)。在查询时,查询内容也会被嵌入,找到相似的向量,然后使用相关的元数据来查找 Cassandra 中的实际行。 + +#### Qdrant 集合结构 + +每个 `(user, collection, schema_name, dimension)` 元组对应一个 Qdrant 集合: + +**集合命名:** `rows_{user}_{collection}_{schema_name}_{dimension}` +名称会被清理(非字母数字字符替换为 `_`,转换为小写,数字前缀添加 `r_` 前缀) +**理由:** 允许通过删除匹配的 Qdrant 集合来干净地删除一个 `(user, collection, schema_name)` 实例;维度后缀允许不同的嵌入模型共存。 + +#### 哪些内容会被嵌入 + +索引值的文本表示: + +| 索引类型 | 示例 `index_value` | 要嵌入的文本 | +|------------|----------------------|---------------| +| 单字段 | `['foo@bar.com']` | `"foo@bar.com"` | +| 组合 | `['US', 'active']` | `"US active"` (空格连接) | + +#### 点结构 + +每个 Qdrant 点包含: + +```json +{ + "id": "", + "vector": [0.1, 0.2, ...], + "payload": { + "index_name": "street_name", + "index_value": ["CHESTNUT ST"], + "text": "CHESTNUT ST" + } +} +``` + +| Payload Field | Description | +|---------------|-------------| +| `index_name` | 此嵌入所代表的索引字段。| +| `index_value` | 原始值列表(用于 Cassandra 查找)。| +| `text` | 嵌入的文本(用于调试/显示)。| + +注意:`user`、`collection` 和 `schema_name` 可以从 Qdrant 集合名称中推断出来。| + +#### 查询流程 + +1. 用户查询用户 U、集合 X、模式 Y 中的“Chestnut Street”。| +2. 嵌入查询文本。| +3. 确定与前缀 `rows_U_X_Y_` 匹配的 Qdrant 集合名称。| +4. 在匹配的 Qdrant 集合中搜索最接近的向量。| +5. 获取包含 `index_name` 和 `index_value` 的有效负载的匹配点。| +6. 查询 Cassandra:| + ```sql + SELECT * FROM rows + WHERE collection = 'X' + AND schema_name = 'Y' + AND index_name = '' + AND index_value = + ``` +7. 返回匹配的行 + +#### 可选:按索引名称过滤 + +查询可以选择性地按 `index_name` 进行过滤,以便在 Qdrant 中仅搜索特定字段: + +**"查找所有匹配 'Chestnut' 的字段"** → 搜索集合中的所有向量 +**"查找 'Chestnut' 匹配的 street_name"** → 过滤 `payload.index_name = 'street_name'` + +#### 架构 + +行嵌入遵循 GraphRAG 使用的 **两阶段模式**(图嵌入、文档嵌入): + +**第一阶段:嵌入计算** (`trustgraph-flow/trustgraph/embeddings/row_embeddings/`) - 消耗 `ExtractedObject`,通过嵌入服务计算嵌入,输出 `RowEmbeddings` +**第二阶段:嵌入存储** (`trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/`) - 消耗 `RowEmbeddings`,将向量写入 Qdrant + +Cassandra 行写入器是一个独立的并行消费者: + +**Cassandra 行写入器** (`trustgraph-flow/trustgraph/storage/rows/cassandra`) - 消耗 `ExtractedObject`,将行写入 Cassandra + +所有三个服务都从同一个流中读取,从而使它们彼此解耦。 这允许: +独立地扩展 Cassandra 写入与嵌入生成与向量存储 +如果不需要,可以禁用嵌入服务 +一个服务中的故障不会影响其他服务 +与 GraphRAG 管道保持一致的架构 + +#### 写入路径 + +**第一阶段(行嵌入处理器):** 接收到 `ExtractedObject` 时: + +1. 查找模式以找到索引字段 +2. 对于每个索引字段: + 构建索引值的文本表示 + 通过嵌入服务计算嵌入 +3. 输出一个包含所有计算向量的 `RowEmbeddings` 消息 + +**第二阶段(行嵌入-写入-Qdrant):** 接收到 `RowEmbeddings` 时: + +1. 对于消息中的每个嵌入: + 从 `(user, collection, schema_name, dimension)` 确定 Qdrant 集合 + 如果需要,创建集合(首次写入时延迟创建) + 使用向量和有效载荷进行更新 + +#### 消息类型 + +```python +@dataclass +class RowIndexEmbedding: + index_name: str # The indexed field name(s) + index_value: list[str] # The field value(s) + text: str # Text that was embedded + vectors: list[list[float]] # Computed embedding vectors + +@dataclass +class RowEmbeddings: + metadata: Metadata + schema_name: str + embeddings: list[RowIndexEmbedding] +``` + +#### 删除集成 + +Qdrant 集合通过在集合名称模式上进行前缀匹配来发现: + +**删除 `(user, collection)`:** +1. 列出所有与前缀 `rows_{user}_{collection}_` 匹配的 Qdrant 集合 +2. 删除每个匹配的集合 +3. 删除 Cassandra 行分区(如上文所述) +4. 清理 `row_partitions` 条目 + +**删除 `(user, collection, schema_name)`:** +1. 列出所有与前缀 `rows_{user}_{collection}_{schema_name}_` 匹配的 Qdrant 集合 +2. 删除每个匹配的集合(处理多个维度) +3. 删除 Cassandra 行分区 +4. 清理 `row_partitions` + +#### 模块位置 + +| 阶段 | 模块 | 入口点 | +|-------|--------|-------------| +| 阶段 1 | `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | `row-embeddings` | +| 阶段 2 | `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | `row-embeddings-write-qdrant` | + +### 行嵌入查询 API + +行嵌入查询是与 GraphQL 行查询服务**不同的 API**: + +| API | 目的 | 后端 | +|-----|---------|---------| +| 行查询 (GraphQL) | 对索引字段进行精确匹配 | Cassandra | +| 行嵌入查询 | 模糊/语义匹配 | Qdrant | + +这种分离保持了关注点的清晰: +GraphQL 服务专注于精确、结构化的查询 +嵌入 API 处理语义相似性 +用户工作流程:通过嵌入进行模糊搜索以查找候选对象,然后进行精确查询以获取完整的行数据 + +#### 请求/响应模式 + +```python +@dataclass +class RowEmbeddingsRequest: + vectors: list[list[float]] # Query vectors (pre-computed embeddings) + user: str = "" + collection: str = "" + schema_name: str = "" + index_name: str = "" # Optional: filter to specific index + limit: int = 10 # Max results per vector + +@dataclass +class RowIndexMatch: + index_name: str = "" # The matched index field(s) + index_value: list[str] = [] # The matched value(s) + text: str = "" # Original text that was embedded + score: float = 0.0 # Similarity score + +@dataclass +class RowEmbeddingsResponse: + error: Error | None = None + matches: list[RowIndexMatch] = [] +``` + +#### 查询处理器 + +模块:`trustgraph-flow/trustgraph/query/row_embeddings/qdrant` + +入口点:`row-embeddings-query-qdrant` + +处理器: +1. 接收带有查询向量的 `RowEmbeddingsRequest` +2. 通过前缀匹配找到合适的 Qdrant 集合 +3. 搜索最近的向量,并可选择使用 `index_name` 过滤器 +4. 返回包含匹配索引信息的 `RowEmbeddingsResponse` + +#### API 网关集成 + +网关通过标准的请求/响应模式公开行嵌入查询: + +| 组件 | 位置 | +|-----------|----------| +| 调度器 | `trustgraph-flow/trustgraph/gateway/dispatch/row_embeddings_query.py` | +| 注册 | 将 `"row-embeddings"` 添加到 `request_response_dispatchers` 中,位于 `manager.py` | + +流程接口名称:`row-embeddings` + +流程蓝图中的接口定义: +```json +{ + "interfaces": { + "row-embeddings": { + "request": "non-persistent://tg/request/row-embeddings:{id}", + "response": "non-persistent://tg/response/row-embeddings:{id}" + } + } +} +``` + +#### Python SDK 支持 + +SDK 提供了用于行嵌入查询的方法: + +```python +# Flow-scoped query (preferred) +api = Api(url) +flow = api.flow().id("default") + +# Query with text (SDK computes embeddings) +matches = flow.row_embeddings_query( + text="Chestnut Street", + collection="my_collection", + schema_name="addresses", + index_name="street_name", # Optional filter + limit=10 +) + +# Query with pre-computed vectors +matches = flow.row_embeddings_query( + vectors=[[0.1, 0.2, ...]], + collection="my_collection", + schema_name="addresses" +) + +# Each match contains: +for match in matches: + print(match.index_name) # e.g., "street_name" + print(match.index_value) # e.g., ["CHESTNUT ST"] + print(match.text) # e.g., "CHESTNUT ST" + print(match.score) # e.g., 0.95 +``` + +#### 命令行工具 + +命令:`tg-invoke-row-embeddings` + +```bash +# Query by text (computes embedding automatically) +tg-invoke-row-embeddings \ + --text "Chestnut Street" \ + --collection my_collection \ + --schema addresses \ + --index street_name \ + --limit 10 + +# Query by vector file +tg-invoke-row-embeddings \ + --vectors vectors.json \ + --collection my_collection \ + --schema addresses + +# Output formats +tg-invoke-row-embeddings --text "..." --format json +tg-invoke-row-embeddings --text "..." --format table +``` + +#### 典型用法示例 + +行嵌入查询通常用作模糊到精确查找流程的一部分: + +```python +# Step 1: Fuzzy search via embeddings +matches = flow.row_embeddings_query( + text="chestnut street", + collection="geo", + schema_name="streets" +) + +# Step 2: Exact lookup via GraphQL for full row data +for match in matches: + query = f''' + query {{ + streets(where: {{ {match.index_name}: {{ eq: "{match.index_value[0]}" }} }}) {{ + street_name + city + zip_code + }} + }} + ''' + rows = flow.rows_query(query, collection="geo") +``` + +这种两步模式可以实现: +当用户搜索 "Chestnut Street" 时,找到 "CHESTNUT ST" +检索包含所有字段的完整行数据 +结合语义相似性和结构化数据访问 + +### 行数据导入 + +暂定于后续阶段。将与其他导入更改一起设计。 + +## 实施影响 + +### 当前状态分析 + +现有的实现包含两个主要组件: + +| 组件 | 位置 | 行数 | 描述 | +|-----------|----------|-------|-------------| +| 查询服务 | `trustgraph-flow/trustgraph/query/objects/cassandra/service.py` | ~740 | 整体式:GraphQL 模式生成、过滤器解析、Cassandra 查询、请求处理 | +| 写入器 | `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` | ~540 | 每个模式的表创建、二级索引、插入/删除 | + +**当前的查询模式:** +```sql +SELECT * FROM {keyspace}.o_{schema_name} +WHERE collection = 'X' AND email = 'foo@bar.com' +ALLOW FILTERING +``` + +**新的查询模式:** +```sql +SELECT * FROM {keyspace}.rows +WHERE collection = 'X' AND schema_name = 'customers' + AND index_name = 'email' AND index_value = ['foo@bar.com'] +``` + +### 关键变更 + +1. **查询语义简化:** 新的模式仅支持对 `index_value` 的精确匹配。当前的 GraphQL 过滤器(`gt`、`lt`、`contains` 等)要么: + 变为对返回数据的后过滤(如果仍然需要) + 被移除,转而使用嵌入 API 进行模糊匹配 + +2. **GraphQL 代码紧密耦合:** 当前的 `service.py` 包含了 Strawberry 类型生成、过滤器解析以及 Cassandra 相关的查询。添加另一个行存储后端会重复大约 400 行的 GraphQL 代码。 + +### 提出的重构 + +重构分为两部分: + +#### 1. 提取 GraphQL 代码 + +将可重用的 GraphQL 组件提取到共享模块中: + +``` +trustgraph-flow/trustgraph/query/graphql/ +├── __init__.py +├── types.py # Filter types (IntFilter, StringFilter, FloatFilter) +├── schema.py # Dynamic schema generation from RowSchema +└── filters.py # Filter parsing utilities +``` + +这实现了: +在不同的行存储后端中实现重用 +更清晰的分层 +更容易独立地测试 GraphQL 逻辑 + +#### 2. 实现新的表模式 + +重构特定于 Cassandra 的代码,以使用统一的表: + +**写入器 (Writer)** (`trustgraph-flow/trustgraph/storage/rows/cassandra/`): +使用单个 `rows` 表,而不是每个模式的表 +写入 N 个副本到每行(每个索引一个) +注册到 `row_partitions` 表 +更简单的表创建(一次性设置) + +**查询服务 (Query Service)** (`trustgraph-flow/trustgraph/query/rows/cassandra/`): +查询统一的 `rows` 表 +使用提取的 GraphQL 模块进行模式生成 +简化的过滤处理(仅在数据库级别进行精确匹配) + +### 模块重命名 + +作为“object”→“row”命名清理的一部分: + +| 当前 (Current) | 新 (New) | +|---------|-----| +| `storage/objects/cassandra/` | `storage/rows/cassandra/` | +| `query/objects/cassandra/` | `query/rows/cassandra/` | +| `embeddings/object_embeddings/` | `embeddings/row_embeddings/` | + +### 新模块 + +| 模块 (Module) | 目的 (Purpose) | +|--------|---------| +| `trustgraph-flow/trustgraph/query/graphql/` | 共享 GraphQL 工具 +| `trustgraph-flow/trustgraph/query/row_embeddings/qdrant/` | 行嵌入查询 API +| `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | 行嵌入计算(第一阶段) +| `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | 行嵌入存储(第二阶段) + +## 引用 + +[结构化数据技术规范](structured-data.md) diff --git a/docs/tech-specs/structured-data-descriptor.ar.md b/docs/tech-specs/structured-data-descriptor.ar.md new file mode 100644 index 00000000..1d06bc03 --- /dev/null +++ b/docs/tech-specs/structured-data-descriptor.ar.md @@ -0,0 +1,559 @@ +# مواصفات محدد البيانات المنظمة + +## نظرة عامة + +محدد البيانات المنظمة هو لغة تكوين تعتمد على JSON تصف كيفية تحليل وتحويل واستيراد البيانات المنظمة إلى TrustGraph. يوفر نهجًا تصريحيًا لاستيعاب البيانات، مما يدعم تنسيقات إدخال متعددة وقنوات تحويل معقدة دون الحاجة إلى تعليمات برمجية مخصصة. + +## المفاهيم الأساسية + +### 1. تعريف التنسيق +يصف نوع ملف الإدخال وخيارات التحليل. يحدد أي محلل لاستخدامه وكيفية تفسير البيانات المصدر. + +### 2. تعيينات الحقول +يربط مسارات المصدر بحقول الهدف مع التحويلات. يحدد كيفية تدفق البيانات من مصادر الإدخال إلى حقول مخطط الإخراج. + +### 3. سلسلة التحويل +سلسلة من تحويلات البيانات التي يمكن تطبيقها على قيم الحقول، بما في ذلك: +تنظيف البيانات (التقليم، التسوية) +تحويل التنسيق (تحليل التاريخ، تحويل النوع) +العمليات الحسابية (العمليات الحسابية، معالجة السلاسل) +عمليات البحث (جداول مرجعية، استبدالات) + +### 4. قواعد التحقق من الصحة +عمليات فحص جودة البيانات المطبقة لضمان سلامة البيانات: +التحقق من النوع +عمليات التحقق من النطاق +مطابقة الأنماط (regex) +التحقق من صحة الحقول المطلوبة +منطق التحقق المخصص + +### 5. الإعدادات العامة +التكوين الذي ينطبق على عملية الاستيراد بأكملها: +جداول البحث لإثراء البيانات +المتغيرات والثوابت العامة +مواصفات تنسيق الإخراج +سياسات معالجة الأخطاء + +## استراتيجية التنفيذ + +يتبع تطبيق المستورد هذا المسار: + +1. **تحليل التكوين** - تحميل والتحقق من صحة الوصف JSON +2. **تهيئة المحلل** - تحميل المحلل المناسب (CSV، XML، JSON، إلخ) بناءً على `format.type` +3. **تطبيق المعالجة المسبقة** - تنفيذ المرشحات والتحويلات العامة +4. **معالجة السجلات** - لكل سجل إدخال: + استخراج البيانات باستخدام مسارات المصدر (JSONPath، XPath، أسماء الأعمدة) + تطبيق التحويلات الخاصة بالحقل بالتسلسل + التحقق من صحة النتائج مقابل القواعد المحددة + تطبيق القيم الافتراضية للبيانات المفقودة +5. **تطبيق المعالجة اللاحقة** - تنفيذ إزالة التكرار، التجميع، إلخ. +6. **إنشاء الإخراج** - إنتاج البيانات بالتنسيق المستهدف المحدد + +## دعم تعبيرات المسار + +تستخدم تنسيقات الإدخال المختلفة لغات تعبيرات المسار المناسبة: + +**CSV**: أسماء الأعمدة أو الفهارس (`"column_name"` أو `"[2]"`) +**JSON**: بناء جملة JSONPath (`"$.user.profile.email"`) +**XML**: تعبيرات XPath (`"//product[@id='123']/price"`) +**العرض الثابت**: أسماء الحقول من تعريفات الحقول + +## المزايا + +**قاعدة تعليمات برمجية واحدة** - يقوم مستورد واحد بمعالجة تنسيقات إدخال متعددة +**سهل الاستخدام** - يمكن للمستخدمين غير التقنيين إنشاء تكوينات +**قابلة لإعادة الاستخدام** - يمكن مشاركة التكوينات وتنسيق الإصدارات +**مرنة** - تحويلات معقدة بدون ترميز مخصص +**قوية** - تحقق مدمج ومعالجة شاملة للأخطاء +**قابلة للصيانة** - يوفر النهج التصريحي تقليل تعقيد التنفيذ + +## مواصفات اللغة + +يستخدم محدد البيانات المنظمة تنسيق تكوين JSON مع البنية العامة التالية: + +```json +{ + "version": "1.0", + "metadata": { + "name": "Configuration Name", + "description": "Description of what this config does", + "author": "Author Name", + "created": "2024-01-01T00:00:00Z" + }, + "format": { ... }, + "globals": { ... }, + "preprocessing": [ ... ], + "mappings": [ ... ], + "postprocessing": [ ... ], + "output": { ... } +} +``` + +### تعريف التنسيق + +يصف تنسيق البيانات المدخلة وخيارات التحليل: + +```json +{ + "format": { + "type": "csv|json|xml|fixed-width|excel|parquet", + "encoding": "utf-8", + "options": { + // Format-specific options + } + } +} +``` + +### خيارات تنسيق CSV +```json +{ + "format": { + "type": "csv", + "options": { + "delimiter": ",", + "quote_char": "\"", + "escape_char": "\\", + "skip_rows": 1, + "has_header": true, + "null_values": ["", "NULL", "null", "N/A"] + } + } +} +``` + +#### خيارات تنسيق JSON +```json +{ + "format": { + "type": "json", + "options": { + "root_path": "$.data", + "array_mode": "records|single", + "flatten": false + } + } +} +``` + +#### خيارات تنسيق XML +```json +{ + "format": { + "type": "xml", + "options": { + "root_element": "//records/record", + "namespaces": { + "ns": "http://example.com/namespace" + } + } + } +} +``` + +### الإعدادات العامة + +تحديد الجداول المرجعية والمتغيرات والتكوين العام: + +```json +{ + "globals": { + "variables": { + "current_date": "2024-01-01", + "batch_id": "BATCH_001", + "default_confidence": 0.8 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "UK": "United Kingdom", + "CA": "Canada" + }, + "status_mapping": { + "1": "active", + "0": "inactive" + } + }, + "constants": { + "source_system": "legacy_crm", + "import_type": "full" + } + } +} +``` + +### تعيينات الحقول + +حدد كيفية تعيين البيانات المصدر إلى الحقول المستهدفة مع التحويلات: + +```json +{ + "mappings": [ + { + "target_field": "person_name", + "source": "$.name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"}, + {"type": "required"} + ], + "validation": [ + {"type": "min_length", "value": 2}, + {"type": "max_length", "value": 100}, + {"type": "pattern", "value": "^[A-Za-z\\s]+$"} + ] + }, + { + "target_field": "age", + "source": "$.age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 150} + ] + }, + { + "target_field": "country", + "source": "$.country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ] +} +``` + +### أنواع التحويل + +الوظائف المتاحة للتحويل: + +#### تحويلات السلاسل النصية +```json +{"type": "trim"}, +{"type": "upper"}, +{"type": "lower"}, +{"type": "title_case"}, +{"type": "replace", "pattern": "old", "replacement": "new"}, +{"type": "regex_replace", "pattern": "\\d+", "replacement": "XXX"}, +{"type": "substring", "start": 0, "end": 10}, +{"type": "pad_left", "length": 10, "char": "0"} +``` + +#### تحويلات الأنواع +```json +{"type": "to_string"}, +{"type": "to_int"}, +{"type": "to_float"}, +{"type": "to_bool"}, +{"type": "to_date", "format": "YYYY-MM-DD"}, +{"type": "parse_json"} +``` + +#### العمليات على البيانات +```json +{"type": "default", "value": "default_value"}, +{"type": "lookup", "table": "table_name"}, +{"type": "concat", "values": ["field1", " - ", "field2"]}, +{"type": "calculate", "expression": "${field1} + ${field2}"}, +{"type": "conditional", "condition": "${age} > 18", "true_value": "adult", "false_value": "minor"} +``` + +### قواعد التحقق + +عمليات فحص جودة البيانات مع معالجة أخطاء قابلة للتكوين: + +#### عمليات التحقق الأساسية +```json +{"type": "required"}, +{"type": "not_null"}, +{"type": "min_length", "value": 5}, +{"type": "max_length", "value": 100}, +{"type": "range", "min": 0, "max": 1000}, +{"type": "pattern", "value": "^[A-Z]{2,3}$"}, +{"type": "in_list", "values": ["active", "inactive", "pending"]} +``` + +#### التحقق من الصحة المخصصة +```json +{ + "type": "custom", + "expression": "${age} >= 18 && ${country} == 'US'", + "message": "Must be 18+ and in US" +}, +{ + "type": "cross_field", + "fields": ["start_date", "end_date"], + "expression": "${start_date} < ${end_date}", + "message": "Start date must be before end date" +} +``` + +### المعالجة الأولية والمعالجة اللاحقة + +العمليات العامة المطبقة قبل/بعد تعيين الحقول: + +```json +{ + "preprocessing": [ + { + "type": "filter", + "condition": "${status} != 'deleted'" + }, + { + "type": "sort", + "field": "created_date", + "order": "asc" + } + ], + "postprocessing": [ + { + "type": "deduplicate", + "key_fields": ["email", "phone"] + }, + { + "type": "aggregate", + "group_by": ["country"], + "functions": { + "total_count": {"type": "count"}, + "avg_age": {"type": "avg", "field": "age"} + } + } + ] +} +``` + +### إعدادات الإخراج + +حدد كيفية إخراج البيانات المعالجة: + +```json +{ + "output": { + "format": "trustgraph-objects", + "schema_name": "person", + "options": { + "batch_size": 1000, + "confidence": 0.9, + "source_span_field": "raw_text", + "metadata": { + "source": "crm_import", + "version": "1.0" + } + }, + "error_handling": { + "on_validation_error": "skip|fail|log", + "on_transform_error": "skip|fail|default", + "max_errors": 100, + "error_output": "errors.json" + } + } +} +``` + +## مثال كامل + +```json +{ + "version": "1.0", + "metadata": { + "name": "Customer Import from CRM CSV", + "description": "Imports customer data from legacy CRM system", + "author": "Data Team", + "created": "2024-01-01T00:00:00Z" + }, + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true, + "skip_rows": 1 + } + }, + "globals": { + "variables": { + "import_date": "2024-01-01", + "default_confidence": 0.85 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "CA": "Canada", + "UK": "United Kingdom" + } + } + }, + "preprocessing": [ + { + "type": "filter", + "condition": "${status} == 'active'" + } + ], + "mappings": [ + { + "target_field": "full_name", + "source": "customer_name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"} + ], + "validation": [ + {"type": "required"}, + {"type": "min_length", "value": 2} + ] + }, + { + "target_field": "email", + "source": "email_address", + "transforms": [ + {"type": "trim"}, + {"type": "lower"} + ], + "validation": [ + {"type": "pattern", "value": "^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$"} + ] + }, + { + "target_field": "age", + "source": "age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 120} + ] + }, + { + "target_field": "country", + "source": "country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ], + "output": { + "format": "trustgraph-objects", + "schema_name": "customer", + "options": { + "confidence": "${default_confidence}", + "batch_size": 500 + }, + "error_handling": { + "on_validation_error": "log", + "max_errors": 50 + } + } +} +``` + +## موجه نموذج اللغة الكبير لإنشاء الوصف + +يمكن استخدام الموجه التالي لجعل نموذج لغة كبير يحلل بيانات عينة وينشئ تكوينًا للوصف: + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +The descriptor should follow this specification: +- version: "1.0" +- metadata: Configuration name, description, author, and creation date +- format: Input format type and parsing options +- globals: Variables, lookup tables, and constants +- preprocessing: Filters and transformations applied before mapping +- mappings: Field-by-field mapping from source to target with transformations and validations +- postprocessing: Operations like deduplication or aggregation +- output: Target format and error handling configuration + +ANALYZE THE DATA: +1. Identify the format (CSV, JSON, XML, etc.) +2. Detect delimiters, encodings, and structure +3. Find data types for each field +4. Identify patterns and constraints +5. Look for fields that need cleaning or transformation +6. Find relationships between fields +7. Identify lookup opportunities (codes that map to values) +8. Detect required vs optional fields + +CREATE THE DESCRIPTOR: +For each field in the sample data: +- Map it to an appropriate target field name +- Add necessary transformations (trim, case conversion, type casting) +- Include appropriate validations (required, patterns, ranges) +- Set defaults for missing values + +Include preprocessing if needed: +- Filters to exclude invalid records +- Sorting requirements + +Include postprocessing if beneficial: +- Deduplication on key fields +- Aggregation for summary data + +Configure output for TrustGraph: +- format: "trustgraph-objects" +- schema_name: Based on the data entity type +- Appropriate error handling + +DATA SAMPLE: +[Insert data sample here] + +ADDITIONAL CONTEXT (optional): +- Target schema name: [if known] +- Business rules: [any specific requirements] +- Data quality issues to address: [known problems] + +Generate a complete, valid Structured Data Descriptor configuration that will properly import this data into TrustGraph. Include comments explaining key decisions. +``` + +### مثال للاستخدام + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +[Standard instructions from above...] + +DATA SAMPLE: +```csv +CustomerID، الاسم، البريد الإلكتروني، العمر، البلد، الحالة، تاريخ الانضمام، إجمالي المشتريات +1001، "Smith, John"، john.smith@email.com، 35، الولايات المتحدة الأمريكية، 1، 2023-01-15، 5420.50 +1002، "doe, jane"، JANE.DOE@GMAIL.COM، 28، كندا، 1، 2023-03-22، 3200.00 +1003، "Bob Johnson"، bob@، 62، المملكة المتحدة، 0، 2022-11-01، 0 +1004، "Alice Chen"، alice.chen@company.org، 41، الولايات المتحدة الأمريكية، 1، 2023-06-10، 8900.25 +1005، ، invalid-email، 25، XX، 1، 2024-01-01، 100 +``` + +ADDITIONAL CONTEXT: +- Target schema name: customer +- Business rules: Email should be valid and lowercase, names should be title case +- Data quality issues: Some emails are invalid, some names are missing, country codes need mapping +``` + +### طلب لتحليل البيانات الحالية بدون عينة + +``` +I need you to help me create a Structured Data Descriptor configuration for importing [data type] data. + +The source data has these characteristics: +- Format: [CSV/JSON/XML/etc] +- Fields: [list the fields] +- Data quality issues: [describe any known issues] +- Volume: [approximate number of records] + +Requirements: +- [List any specific transformation needs] +- [List any validation requirements] +- [List any business rules] + +Please generate a Structured Data Descriptor configuration that will: +1. Parse the input format correctly +2. Clean and standardize the data +3. Validate according to the requirements +4. Handle errors gracefully +5. Output in TrustGraph ExtractedObject format + +Focus on making the configuration robust and reusable. +``` \ No newline at end of file diff --git a/docs/tech-specs/structured-data-descriptor.es.md b/docs/tech-specs/structured-data-descriptor.es.md new file mode 100644 index 00000000..4c61546a --- /dev/null +++ b/docs/tech-specs/structured-data-descriptor.es.md @@ -0,0 +1,559 @@ +# Especificación del Descriptor de Datos Estructurados + +## Resumen + +El Descriptor de Datos Estructurados es un lenguaje de configuración basado en JSON que describe cómo analizar, transformar e importar datos estructurados en TrustGraph. Proporciona un enfoque declarativo para la ingesta de datos, admitiendo múltiples formatos de entrada y complejas canalizaciones de transformación sin requerir código personalizado. + +## Conceptos Clave + +### 1. Definición de Formato +Describe el tipo de archivo de entrada y las opciones de análisis. Determina qué analizador utilizar y cómo interpretar los datos de origen. + +### 2. Mapeo de Campos +Mapea las rutas de origen a los campos de destino con transformaciones. Define cómo fluyen los datos desde las fuentes de entrada a los campos del esquema de salida. + +### 3. Canalización de Transformación +Cadena de transformaciones de datos que se pueden aplicar a los valores de los campos, incluyendo: +Limpieza de datos (recorte, normalización) +Conversión de formato (análisis de fechas, conversión de tipos) +Cálculos (aritméticos, manipulación de cadenas) +Consultas (tablas de referencia, sustituciones) + +### 4. Reglas de Validación +Comprobaciones de calidad de datos aplicadas para garantizar la integridad de los datos: +Validación de tipo +Comprobaciones de rango +Coincidencia de patrones (expresiones regulares) +Validación de campos obligatorios +Lógica de validación personalizada + +### 5. Configuración Global +Configuración que se aplica a todo el proceso de importación: +Tablas de consulta para la enriquecimiento de datos +Variables y constantes globales +Especificaciones de formato de salida +Políticas de manejo de errores + +## Estrategia de Implementación + +La implementación del importador sigue esta canalización: + +1. **Análisis de Configuración** - Carga y valida el descriptor JSON +2. **Inicialización del Analizador** - Carga el analizador apropiado (CSV, XML, JSON, etc.) basado en `format.type` +3. **Aplicación de Preprocesamiento** - Ejecuta filtros y transformaciones globales +4. **Procesamiento de Registros** - Para cada registro de entrada: + Extrae datos utilizando rutas de origen (JSONPath, XPath, nombres de columna) + Aplica transformaciones a nivel de campo en secuencia + Valida los resultados contra las reglas definidas + Aplica valores predeterminados para datos faltantes +5. **Aplicación de Postprocesamiento** - Ejecuta desduplicación, agregación, etc. +6. **Generación de Salida** - Produce datos en el formato de destino especificado + +## Soporte de Expresiones de Ruta + +Diferentes formatos de entrada utilizan lenguajes de expresiones de ruta apropiados: + +**CSV**: Nombres de columna o índices (`"column_name"` o `"[2]"`) +**JSON**: Sintaxis JSONPath (`"$.user.profile.email"`) +**XML**: Expresiones XPath (`"//product[@id='123']/price"`) +**Ancho Fijo**: Nombres de campo de las definiciones de campo + +## Beneficios + +**Base de Código Única** - Un único importador maneja múltiples formatos de entrada +**Fácil de Usar** - Usuarios no técnicos pueden crear configuraciones +**Reutilizable** - Las configuraciones se pueden compartir y versionar +**Flexible** - Transformaciones complejas sin codificación personalizada +**Robusto** - Validación integrada y manejo de errores integral +**Mantenible** - El enfoque declarativo reduce la complejidad de la implementación + +## Especificación del Lenguaje + +El Descriptor de Datos Estructurados utiliza un formato de configuración JSON con la siguiente estructura de nivel superior: + +```json +{ + "version": "1.0", + "metadata": { + "name": "Configuration Name", + "description": "Description of what this config does", + "author": "Author Name", + "created": "2024-01-01T00:00:00Z" + }, + "format": { ... }, + "globals": { ... }, + "preprocessing": [ ... ], + "mappings": [ ... ], + "postprocessing": [ ... ], + "output": { ... } +} +``` + +### Definición del formato + +Describe el formato de los datos de entrada y las opciones de análisis: + +```json +{ + "format": { + "type": "csv|json|xml|fixed-width|excel|parquet", + "encoding": "utf-8", + "options": { + // Format-specific options + } + } +} +``` + +#### Opciones de formato CSV +```json +{ + "format": { + "type": "csv", + "options": { + "delimiter": ",", + "quote_char": "\"", + "escape_char": "\\", + "skip_rows": 1, + "has_header": true, + "null_values": ["", "NULL", "null", "N/A"] + } + } +} +``` + +#### Opciones de formato JSON +```json +{ + "format": { + "type": "json", + "options": { + "root_path": "$.data", + "array_mode": "records|single", + "flatten": false + } + } +} +``` + +#### Opciones de formato XML +```json +{ + "format": { + "type": "xml", + "options": { + "root_element": "//records/record", + "namespaces": { + "ns": "http://example.com/namespace" + } + } + } +} +``` + +### Configuración Global + +Defina tablas de búsqueda, variables y configuración global: + +```json +{ + "globals": { + "variables": { + "current_date": "2024-01-01", + "batch_id": "BATCH_001", + "default_confidence": 0.8 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "UK": "United Kingdom", + "CA": "Canada" + }, + "status_mapping": { + "1": "active", + "0": "inactive" + } + }, + "constants": { + "source_system": "legacy_crm", + "import_type": "full" + } + } +} +``` + +### Mapeo de campos + +Defina cómo los datos de origen se mapean a los campos de destino con transformaciones: + +```json +{ + "mappings": [ + { + "target_field": "person_name", + "source": "$.name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"}, + {"type": "required"} + ], + "validation": [ + {"type": "min_length", "value": 2}, + {"type": "max_length", "value": 100}, + {"type": "pattern", "value": "^[A-Za-z\\s]+$"} + ] + }, + { + "target_field": "age", + "source": "$.age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 150} + ] + }, + { + "target_field": "country", + "source": "$.country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ] +} +``` + +### Tipos de Transformación + +Funciones de transformación disponibles: + +#### Transformaciones de Cadenas de Texto +```json +{"type": "trim"}, +{"type": "upper"}, +{"type": "lower"}, +{"type": "title_case"}, +{"type": "replace", "pattern": "old", "replacement": "new"}, +{"type": "regex_replace", "pattern": "\\d+", "replacement": "XXX"}, +{"type": "substring", "start": 0, "end": 10}, +{"type": "pad_left", "length": 10, "char": "0"} +``` + +#### Conversiones de tipo +```json +{"type": "to_string"}, +{"type": "to_int"}, +{"type": "to_float"}, +{"type": "to_bool"}, +{"type": "to_date", "format": "YYYY-MM-DD"}, +{"type": "parse_json"} +``` + +#### Operaciones de datos +```json +{"type": "default", "value": "default_value"}, +{"type": "lookup", "table": "table_name"}, +{"type": "concat", "values": ["field1", " - ", "field2"]}, +{"type": "calculate", "expression": "${field1} + ${field2}"}, +{"type": "conditional", "condition": "${age} > 18", "true_value": "adult", "false_value": "minor"} +``` + +### Reglas de validación + +Comprobaciones de calidad de datos con manejo de errores configurable: + +#### Validaciones básicas +```json +{"type": "required"}, +{"type": "not_null"}, +{"type": "min_length", "value": 5}, +{"type": "max_length", "value": 100}, +{"type": "range", "min": 0, "max": 1000}, +{"type": "pattern", "value": "^[A-Z]{2,3}$"}, +{"type": "in_list", "values": ["active", "inactive", "pending"]} +``` + +#### Validaciones Personalizadas +```json +{ + "type": "custom", + "expression": "${age} >= 18 && ${country} == 'US'", + "message": "Must be 18+ and in US" +}, +{ + "type": "cross_field", + "fields": ["start_date", "end_date"], + "expression": "${start_date} < ${end_date}", + "message": "Start date must be before end date" +} +``` + +### Preprocesamiento y Postprocesamiento + +Operaciones globales aplicadas antes/después del mapeo de campos: + +```json +{ + "preprocessing": [ + { + "type": "filter", + "condition": "${status} != 'deleted'" + }, + { + "type": "sort", + "field": "created_date", + "order": "asc" + } + ], + "postprocessing": [ + { + "type": "deduplicate", + "key_fields": ["email", "phone"] + }, + { + "type": "aggregate", + "group_by": ["country"], + "functions": { + "total_count": {"type": "count"}, + "avg_age": {"type": "avg", "field": "age"} + } + } + ] +} +``` + +### Configuración de salida + +Defina cómo se deben mostrar los datos procesados: + +```json +{ + "output": { + "format": "trustgraph-objects", + "schema_name": "person", + "options": { + "batch_size": 1000, + "confidence": 0.9, + "source_span_field": "raw_text", + "metadata": { + "source": "crm_import", + "version": "1.0" + } + }, + "error_handling": { + "on_validation_error": "skip|fail|log", + "on_transform_error": "skip|fail|default", + "max_errors": 100, + "error_output": "errors.json" + } + } +} +``` + +## Ejemplo Completo + +```json +{ + "version": "1.0", + "metadata": { + "name": "Customer Import from CRM CSV", + "description": "Imports customer data from legacy CRM system", + "author": "Data Team", + "created": "2024-01-01T00:00:00Z" + }, + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true, + "skip_rows": 1 + } + }, + "globals": { + "variables": { + "import_date": "2024-01-01", + "default_confidence": 0.85 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "CA": "Canada", + "UK": "United Kingdom" + } + } + }, + "preprocessing": [ + { + "type": "filter", + "condition": "${status} == 'active'" + } + ], + "mappings": [ + { + "target_field": "full_name", + "source": "customer_name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"} + ], + "validation": [ + {"type": "required"}, + {"type": "min_length", "value": 2} + ] + }, + { + "target_field": "email", + "source": "email_address", + "transforms": [ + {"type": "trim"}, + {"type": "lower"} + ], + "validation": [ + {"type": "pattern", "value": "^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$"} + ] + }, + { + "target_field": "age", + "source": "age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 120} + ] + }, + { + "target_field": "country", + "source": "country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ], + "output": { + "format": "trustgraph-objects", + "schema_name": "customer", + "options": { + "confidence": "${default_confidence}", + "batch_size": 500 + }, + "error_handling": { + "on_validation_error": "log", + "max_errors": 50 + } + } +} +``` + +## Indicación para el LLM para la Generación de Descriptores + +La siguiente indicación se puede utilizar para que un LLM analice datos de muestra y genere una configuración de descriptor: + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +The descriptor should follow this specification: +- version: "1.0" +- metadata: Configuration name, description, author, and creation date +- format: Input format type and parsing options +- globals: Variables, lookup tables, and constants +- preprocessing: Filters and transformations applied before mapping +- mappings: Field-by-field mapping from source to target with transformations and validations +- postprocessing: Operations like deduplication or aggregation +- output: Target format and error handling configuration + +ANALYZE THE DATA: +1. Identify the format (CSV, JSON, XML, etc.) +2. Detect delimiters, encodings, and structure +3. Find data types for each field +4. Identify patterns and constraints +5. Look for fields that need cleaning or transformation +6. Find relationships between fields +7. Identify lookup opportunities (codes that map to values) +8. Detect required vs optional fields + +CREATE THE DESCRIPTOR: +For each field in the sample data: +- Map it to an appropriate target field name +- Add necessary transformations (trim, case conversion, type casting) +- Include appropriate validations (required, patterns, ranges) +- Set defaults for missing values + +Include preprocessing if needed: +- Filters to exclude invalid records +- Sorting requirements + +Include postprocessing if beneficial: +- Deduplication on key fields +- Aggregation for summary data + +Configure output for TrustGraph: +- format: "trustgraph-objects" +- schema_name: Based on the data entity type +- Appropriate error handling + +DATA SAMPLE: +[Insert data sample here] + +ADDITIONAL CONTEXT (optional): +- Target schema name: [if known] +- Business rules: [any specific requirements] +- Data quality issues to address: [known problems] + +Generate a complete, valid Structured Data Descriptor configuration that will properly import this data into TrustGraph. Include comments explaining key decisions. +``` + +### Ejemplo de uso (Prompt) + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +[Standard instructions from above...] + +DATA SAMPLE: +```csv +CustomerID,Nombre,Email,Edad,País,Estado,Fecha de Inscripción,Total de Compras +1001,"Smith, John",john.smith@email.com,35,US,1,2023-01-15,5420.50 +1002,"doe, jane",JANE.DOE@GMAIL.COM,28,CA,1,2023-03-22,3200.00 +1003,"Bob Johnson",bob@,62,UK,0,2022-11-01,0 +1004,"Alice Chen","alice.chen@company.org",41,US,1,2023-06-10,8900.25 +1005,,invalid-email,25,XX,1,2024-01-01,100 +``` + +ADDITIONAL CONTEXT: +- Target schema name: customer +- Business rules: Email should be valid and lowercase, names should be title case +- Data quality issues: Some emails are invalid, some names are missing, country codes need mapping +``` + +### Solicitud para Analizar Datos Existentes Sin Muestra + +``` +I need you to help me create a Structured Data Descriptor configuration for importing [data type] data. + +The source data has these characteristics: +- Format: [CSV/JSON/XML/etc] +- Fields: [list the fields] +- Data quality issues: [describe any known issues] +- Volume: [approximate number of records] + +Requirements: +- [List any specific transformation needs] +- [List any validation requirements] +- [List any business rules] + +Please generate a Structured Data Descriptor configuration that will: +1. Parse the input format correctly +2. Clean and standardize the data +3. Validate according to the requirements +4. Handle errors gracefully +5. Output in TrustGraph ExtractedObject format + +Focus on making the configuration robust and reusable. +``` \ No newline at end of file diff --git a/docs/tech-specs/structured-data-descriptor.he.md b/docs/tech-specs/structured-data-descriptor.he.md new file mode 100644 index 00000000..2c73957c --- /dev/null +++ b/docs/tech-specs/structured-data-descriptor.he.md @@ -0,0 +1,559 @@ +# מפרט עבור תיאור נתונים מובנים + +## סקירה כללית + +תיאור הנתונים המובנים הוא שפת תצורה מבוססת JSON המתארת כיצד לנתח, להמיר ולייבא נתונים מובנים ל-TrustGraph. הוא מספק גישה הצהרתית לייבוא נתונים, תוך תמיכה בפורמטים מרובים של קלט וצינורות המרה מורכבים מבלי לדרוש קוד מותאם אישית. + +## מושגים מרכזיים + +### 1. הגדרת פורמט +מתאר את סוג הקובץ הנכנס ואפשרויות הניתוח. קובע איזה מנתח להשתמש וכיצד לפרש את הנתונים המקור. + +### 2. מיפוי שדות +ממפה נתיבים מקור לשדות יעד עם המרות. מגדיר כיצד הנתונים זורמים ממקורות קלט לשדות סכימה בפלט. + +### 3. צינור המרה +שרשרת של המרות נתונים שניתן להחיל על ערכי שדות, כולל: +ניקוי נתונים (חיתוך, נרמול) +המרת פורמט (ניתוח תאריכים, המרת טיפוסים) +חישובים (חשבון, מניפולציה של מחרוזות) +חיפושים (טבלאות הפניה, החלפות) + +### 4. כללי אימות +בדיקות איכות נתונים המיושמות כדי להבטיח את שלמות הנתונים: +אימות טיפוס +בדיקות טווח +התאמת תבניות (ביטויים רגולריים) +אימות שדות חובה +לוגיקה מותאמת אישית לאימות + +### 5. הגדרות גלובליות +תצורה החלה על כל תהליך הייבוא: +טבלאות חיפוש להעשרת נתונים +משתנים וקבועים גלובליים +מפרטי פורמט פלט +מדיניות טיפול בשגיאות + +## אסטרטגיית יישום + +יישום המייבא עוקב אחר הצינור הבא: + +1. **ניתוח תצורה** - טעינה ואימות של תיאור JSON +2. **אתחול מנתח** - טעינת מנתח מתאים (CSV, XML, JSON, וכו') בהתבסס על `format.type` +3. **החלת עיבוד מקדים** - ביצוע פילטרים והמרות גלובליים +4. **עיבוד רשומות** - עבור כל רשומה נכנסת: + חילוץ נתונים באמצעות נתיבי מקור (JSONPath, XPath, שמות עמודות) + החלת המרות ברמת השדה בסדר + אימות תוצאות בהתאם לכללים מוגדרים + החלת ערכי ברירת מחדל עבור נתונים חסרים +5. **החלת עיבוד לאחר** - ביצוע הסרה כפילות, אגרגציה, וכו'. +6. **יצירת פלט** - יצירת נתונים בפורמט יעד מוגדר + +## תמיכה בביטוי נתיב + +פורמטים שונים של קלט משתמשים בשפות ביטוי נתיב מתאימות: + +**CSV**: שמות עמודות או אינדקסים (`"column_name"` או `"[2]"`) +**JSON**: תחביר JSONPath (`"$.user.profile.email"`) +**XML**: ביטויי XPath (`"//product[@id='123']/price"`) +**רוחב קבוע**: שמות שדות מהגדרות שדות + +## יתרונות + +**בסיס קוד יחיד** - מייבא אחד מטפל בפורמטים מרובים של קלט +**ידידותי למשתמש** - משתמשים לא טכניים יכולים ליצור תצורות +**ניתן לשימוש חוזר** - ניתן לשתף תצורות ולגרסן +**גמיש** - המרות מורכבות ללא קידוד מותאם אישית +**יציב** - אימות מובנה וטיפול מקיף בשגיאות +**ניתן לתחזוקה** - גישה הצהרתית מפחיתה את מורכבות היישום + +## מפרט שפה + +תיאור הנתונים המובנים משתמש בפורמט תצורה JSON עם המבנה הבסיסי הבא ברמה העליונה: + +```json +{ + "version": "1.0", + "metadata": { + "name": "Configuration Name", + "description": "Description of what this config does", + "author": "Author Name", + "created": "2024-01-01T00:00:00Z" + }, + "format": { ... }, + "globals": { ... }, + "preprocessing": [ ... ], + "mappings": [ ... ], + "postprocessing": [ ... ], + "output": { ... } +} +``` + +### הגדרת פורמט + +מתאר את פורמט הנתונים הקלט ואפשרויות הניתוח: + +```json +{ + "format": { + "type": "csv|json|xml|fixed-width|excel|parquet", + "encoding": "utf-8", + "options": { + // Format-specific options + } + } +} +``` + +#### אפשרויות פורמט CSV +```json +{ + "format": { + "type": "csv", + "options": { + "delimiter": ",", + "quote_char": "\"", + "escape_char": "\\", + "skip_rows": 1, + "has_header": true, + "null_values": ["", "NULL", "null", "N/A"] + } + } +} +``` + +#### אפשרויות פורמט JSON +```json +{ + "format": { + "type": "json", + "options": { + "root_path": "$.data", + "array_mode": "records|single", + "flatten": false + } + } +} +``` + +#### אפשרויות פורמט XML +```json +{ + "format": { + "type": "xml", + "options": { + "root_element": "//records/record", + "namespaces": { + "ns": "http://example.com/namespace" + } + } + } +} +``` + +### הגדרות גלובליות + +הגדירו טבלאות חיפוש, משתנים ותצורות גלובליות: + +```json +{ + "globals": { + "variables": { + "current_date": "2024-01-01", + "batch_id": "BATCH_001", + "default_confidence": 0.8 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "UK": "United Kingdom", + "CA": "Canada" + }, + "status_mapping": { + "1": "active", + "0": "inactive" + } + }, + "constants": { + "source_system": "legacy_crm", + "import_type": "full" + } + } +} +``` + +### מיפוי שדות + +הגדירו כיצד נתוני המקור ממופים לשדות היעד עם טרנספורמציות: + +```json +{ + "mappings": [ + { + "target_field": "person_name", + "source": "$.name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"}, + {"type": "required"} + ], + "validation": [ + {"type": "min_length", "value": 2}, + {"type": "max_length", "value": 100}, + {"type": "pattern", "value": "^[A-Za-z\\s]+$"} + ] + }, + { + "target_field": "age", + "source": "$.age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 150} + ] + }, + { + "target_field": "country", + "source": "$.country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ] +} +``` + +### סוגי טרנספורמציה + +פונקציות טרנספורמציה זמינות: + +#### טרנספורמציות מחרוזות +```json +{"type": "trim"}, +{"type": "upper"}, +{"type": "lower"}, +{"type": "title_case"}, +{"type": "replace", "pattern": "old", "replacement": "new"}, +{"type": "regex_replace", "pattern": "\\d+", "replacement": "XXX"}, +{"type": "substring", "start": 0, "end": 10}, +{"type": "pad_left", "length": 10, "char": "0"} +``` + +#### המרות טיפוסים +```json +{"type": "to_string"}, +{"type": "to_int"}, +{"type": "to_float"}, +{"type": "to_bool"}, +{"type": "to_date", "format": "YYYY-MM-DD"}, +{"type": "parse_json"} +``` + +#### פעולות נתונים +```json +{"type": "default", "value": "default_value"}, +{"type": "lookup", "table": "table_name"}, +{"type": "concat", "values": ["field1", " - ", "field2"]}, +{"type": "calculate", "expression": "${field1} + ${field2}"}, +{"type": "conditional", "condition": "${age} > 18", "true_value": "adult", "false_value": "minor"} +``` + +### כללי אימות + +בדיקות איכות נתונים עם טיפול בשגיאות הניתן להגדרה: + +#### אימותים בסיסיים +```json +{"type": "required"}, +{"type": "not_null"}, +{"type": "min_length", "value": 5}, +{"type": "max_length", "value": 100}, +{"type": "range", "min": 0, "max": 1000}, +{"type": "pattern", "value": "^[A-Z]{2,3}$"}, +{"type": "in_list", "values": ["active", "inactive", "pending"]} +``` + +#### אימותים מותאמים אישית +```json +{ + "type": "custom", + "expression": "${age} >= 18 && ${country} == 'US'", + "message": "Must be 18+ and in US" +}, +{ + "type": "cross_field", + "fields": ["start_date", "end_date"], + "expression": "${start_date} < ${end_date}", + "message": "Start date must be before end date" +} +``` + +### עיבוד מקדים ועיבוד סופי + +פעולות גלובליות המיושמות לפני/אחרי מיפוי שדות: + +```json +{ + "preprocessing": [ + { + "type": "filter", + "condition": "${status} != 'deleted'" + }, + { + "type": "sort", + "field": "created_date", + "order": "asc" + } + ], + "postprocessing": [ + { + "type": "deduplicate", + "key_fields": ["email", "phone"] + }, + { + "type": "aggregate", + "group_by": ["country"], + "functions": { + "total_count": {"type": "count"}, + "avg_age": {"type": "avg", "field": "age"} + } + } + ] +} +``` + +### הגדרות פלט + +הגדירו כיצד יש להוציא את הנתונים שעברו עיבוד: + +```json +{ + "output": { + "format": "trustgraph-objects", + "schema_name": "person", + "options": { + "batch_size": 1000, + "confidence": 0.9, + "source_span_field": "raw_text", + "metadata": { + "source": "crm_import", + "version": "1.0" + } + }, + "error_handling": { + "on_validation_error": "skip|fail|log", + "on_transform_error": "skip|fail|default", + "max_errors": 100, + "error_output": "errors.json" + } + } +} +``` + +## דוגמה מלאה + +```json +{ + "version": "1.0", + "metadata": { + "name": "Customer Import from CRM CSV", + "description": "Imports customer data from legacy CRM system", + "author": "Data Team", + "created": "2024-01-01T00:00:00Z" + }, + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true, + "skip_rows": 1 + } + }, + "globals": { + "variables": { + "import_date": "2024-01-01", + "default_confidence": 0.85 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "CA": "Canada", + "UK": "United Kingdom" + } + } + }, + "preprocessing": [ + { + "type": "filter", + "condition": "${status} == 'active'" + } + ], + "mappings": [ + { + "target_field": "full_name", + "source": "customer_name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"} + ], + "validation": [ + {"type": "required"}, + {"type": "min_length", "value": 2} + ] + }, + { + "target_field": "email", + "source": "email_address", + "transforms": [ + {"type": "trim"}, + {"type": "lower"} + ], + "validation": [ + {"type": "pattern", "value": "^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$"} + ] + }, + { + "target_field": "age", + "source": "age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 120} + ] + }, + { + "target_field": "country", + "source": "country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ], + "output": { + "format": "trustgraph-objects", + "schema_name": "customer", + "options": { + "confidence": "${default_confidence}", + "batch_size": 500 + }, + "error_handling": { + "on_validation_error": "log", + "max_errors": 50 + } + } +} +``` + +## הנחיה עבור מודל שפה גדול (LLM) ליצירת תיאור + +ניתן להשתמש בהנחיה הבאה כדי לגרום למודל שפה גדול לנתח נתוני דוגמה וליצור תצורת תיאור: + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +The descriptor should follow this specification: +- version: "1.0" +- metadata: Configuration name, description, author, and creation date +- format: Input format type and parsing options +- globals: Variables, lookup tables, and constants +- preprocessing: Filters and transformations applied before mapping +- mappings: Field-by-field mapping from source to target with transformations and validations +- postprocessing: Operations like deduplication or aggregation +- output: Target format and error handling configuration + +ANALYZE THE DATA: +1. Identify the format (CSV, JSON, XML, etc.) +2. Detect delimiters, encodings, and structure +3. Find data types for each field +4. Identify patterns and constraints +5. Look for fields that need cleaning or transformation +6. Find relationships between fields +7. Identify lookup opportunities (codes that map to values) +8. Detect required vs optional fields + +CREATE THE DESCRIPTOR: +For each field in the sample data: +- Map it to an appropriate target field name +- Add necessary transformations (trim, case conversion, type casting) +- Include appropriate validations (required, patterns, ranges) +- Set defaults for missing values + +Include preprocessing if needed: +- Filters to exclude invalid records +- Sorting requirements + +Include postprocessing if beneficial: +- Deduplication on key fields +- Aggregation for summary data + +Configure output for TrustGraph: +- format: "trustgraph-objects" +- schema_name: Based on the data entity type +- Appropriate error handling + +DATA SAMPLE: +[Insert data sample here] + +ADDITIONAL CONTEXT (optional): +- Target schema name: [if known] +- Business rules: [any specific requirements] +- Data quality issues to address: [known problems] + +Generate a complete, valid Structured Data Descriptor configuration that will properly import this data into TrustGraph. Include comments explaining key decisions. +``` + +### הנחיה לדוגמה לשימוש + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +[Standard instructions from above...] + +DATA SAMPLE: +```csv +CustomerID,שם לקוח,כתובת דוא"ל,גיל,מדינה,סטטוס,תאריך הצטרפות,סך רכישות +1001,"Smith, John",john.smith@email.com,35,US,1,2023-01-15,5420.50 +1002,"doe, jane",JANE.DOE@GMAIL.COM,28,CA,1,2023-03-22,3200.00 +1003,"Bob Johnson",bob@,62,UK,0,2022-11-01,0 +1004,"Alice Chen","alice.chen@company.org",41,US,1,2023-06-10,8900.25 +1005,,invalid-email,25,XX,1,2024-01-01,100 +``` + +ADDITIONAL CONTEXT: +- Target schema name: customer +- Business rules: Email should be valid and lowercase, names should be title case +- Data quality issues: Some emails are invalid, some names are missing, country codes need mapping +``` + +### הנחיה לניתוח נתונים קיימים ללא דוגמה + +``` +I need you to help me create a Structured Data Descriptor configuration for importing [data type] data. + +The source data has these characteristics: +- Format: [CSV/JSON/XML/etc] +- Fields: [list the fields] +- Data quality issues: [describe any known issues] +- Volume: [approximate number of records] + +Requirements: +- [List any specific transformation needs] +- [List any validation requirements] +- [List any business rules] + +Please generate a Structured Data Descriptor configuration that will: +1. Parse the input format correctly +2. Clean and standardize the data +3. Validate according to the requirements +4. Handle errors gracefully +5. Output in TrustGraph ExtractedObject format + +Focus on making the configuration robust and reusable. +``` \ No newline at end of file diff --git a/docs/tech-specs/structured-data-descriptor.hi.md b/docs/tech-specs/structured-data-descriptor.hi.md new file mode 100644 index 00000000..dd2570b7 --- /dev/null +++ b/docs/tech-specs/structured-data-descriptor.hi.md @@ -0,0 +1,559 @@ +# संरचित डेटा विवरण विनिर्देश + +## अवलोकन + +संरचित डेटा विवरण एक JSON-आधारित कॉन्फ़िगरेशन भाषा है जो यह बताती है कि संरचित डेटा को कैसे पार्स, रूपांतरित और ट्रस्टग्राफ में आयात किया जाए। यह डेटा इनग्रेसन के लिए एक घोषणात्मक दृष्टिकोण प्रदान करता है, जो कई इनपुट प्रारूपों और जटिल परिवर्तन पाइपलाइनों का समर्थन करता है, बिना कस्टम कोड की आवश्यकता के। + +## मुख्य अवधारणाएँ + +### 1. प्रारूप परिभाषा +इनपुट फ़ाइल प्रकार और पार्सिंग विकल्पों का वर्णन करता है। यह निर्धारित करता है कि किस पार्सर का उपयोग करना है और स्रोत डेटा की व्याख्या कैसे करनी है। + +### 2. फ़ील्ड मैपिंग +स्रोत पथों को लक्ष्य फ़ील्ड में रूपांतरणों के साथ मैप करता है। यह परिभाषित करता है कि डेटा इनपुट स्रोतों से आउटपुट स्कीमा फ़ील्ड में कैसे प्रवाहित होता है। + +### 3. परिवर्तन पाइपलाइन +डेटा रूपांतरणों की श्रृंखला जो फ़ील्ड मानों पर लागू की जा सकती है, जिसमें शामिल हैं: +डेटा सफाई (ट्रिम, सामान्यीकरण) +प्रारूप रूपांतरण (तारीख पार्सिंग, प्रकार कास्टिंग) +गणनाएँ (अंकगणित, स्ट्रिंग हेरफेर) +लुकअप (संदर्भ तालिकाएँ, प्रतिस्थापन) + +### 4. सत्यापन नियम +डेटा गुणवत्ता जांच जो डेटा अखंडता सुनिश्चित करने के लिए लागू की जाती हैं: +प्रकार सत्यापन +सीमा जांच +पैटर्न मिलान (रेगेक्स) +आवश्यक फ़ील्ड सत्यापन +कस्टम सत्यापन तर्क + +### 5. वैश्विक सेटिंग्स +कॉन्फ़िगरेशन जो संपूर्ण आयात प्रक्रिया पर लागू होता है: +डेटा संवर्धन के लिए लुकअप तालिकाएँ +वैश्विक चर और स्थिरांक +आउटपुट प्रारूप विनिर्देश +त्रुटि हैंडलिंग नीतियां + +## कार्यान्वयन रणनीति + +इम्पोर्टर कार्यान्वयन निम्नलिखित पाइपलाइन का पालन करता है: + +1. **कॉन्फ़िगरेशन पार्स करें** - JSON विवरण लोड करें और मान्य करें +2. **पार्सर आरंभ करें** - उपयुक्त पार्सर लोड करें (CSV, XML, JSON, आदि) `format.type` के आधार पर +3. **पूर्व-प्रसंस्करण लागू करें** - वैश्विक फ़िल्टर और रूपांतरण निष्पादित करें +4. **रिकॉर्ड संसाधित करें** - प्रत्येक इनपुट रिकॉर्ड के लिए: + स्रोत पथों (JSONPath, XPath, कॉलम नाम) का उपयोग करके डेटा निकालें + अनुक्रम में फ़ील्ड-स्तरीय रूपांतरण लागू करें + परिभाषित नियमों के विरुद्ध परिणामों को मान्य करें + लापता डेटा के लिए डिफ़ॉल्ट मान लागू करें +5. **पोस्ट-प्रोसेसिंग लागू करें** - डुप्लिकेट हटाना, एकत्रीकरण, आदि निष्पादित करें। +6. **आउटपुट उत्पन्न करें** - निर्दिष्ट लक्ष्य प्रारूप में डेटा उत्पन्न करें + +## पथ अभिव्यक्ति समर्थन + +विभिन्न इनपुट प्रारूप उपयुक्त पथ अभिव्यक्ति भाषाओं का उपयोग करते हैं: + +**CSV**: कॉलम नाम या इंडेक्स (`"column_name"` या `"[2]"`) +**JSON**: JSONPath सिंटैक्स (`"$.user.profile.email"`) +**XML**: XPath एक्सप्रेशन (`"//product[@id='123']/price"`) +**फिक्स्ड-विड्थ**: फ़ील्ड परिभाषाओं से फ़ील्ड नाम + +## लाभ + +**सिंगल कोडबेस** - एक इम्पोर्टर कई इनपुट प्रारूपों को संभालता है +**उपयोगकर्ता के अनुकूल** - गैर-तकनीकी उपयोगकर्ता कॉन्फ़िगरेशन बना सकते हैं +**पुन: प्रयोज्य** - कॉन्फ़िगरेशन साझा और संस्करणित किए जा सकते हैं +**लचीला** - कस्टम कोडिंग के बिना जटिल रूपांतरण +**मजबूत** - अंतर्निहित सत्यापन और व्यापक त्रुटि हैंडलिंग +**रखरखाव योग्य** - घोषणात्मक दृष्टिकोण कार्यान्वयन जटिलता को कम करता है + +## भाषा विनिर्देश + +संरचित डेटा विवरण एक JSON कॉन्फ़िगरेशन प्रारूप का उपयोग करता है जिसमें निम्नलिखित शीर्ष-स्तरीय संरचना है: + +```json +{ + "version": "1.0", + "metadata": { + "name": "Configuration Name", + "description": "Description of what this config does", + "author": "Author Name", + "created": "2024-01-01T00:00:00Z" + }, + "format": { ... }, + "globals": { ... }, + "preprocessing": [ ... ], + "mappings": [ ... ], + "postprocessing": [ ... ], + "output": { ... } +} +``` + +### प्रारूप परिभाषा + +इनपुट डेटा प्रारूप और पार्सिंग विकल्पों का वर्णन करता है: + +```json +{ + "format": { + "type": "csv|json|xml|fixed-width|excel|parquet", + "encoding": "utf-8", + "options": { + // Format-specific options + } + } +} +``` + +#### सीएसवी प्रारूप विकल्प +```json +{ + "format": { + "type": "csv", + "options": { + "delimiter": ",", + "quote_char": "\"", + "escape_char": "\\", + "skip_rows": 1, + "has_header": true, + "null_values": ["", "NULL", "null", "N/A"] + } + } +} +``` + +#### जेएसओएन प्रारूप विकल्प +```json +{ + "format": { + "type": "json", + "options": { + "root_path": "$.data", + "array_mode": "records|single", + "flatten": false + } + } +} +``` + +#### XML प्रारूप विकल्प +```json +{ + "format": { + "type": "xml", + "options": { + "root_element": "//records/record", + "namespaces": { + "ns": "http://example.com/namespace" + } + } + } +} +``` + +### वैश्विक सेटिंग्स + +लुकअप टेबल, वेरिएबल और वैश्विक कॉन्फ़िगरेशन को परिभाषित करें: + +```json +{ + "globals": { + "variables": { + "current_date": "2024-01-01", + "batch_id": "BATCH_001", + "default_confidence": 0.8 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "UK": "United Kingdom", + "CA": "Canada" + }, + "status_mapping": { + "1": "active", + "0": "inactive" + } + }, + "constants": { + "source_system": "legacy_crm", + "import_type": "full" + } + } +} +``` + +### फ़ील्ड मैपिंग + +परिभाषित करें कि स्रोत डेटा लक्ष्य फ़ील्ड में कैसे मैप होता है, जिसमें रूपांतरण शामिल हैं: + +```json +{ + "mappings": [ + { + "target_field": "person_name", + "source": "$.name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"}, + {"type": "required"} + ], + "validation": [ + {"type": "min_length", "value": 2}, + {"type": "max_length", "value": 100}, + {"type": "pattern", "value": "^[A-Za-z\\s]+$"} + ] + }, + { + "target_field": "age", + "source": "$.age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 150} + ] + }, + { + "target_field": "country", + "source": "$.country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ] +} +``` + +### रूपांतरण प्रकार + +उपलब्ध रूपांतरण फ़ंक्शन: + +#### स्ट्रिंग रूपांतरण +```json +{"type": "trim"}, +{"type": "upper"}, +{"type": "lower"}, +{"type": "title_case"}, +{"type": "replace", "pattern": "old", "replacement": "new"}, +{"type": "regex_replace", "pattern": "\\d+", "replacement": "XXX"}, +{"type": "substring", "start": 0, "end": 10}, +{"type": "pad_left", "length": 10, "char": "0"} +``` + +#### प्रकार रूपांतरण +```json +{"type": "to_string"}, +{"type": "to_int"}, +{"type": "to_float"}, +{"type": "to_bool"}, +{"type": "to_date", "format": "YYYY-MM-DD"}, +{"type": "parse_json"} +``` + +#### डेटा संचालन +```json +{"type": "default", "value": "default_value"}, +{"type": "lookup", "table": "table_name"}, +{"type": "concat", "values": ["field1", " - ", "field2"]}, +{"type": "calculate", "expression": "${field1} + ${field2}"}, +{"type": "conditional", "condition": "${age} > 18", "true_value": "adult", "false_value": "minor"} +``` + +### सत्यापन नियम + +कॉन्फ़िगर करने योग्य त्रुटि प्रबंधन के साथ डेटा गुणवत्ता जांच: + +#### बुनियादी सत्यापन +```json +{"type": "required"}, +{"type": "not_null"}, +{"type": "min_length", "value": 5}, +{"type": "max_length", "value": 100}, +{"type": "range", "min": 0, "max": 1000}, +{"type": "pattern", "value": "^[A-Z]{2,3}$"}, +{"type": "in_list", "values": ["active", "inactive", "pending"]} +``` + +#### कस्टम सत्यापन +```json +{ + "type": "custom", + "expression": "${age} >= 18 && ${country} == 'US'", + "message": "Must be 18+ and in US" +}, +{ + "type": "cross_field", + "fields": ["start_date", "end_date"], + "expression": "${start_date} < ${end_date}", + "message": "Start date must be before end date" +} +``` + +### पूर्व-प्रसंस्करण और उत्तर-प्रसंस्करण + +फ़ील्ड मैपिंग से पहले/बाद लागू किए गए वैश्विक ऑपरेशन: + +```json +{ + "preprocessing": [ + { + "type": "filter", + "condition": "${status} != 'deleted'" + }, + { + "type": "sort", + "field": "created_date", + "order": "asc" + } + ], + "postprocessing": [ + { + "type": "deduplicate", + "key_fields": ["email", "phone"] + }, + { + "type": "aggregate", + "group_by": ["country"], + "functions": { + "total_count": {"type": "count"}, + "avg_age": {"type": "avg", "field": "age"} + } + } + ] +} +``` + +### आउटपुट कॉन्फ़िगरेशन + +परिभाषित करें कि संसाधित डेटा को कैसे आउटपुट किया जाना चाहिए: + +```json +{ + "output": { + "format": "trustgraph-objects", + "schema_name": "person", + "options": { + "batch_size": 1000, + "confidence": 0.9, + "source_span_field": "raw_text", + "metadata": { + "source": "crm_import", + "version": "1.0" + } + }, + "error_handling": { + "on_validation_error": "skip|fail|log", + "on_transform_error": "skip|fail|default", + "max_errors": 100, + "error_output": "errors.json" + } + } +} +``` + +## पूर्ण उदाहरण + +```json +{ + "version": "1.0", + "metadata": { + "name": "Customer Import from CRM CSV", + "description": "Imports customer data from legacy CRM system", + "author": "Data Team", + "created": "2024-01-01T00:00:00Z" + }, + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true, + "skip_rows": 1 + } + }, + "globals": { + "variables": { + "import_date": "2024-01-01", + "default_confidence": 0.85 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "CA": "Canada", + "UK": "United Kingdom" + } + } + }, + "preprocessing": [ + { + "type": "filter", + "condition": "${status} == 'active'" + } + ], + "mappings": [ + { + "target_field": "full_name", + "source": "customer_name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"} + ], + "validation": [ + {"type": "required"}, + {"type": "min_length", "value": 2} + ] + }, + { + "target_field": "email", + "source": "email_address", + "transforms": [ + {"type": "trim"}, + {"type": "lower"} + ], + "validation": [ + {"type": "pattern", "value": "^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$"} + ] + }, + { + "target_field": "age", + "source": "age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 120} + ] + }, + { + "target_field": "country", + "source": "country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ], + "output": { + "format": "trustgraph-objects", + "schema_name": "customer", + "options": { + "confidence": "${default_confidence}", + "batch_size": 500 + }, + "error_handling": { + "on_validation_error": "log", + "max_errors": 50 + } + } +} +``` + +## एलएलएम प्रॉम्प्ट (LLM Prompt) का उपयोग करके विवरण (डेस्क्रिप्टर) निर्माण + +निम्नलिखित प्रॉम्प्ट का उपयोग करके, एक एलएलएम (LLM) नमूना डेटा का विश्लेषण कर सकता है और एक विवरण कॉन्फ़िगरेशन उत्पन्न कर सकता है: + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +The descriptor should follow this specification: +- version: "1.0" +- metadata: Configuration name, description, author, and creation date +- format: Input format type and parsing options +- globals: Variables, lookup tables, and constants +- preprocessing: Filters and transformations applied before mapping +- mappings: Field-by-field mapping from source to target with transformations and validations +- postprocessing: Operations like deduplication or aggregation +- output: Target format and error handling configuration + +ANALYZE THE DATA: +1. Identify the format (CSV, JSON, XML, etc.) +2. Detect delimiters, encodings, and structure +3. Find data types for each field +4. Identify patterns and constraints +5. Look for fields that need cleaning or transformation +6. Find relationships between fields +7. Identify lookup opportunities (codes that map to values) +8. Detect required vs optional fields + +CREATE THE DESCRIPTOR: +For each field in the sample data: +- Map it to an appropriate target field name +- Add necessary transformations (trim, case conversion, type casting) +- Include appropriate validations (required, patterns, ranges) +- Set defaults for missing values + +Include preprocessing if needed: +- Filters to exclude invalid records +- Sorting requirements + +Include postprocessing if beneficial: +- Deduplication on key fields +- Aggregation for summary data + +Configure output for TrustGraph: +- format: "trustgraph-objects" +- schema_name: Based on the data entity type +- Appropriate error handling + +DATA SAMPLE: +[Insert data sample here] + +ADDITIONAL CONTEXT (optional): +- Target schema name: [if known] +- Business rules: [any specific requirements] +- Data quality issues to address: [known problems] + +Generate a complete, valid Structured Data Descriptor configuration that will properly import this data into TrustGraph. Include comments explaining key decisions. +``` + +### उदाहरण उपयोग संकेत + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +[Standard instructions from above...] + +DATA SAMPLE: +```csv +ग्राहक आईडी, नाम, ईमेल, आयु, देश, स्थिति, शामिल होने की तिथि, कुल खरीदारी +1001, "स्मिथ, जॉन", john.smith@email.com, 35, यूएस, 1, 2023-01-15, 5420.50 +1002, "डो, जेन", JANE.DOE@GMAIL.COM, 28, कनाडा, 1, 2023-03-22, 3200.00 +1003, "बॉब जॉनसन", bob@, 62, यूके, 0, 2022-11-01, 0 +1004, "एलिस चेन", "alice.chen@company.org", 41, यूएस, 1, 2023-06-10, 8900.25 +1005, , invalid-email, 25, XX, 1, 2024-01-01, 100 +``` + +ADDITIONAL CONTEXT: +- Target schema name: customer +- Business rules: Email should be valid and lowercase, names should be title case +- Data quality issues: Some emails are invalid, some names are missing, country codes need mapping +``` + +### मौजूदा डेटा का विश्लेषण करने के लिए संकेत (प्रॉम्प्ट) बिना नमूने के + +``` +I need you to help me create a Structured Data Descriptor configuration for importing [data type] data. + +The source data has these characteristics: +- Format: [CSV/JSON/XML/etc] +- Fields: [list the fields] +- Data quality issues: [describe any known issues] +- Volume: [approximate number of records] + +Requirements: +- [List any specific transformation needs] +- [List any validation requirements] +- [List any business rules] + +Please generate a Structured Data Descriptor configuration that will: +1. Parse the input format correctly +2. Clean and standardize the data +3. Validate according to the requirements +4. Handle errors gracefully +5. Output in TrustGraph ExtractedObject format + +Focus on making the configuration robust and reusable. +``` \ No newline at end of file diff --git a/docs/tech-specs/structured-data-descriptor.pt.md b/docs/tech-specs/structured-data-descriptor.pt.md new file mode 100644 index 00000000..b52b8232 --- /dev/null +++ b/docs/tech-specs/structured-data-descriptor.pt.md @@ -0,0 +1,559 @@ +# Especificação do Descritor de Dados Estruturados + +## Visão Geral + +O Descritor de Dados Estruturados é uma linguagem de configuração baseada em JSON que descreve como analisar, transformar e importar dados estruturados para o TrustGraph. Ele fornece uma abordagem declarativa para a ingestão de dados, suportando vários formatos de entrada e pipelines de transformação complexos sem a necessidade de código personalizado. + +## Conceitos Principais + +### 1. Definição de Formato +Descreve o tipo de arquivo de entrada e as opções de análise. Determina qual analisador usar e como interpretar os dados de origem. + +### 2. Mapeamentos de Campos +Mapeia caminhos de origem para campos de destino com transformações. Define como os dados fluem das fontes de entrada para os campos do esquema de saída. + +### 3. Pipeline de Transformação +Cadeia de transformações de dados que podem ser aplicadas aos valores dos campos, incluindo: +Limpeza de dados (remover espaços em branco, normalização) +Conversão de formato (análise de data, conversão de tipo) +Cálculos (aritméticos, manipulação de strings) +Consultas (tabelas de referência, substituições) + +### 4. Regras de Validação +Verificações de qualidade de dados aplicadas para garantir a integridade dos dados: +Validação de tipo +Verificações de intervalo +Correspondência de padrões (regex) +Validação de campos obrigatórios +Lógica de validação personalizada + +### 5. Configurações Globais +Configuração que se aplica a todo o processo de importação: +Tabelas de consulta para enriquecimento de dados +Variáveis e constantes globais +Especificações de formato de saída +Políticas de tratamento de erros + +## Estratégia de Implementação + +A implementação do importador segue este pipeline: + +1. **Analisar Configuração** - Carregar e validar o descritor JSON +2. **Inicializar Analisador** - Carregar o analisador apropriado (CSV, XML, JSON, etc.) com base em `format.type` +3. **Aplicar Pré-processamento** - Executar filtros e transformações globais +4. **Processar Registros** - Para cada registro de entrada: + Extrair dados usando caminhos de origem (JSONPath, XPath, nomes de coluna) + Aplicar transformações de nível de campo em sequência + Validar os resultados em relação às regras definidas + Aplicar valores padrão para dados ausentes +5. **Aplicar Pós-processamento** - Executar desduplicação, agregação, etc. +6. **Gerar Saída** - Produzir dados no formato de destino especificado + +## Suporte a Expressões de Caminho + +Diferentes formatos de entrada usam linguagens de expressão de caminho apropriadas: + +**CSV**: Nomes de coluna ou índices (`"column_name"` ou `"[2]"`) +**JSON**: Sintaxe JSONPath (`"$.user.profile.email"`) +**XML**: Expressões XPath (`"//product[@id='123']/price"`) +**Largura Fixa**: Nomes de campo das definições de campo + +## Benefícios + +**Base de Código Única** - Um único importador lida com vários formatos de entrada +**Fácil de Usar** - Usuários não técnicos podem criar configurações +**Reutilizável** - As configurações podem ser compartilhadas e versionadas +**Flexível** - Transformações complexas sem codificação personalizada +**Robusto** - Validação integrada e tratamento de erros abrangente +**Manutenível** - A abordagem declarativa reduz a complexidade da implementação + +## Especificação da Linguagem + +O Descritor de Dados Estruturados usa um formato de configuração JSON com a seguinte estrutura de nível superior: + +```json +{ + "version": "1.0", + "metadata": { + "name": "Configuration Name", + "description": "Description of what this config does", + "author": "Author Name", + "created": "2024-01-01T00:00:00Z" + }, + "format": { ... }, + "globals": { ... }, + "preprocessing": [ ... ], + "mappings": [ ... ], + "postprocessing": [ ... ], + "output": { ... } +} +``` + +### Definição do Formato + +Descreve o formato dos dados de entrada e as opções de análise: + +```json +{ + "format": { + "type": "csv|json|xml|fixed-width|excel|parquet", + "encoding": "utf-8", + "options": { + // Format-specific options + } + } +} +``` + +#### Opções de Formato CSV +```json +{ + "format": { + "type": "csv", + "options": { + "delimiter": ",", + "quote_char": "\"", + "escape_char": "\\", + "skip_rows": 1, + "has_header": true, + "null_values": ["", "NULL", "null", "N/A"] + } + } +} +``` + +#### Opções de Formato JSON +```json +{ + "format": { + "type": "json", + "options": { + "root_path": "$.data", + "array_mode": "records|single", + "flatten": false + } + } +} +``` + +#### Opções de Formato XML +```json +{ + "format": { + "type": "xml", + "options": { + "root_element": "//records/record", + "namespaces": { + "ns": "http://example.com/namespace" + } + } + } +} +``` + +### Configurações Globais + +Defina tabelas de consulta, variáveis e configuração global: + +```json +{ + "globals": { + "variables": { + "current_date": "2024-01-01", + "batch_id": "BATCH_001", + "default_confidence": 0.8 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "UK": "United Kingdom", + "CA": "Canada" + }, + "status_mapping": { + "1": "active", + "0": "inactive" + } + }, + "constants": { + "source_system": "legacy_crm", + "import_type": "full" + } + } +} +``` + +### Mapeamentos de Campos + +Defina como os dados de origem são mapeados para os campos de destino, com transformações: + +```json +{ + "mappings": [ + { + "target_field": "person_name", + "source": "$.name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"}, + {"type": "required"} + ], + "validation": [ + {"type": "min_length", "value": 2}, + {"type": "max_length", "value": 100}, + {"type": "pattern", "value": "^[A-Za-z\\s]+$"} + ] + }, + { + "target_field": "age", + "source": "$.age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 150} + ] + }, + { + "target_field": "country", + "source": "$.country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ] +} +``` + +### Tipos de Transformação + +Funções de transformação disponíveis: + +#### Transformações de String +```json +{"type": "trim"}, +{"type": "upper"}, +{"type": "lower"}, +{"type": "title_case"}, +{"type": "replace", "pattern": "old", "replacement": "new"}, +{"type": "regex_replace", "pattern": "\\d+", "replacement": "XXX"}, +{"type": "substring", "start": 0, "end": 10}, +{"type": "pad_left", "length": 10, "char": "0"} +``` + +#### Conversões de Tipo +```json +{"type": "to_string"}, +{"type": "to_int"}, +{"type": "to_float"}, +{"type": "to_bool"}, +{"type": "to_date", "format": "YYYY-MM-DD"}, +{"type": "parse_json"} +``` + +#### Operações com Dados +```json +{"type": "default", "value": "default_value"}, +{"type": "lookup", "table": "table_name"}, +{"type": "concat", "values": ["field1", " - ", "field2"]}, +{"type": "calculate", "expression": "${field1} + ${field2}"}, +{"type": "conditional", "condition": "${age} > 18", "true_value": "adult", "false_value": "minor"} +``` + +### Regras de Validação + +Verificações de qualidade de dados com tratamento de erros configurável: + +#### Validações Básicas +```json +{"type": "required"}, +{"type": "not_null"}, +{"type": "min_length", "value": 5}, +{"type": "max_length", "value": 100}, +{"type": "range", "min": 0, "max": 1000}, +{"type": "pattern", "value": "^[A-Z]{2,3}$"}, +{"type": "in_list", "values": ["active", "inactive", "pending"]} +``` + +#### Validações Personalizadas +```json +{ + "type": "custom", + "expression": "${age} >= 18 && ${country} == 'US'", + "message": "Must be 18+ and in US" +}, +{ + "type": "cross_field", + "fields": ["start_date", "end_date"], + "expression": "${start_date} < ${end_date}", + "message": "Start date must be before end date" +} +``` + +### Pré-processamento e pós-processamento + +Operações globais aplicadas antes/depois do mapeamento de campos: + +```json +{ + "preprocessing": [ + { + "type": "filter", + "condition": "${status} != 'deleted'" + }, + { + "type": "sort", + "field": "created_date", + "order": "asc" + } + ], + "postprocessing": [ + { + "type": "deduplicate", + "key_fields": ["email", "phone"] + }, + { + "type": "aggregate", + "group_by": ["country"], + "functions": { + "total_count": {"type": "count"}, + "avg_age": {"type": "avg", "field": "age"} + } + } + ] +} +``` + +### Configuração de Saída + +Defina como os dados processados devem ser enviados: + +```json +{ + "output": { + "format": "trustgraph-objects", + "schema_name": "person", + "options": { + "batch_size": 1000, + "confidence": 0.9, + "source_span_field": "raw_text", + "metadata": { + "source": "crm_import", + "version": "1.0" + } + }, + "error_handling": { + "on_validation_error": "skip|fail|log", + "on_transform_error": "skip|fail|default", + "max_errors": 100, + "error_output": "errors.json" + } + } +} +``` + +## Exemplo Completo + +```json +{ + "version": "1.0", + "metadata": { + "name": "Customer Import from CRM CSV", + "description": "Imports customer data from legacy CRM system", + "author": "Data Team", + "created": "2024-01-01T00:00:00Z" + }, + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true, + "skip_rows": 1 + } + }, + "globals": { + "variables": { + "import_date": "2024-01-01", + "default_confidence": 0.85 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "CA": "Canada", + "UK": "United Kingdom" + } + } + }, + "preprocessing": [ + { + "type": "filter", + "condition": "${status} == 'active'" + } + ], + "mappings": [ + { + "target_field": "full_name", + "source": "customer_name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"} + ], + "validation": [ + {"type": "required"}, + {"type": "min_length", "value": 2} + ] + }, + { + "target_field": "email", + "source": "email_address", + "transforms": [ + {"type": "trim"}, + {"type": "lower"} + ], + "validation": [ + {"type": "pattern", "value": "^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$"} + ] + }, + { + "target_field": "age", + "source": "age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 120} + ] + }, + { + "target_field": "country", + "source": "country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ], + "output": { + "format": "trustgraph-objects", + "schema_name": "customer", + "options": { + "confidence": "${default_confidence}", + "batch_size": 500 + }, + "error_handling": { + "on_validation_error": "log", + "max_errors": 50 + } + } +} +``` + +## Prompt de LLM para Geração de Descritores + +O seguinte prompt pode ser usado para que um LLM analise dados de amostra e gere uma configuração de descritores: + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +The descriptor should follow this specification: +- version: "1.0" +- metadata: Configuration name, description, author, and creation date +- format: Input format type and parsing options +- globals: Variables, lookup tables, and constants +- preprocessing: Filters and transformations applied before mapping +- mappings: Field-by-field mapping from source to target with transformations and validations +- postprocessing: Operations like deduplication or aggregation +- output: Target format and error handling configuration + +ANALYZE THE DATA: +1. Identify the format (CSV, JSON, XML, etc.) +2. Detect delimiters, encodings, and structure +3. Find data types for each field +4. Identify patterns and constraints +5. Look for fields that need cleaning or transformation +6. Find relationships between fields +7. Identify lookup opportunities (codes that map to values) +8. Detect required vs optional fields + +CREATE THE DESCRIPTOR: +For each field in the sample data: +- Map it to an appropriate target field name +- Add necessary transformations (trim, case conversion, type casting) +- Include appropriate validations (required, patterns, ranges) +- Set defaults for missing values + +Include preprocessing if needed: +- Filters to exclude invalid records +- Sorting requirements + +Include postprocessing if beneficial: +- Deduplication on key fields +- Aggregation for summary data + +Configure output for TrustGraph: +- format: "trustgraph-objects" +- schema_name: Based on the data entity type +- Appropriate error handling + +DATA SAMPLE: +[Insert data sample here] + +ADDITIONAL CONTEXT (optional): +- Target schema name: [if known] +- Business rules: [any specific requirements] +- Data quality issues to address: [known problems] + +Generate a complete, valid Structured Data Descriptor configuration that will properly import this data into TrustGraph. Include comments explaining key decisions. +``` + +### Exemplo de Uso (Prompt) + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +[Standard instructions from above...] + +DATA SAMPLE: +```csv +CustomerID,Nome,Email,Idade,País,Status,Data de Adesão,Total de Compras +1001,"Smith, John",john.smith@email.com,35,US,1,2023-01-15,5420.50 +1002,"doe, jane",JANE.DOE@GMAIL.COM,28,CA,1,2023-03-22,3200.00 +1003,"Bob Johnson",bob@,62,UK,0,2022-11-01,0 +1004,"Alice Chen","alice.chen@company.org",41,US,1,2023-06-10,8900.25 +1005,,invalid-email,25,XX,1,2024-01-01,100 +``` + +ADDITIONAL CONTEXT: +- Target schema name: customer +- Business rules: Email should be valid and lowercase, names should be title case +- Data quality issues: Some emails are invalid, some names are missing, country codes need mapping +``` + +### Solicitação para Análise de Dados Existentes Sem Amostra + +``` +I need you to help me create a Structured Data Descriptor configuration for importing [data type] data. + +The source data has these characteristics: +- Format: [CSV/JSON/XML/etc] +- Fields: [list the fields] +- Data quality issues: [describe any known issues] +- Volume: [approximate number of records] + +Requirements: +- [List any specific transformation needs] +- [List any validation requirements] +- [List any business rules] + +Please generate a Structured Data Descriptor configuration that will: +1. Parse the input format correctly +2. Clean and standardize the data +3. Validate according to the requirements +4. Handle errors gracefully +5. Output in TrustGraph ExtractedObject format + +Focus on making the configuration robust and reusable. +``` \ No newline at end of file diff --git a/docs/tech-specs/structured-data-descriptor.ru.md b/docs/tech-specs/structured-data-descriptor.ru.md new file mode 100644 index 00000000..525c17c7 --- /dev/null +++ b/docs/tech-specs/structured-data-descriptor.ru.md @@ -0,0 +1,559 @@ +# Спецификация дескриптора структурированных данных + +## Обзор + +Дескриптор структурированных данных - это язык конфигурации на основе JSON, который описывает, как анализировать, преобразовывать и импортировать структурированные данные в TrustGraph. Он предоставляет декларативный подход к импорту данных, поддерживающий различные форматы входных данных и сложные конвейеры преобразований без необходимости написания пользовательского кода. + +## Основные понятия + +### 1. Определение формата +Описывает тип входного файла и параметры анализа. Определяет, какой анализатор использовать и как интерпретировать исходные данные. + +### 2. Отображения полей +Отображает пути источника на целевые поля с преобразованиями. Определяет, как данные передаются из исходных источников в поля выходной схемы. + +### 3. Конвейер преобразований +Цепочка преобразований данных, которые могут быть применены к значениям полей, включая: +Очистка данных (удаление лишних пробелов, нормализация) +Преобразование формата (разбор дат, приведение типов) +Вычисления (арифметические операции, манипуляции со строками) +Поиск (таблицы ссылок, замены) + +### 4. Правила проверки +Проверки качества данных, применяемые для обеспечения целостности данных: +Проверка типов +Проверки диапазонов +Сопоставление с образцом (регулярные выражения) +Проверка обязательных полей +Пользовательская логика проверки + +### 5. Глобальные настройки +Конфигурация, применяемая ко всему процессу импорта: +Таблицы поиска для обогащения данных +Глобальные переменные и константы +Спецификации формата вывода +Политики обработки ошибок + +## Стратегия реализации + +Реализация импортера следует следующей схеме: + +1. **Анализ конфигурации** - Загрузка и проверка JSON-дескриптора +2. **Инициализация анализатора** - Загрузка соответствующего анализатора (CSV, XML, JSON и т.д.) на основе `format.type` +3. **Применение предварительной обработки** - Выполнение глобальных фильтров и преобразований +4. **Обработка записей** - Для каждой входной записи: + Извлечение данных с использованием путей источника (JSONPath, XPath, имена столбцов) + Применение преобразований на уровне поля в последовательности + Проверка результатов на соответствие определенным правилам + Применение значений по умолчанию для отсутствующих данных +5. **Применение постобработки** - Выполнение дедупликации, агрегации и т.д. +6. **Генерация вывода** - Создание данных в указанном целевом формате + +## Поддержка выражений путей + +Различные форматы входных данных используют соответствующие языки выражений путей: + +**CSV**: Имена столбцов или индексы (`"column_name"` или `"[2]"`) +**JSON**: Синтаксис JSONPath (`"$.user.profile.email"`) +**XML**: Выражения XPath (`"//product[@id='123']/price"`) +**Fixed-width**: Имена полей из определений полей + +## Преимущества + +**Единая кодовая база** - Один импортер обрабатывает несколько форматов входных данных +**Удобство использования** - Пользователи, не являющиеся специалистами, могут создавать конфигурации +**Повторное использование** - Конфигурации можно обмениваться и версионировать +**Гибкость** - Сложные преобразования без пользовательского кода +**Надежность** - Встроенная проверка и комплексная обработка ошибок +**Поддерживаемость** - Декларативный подход снижает сложность реализации + +## Спецификация языка + +Дескриптор структурированных данных использует формат конфигурации JSON со следующей структурой верхнего уровня: + +```json +{ + "version": "1.0", + "metadata": { + "name": "Configuration Name", + "description": "Description of what this config does", + "author": "Author Name", + "created": "2024-01-01T00:00:00Z" + }, + "format": { ... }, + "globals": { ... }, + "preprocessing": [ ... ], + "mappings": [ ... ], + "postprocessing": [ ... ], + "output": { ... } +} +``` + +### Определение формата + +Описывает формат входных данных и параметры разбора: + +```json +{ + "format": { + "type": "csv|json|xml|fixed-width|excel|parquet", + "encoding": "utf-8", + "options": { + // Format-specific options + } + } +} +``` + +#### Варианты формата CSV +```json +{ + "format": { + "type": "csv", + "options": { + "delimiter": ",", + "quote_char": "\"", + "escape_char": "\\", + "skip_rows": 1, + "has_header": true, + "null_values": ["", "NULL", "null", "N/A"] + } + } +} +``` + +#### Варианты формата JSON +```json +{ + "format": { + "type": "json", + "options": { + "root_path": "$.data", + "array_mode": "records|single", + "flatten": false + } + } +} +``` + +#### Варианты формата XML +```json +{ + "format": { + "type": "xml", + "options": { + "root_element": "//records/record", + "namespaces": { + "ns": "http://example.com/namespace" + } + } + } +} +``` + +### Глобальные настройки + +Определите таблицы поиска, переменные и глобальную конфигурацию: + +```json +{ + "globals": { + "variables": { + "current_date": "2024-01-01", + "batch_id": "BATCH_001", + "default_confidence": 0.8 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "UK": "United Kingdom", + "CA": "Canada" + }, + "status_mapping": { + "1": "active", + "0": "inactive" + } + }, + "constants": { + "source_system": "legacy_crm", + "import_type": "full" + } + } +} +``` + +### Отображение полей + +Определите, как исходные данные сопоставляются с целевыми полями с использованием преобразований: + +```json +{ + "mappings": [ + { + "target_field": "person_name", + "source": "$.name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"}, + {"type": "required"} + ], + "validation": [ + {"type": "min_length", "value": 2}, + {"type": "max_length", "value": 100}, + {"type": "pattern", "value": "^[A-Za-z\\s]+$"} + ] + }, + { + "target_field": "age", + "source": "$.age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 150} + ] + }, + { + "target_field": "country", + "source": "$.country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ] +} +``` + +### Типы преобразований + +Доступные функции преобразования: + +#### Преобразования строк +```json +{"type": "trim"}, +{"type": "upper"}, +{"type": "lower"}, +{"type": "title_case"}, +{"type": "replace", "pattern": "old", "replacement": "new"}, +{"type": "regex_replace", "pattern": "\\d+", "replacement": "XXX"}, +{"type": "substring", "start": 0, "end": 10}, +{"type": "pad_left", "length": 10, "char": "0"} +``` + +#### Преобразования типов +```json +{"type": "to_string"}, +{"type": "to_int"}, +{"type": "to_float"}, +{"type": "to_bool"}, +{"type": "to_date", "format": "YYYY-MM-DD"}, +{"type": "parse_json"} +``` + +#### Операции с данными +```json +{"type": "default", "value": "default_value"}, +{"type": "lookup", "table": "table_name"}, +{"type": "concat", "values": ["field1", " - ", "field2"]}, +{"type": "calculate", "expression": "${field1} + ${field2}"}, +{"type": "conditional", "condition": "${age} > 18", "true_value": "adult", "false_value": "minor"} +``` + +### Правила проверки + +Проверки качества данных с настраиваемой обработкой ошибок: + +#### Базовые проверки +```json +{"type": "required"}, +{"type": "not_null"}, +{"type": "min_length", "value": 5}, +{"type": "max_length", "value": 100}, +{"type": "range", "min": 0, "max": 1000}, +{"type": "pattern", "value": "^[A-Z]{2,3}$"}, +{"type": "in_list", "values": ["active", "inactive", "pending"]} +``` + +#### Пользовательские проверки +```json +{ + "type": "custom", + "expression": "${age} >= 18 && ${country} == 'US'", + "message": "Must be 18+ and in US" +}, +{ + "type": "cross_field", + "fields": ["start_date", "end_date"], + "expression": "${start_date} < ${end_date}", + "message": "Start date must be before end date" +} +``` + +### Предварительная обработка и постобработка + +Глобальные операции, применяемые до/после сопоставления полей: + +```json +{ + "preprocessing": [ + { + "type": "filter", + "condition": "${status} != 'deleted'" + }, + { + "type": "sort", + "field": "created_date", + "order": "asc" + } + ], + "postprocessing": [ + { + "type": "deduplicate", + "key_fields": ["email", "phone"] + }, + { + "type": "aggregate", + "group_by": ["country"], + "functions": { + "total_count": {"type": "count"}, + "avg_age": {"type": "avg", "field": "age"} + } + } + ] +} +``` + +### Настройка вывода + +Определите, как обработанные данные должны быть выведены: + +```json +{ + "output": { + "format": "trustgraph-objects", + "schema_name": "person", + "options": { + "batch_size": 1000, + "confidence": 0.9, + "source_span_field": "raw_text", + "metadata": { + "source": "crm_import", + "version": "1.0" + } + }, + "error_handling": { + "on_validation_error": "skip|fail|log", + "on_transform_error": "skip|fail|default", + "max_errors": 100, + "error_output": "errors.json" + } + } +} +``` + +## Полный пример + +```json +{ + "version": "1.0", + "metadata": { + "name": "Customer Import from CRM CSV", + "description": "Imports customer data from legacy CRM system", + "author": "Data Team", + "created": "2024-01-01T00:00:00Z" + }, + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true, + "skip_rows": 1 + } + }, + "globals": { + "variables": { + "import_date": "2024-01-01", + "default_confidence": 0.85 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "CA": "Canada", + "UK": "United Kingdom" + } + } + }, + "preprocessing": [ + { + "type": "filter", + "condition": "${status} == 'active'" + } + ], + "mappings": [ + { + "target_field": "full_name", + "source": "customer_name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"} + ], + "validation": [ + {"type": "required"}, + {"type": "min_length", "value": 2} + ] + }, + { + "target_field": "email", + "source": "email_address", + "transforms": [ + {"type": "trim"}, + {"type": "lower"} + ], + "validation": [ + {"type": "pattern", "value": "^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$"} + ] + }, + { + "target_field": "age", + "source": "age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 120} + ] + }, + { + "target_field": "country", + "source": "country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ], + "output": { + "format": "trustgraph-objects", + "schema_name": "customer", + "options": { + "confidence": "${default_confidence}", + "batch_size": 500 + }, + "error_handling": { + "on_validation_error": "log", + "max_errors": 50 + } + } +} +``` + +## Подсказка для LLM для генерации описаний + +Следующую подсказку можно использовать, чтобы LLM проанализировал примеры данных и сгенерировал конфигурацию описания: + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +The descriptor should follow this specification: +- version: "1.0" +- metadata: Configuration name, description, author, and creation date +- format: Input format type and parsing options +- globals: Variables, lookup tables, and constants +- preprocessing: Filters and transformations applied before mapping +- mappings: Field-by-field mapping from source to target with transformations and validations +- postprocessing: Operations like deduplication or aggregation +- output: Target format and error handling configuration + +ANALYZE THE DATA: +1. Identify the format (CSV, JSON, XML, etc.) +2. Detect delimiters, encodings, and structure +3. Find data types for each field +4. Identify patterns and constraints +5. Look for fields that need cleaning or transformation +6. Find relationships between fields +7. Identify lookup opportunities (codes that map to values) +8. Detect required vs optional fields + +CREATE THE DESCRIPTOR: +For each field in the sample data: +- Map it to an appropriate target field name +- Add necessary transformations (trim, case conversion, type casting) +- Include appropriate validations (required, patterns, ranges) +- Set defaults for missing values + +Include preprocessing if needed: +- Filters to exclude invalid records +- Sorting requirements + +Include postprocessing if beneficial: +- Deduplication on key fields +- Aggregation for summary data + +Configure output for TrustGraph: +- format: "trustgraph-objects" +- schema_name: Based on the data entity type +- Appropriate error handling + +DATA SAMPLE: +[Insert data sample here] + +ADDITIONAL CONTEXT (optional): +- Target schema name: [if known] +- Business rules: [any specific requirements] +- Data quality issues to address: [known problems] + +Generate a complete, valid Structured Data Descriptor configuration that will properly import this data into TrustGraph. Include comments explaining key decisions. +``` + +### Пример использования запроса + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +[Standard instructions from above...] + +DATA SAMPLE: +```csv +CustomerID,Имя,Электронная почта,Возраст,Страна,Статус,Дата присоединения,Общая сумма покупок +1001,"Smith, John",john.smith@email.com,35,US,1,2023-01-15,5420.50 +1002,"doe, jane",JANE.DOE@GMAIL.COM,28,CA,1,2023-03-22,3200.00 +1003,"Bob Johnson",bob@,62,UK,0,2022-11-01,0 +1004,"Alice Chen","alice.chen@company.org",41,US,1,2023-06-10,8900.25 +1005,,invalid-email,25,XX,1,2024-01-01,100 +``` + +ADDITIONAL CONTEXT: +- Target schema name: customer +- Business rules: Email should be valid and lowercase, names should be title case +- Data quality issues: Some emails are invalid, some names are missing, country codes need mapping +``` + +### Запрос на анализ существующих данных без использования образцов + +``` +I need you to help me create a Structured Data Descriptor configuration for importing [data type] data. + +The source data has these characteristics: +- Format: [CSV/JSON/XML/etc] +- Fields: [list the fields] +- Data quality issues: [describe any known issues] +- Volume: [approximate number of records] + +Requirements: +- [List any specific transformation needs] +- [List any validation requirements] +- [List any business rules] + +Please generate a Structured Data Descriptor configuration that will: +1. Parse the input format correctly +2. Clean and standardize the data +3. Validate according to the requirements +4. Handle errors gracefully +5. Output in TrustGraph ExtractedObject format + +Focus on making the configuration robust and reusable. +``` \ No newline at end of file diff --git a/docs/tech-specs/structured-data-descriptor.sw.md b/docs/tech-specs/structured-data-descriptor.sw.md new file mode 100644 index 00000000..afe83b70 --- /dev/null +++ b/docs/tech-specs/structured-data-descriptor.sw.md @@ -0,0 +1,559 @@ +# Maelezo ya Muundo wa Data + +## Muhtasari + +Maelezo ya Muundo wa Data ni lugha ya usanidi iliyo msingi ya JSON ambayo inaeleza jinsi ya kuchanganua, kubadilisha, na kuingiza data iliyo na muundo katika TrustGraph. Inatoa njia ya matangazo ya jinsi ya kuingiza data, ikisaidia aina tofauti za pembejeo na mnyororo mgumu wa mabadiliko bila kuhitaji nambari maalum. + +## Dhana Muhimu + +### 1. Ufafanuzi wa Aina +Inaeleza aina ya faili ya pembejeo na chaguzi za kuchanganua. Inaamua kichanganuzi gani cha kutumia na jinsi ya kutafsiri data ya chanzo. + +### 2. Ramani za Uwanja +Inaunganisha njia za chanzo na uwanja wa lengo pamoja na mabadiliko. Inaeleza jinsi data inavyosonga kutoka kwa vyanzo vya pembejeo hadi kwenye uwanja wa schema ya pato. + +### 3. Mnyororo wa Mabadiliko +Mnyororo wa mabadiliko ya data ambayo yanaweza kutumika kwenye thamani za uwanja, pamoja na: +Usafishaji wa data (kukata, kusawazisha) +Ubadilishaji wa aina (uchanganuzi wa tarehe, ubadilishaji wa aina) +Hesabu (hesabu, urekebishaji wa maandishi) +Utafiti (meza za rejea, mbadala) + +### 4. Kanuni za Uthibitisho +Vipimo vya ubora wa data ambavyo hutumika kuhakikisha uadilifu wa data: +Uthibitisho wa aina +Vipimo vya anuwai +Ulinganishi wa muundo (regex) +Uthibitisho wa uwanja unaohitajika +Mantiki ya uthibitisho maalum + +### 5. Mpangilio wa Jumla +Mpangilio ambao hutumika katika mchakato wote wa uingizaji: +Meza za utafiti kwa uboreshaji wa data +Vigezo na mara kwa mara vya kimataifa +Maelezo ya muundo wa pato +Sera za kushughulikia makosa + +## Mkakati wa Utendaji + +Utendaji wa programu ya uingizaji unafuata mnyororo huu: + +1. **Changanua Mpangilio** - Pakia na thibitisha maelezo ya JSON +2. **Anzisha Kichanganuzi** - Pakia kichanganuzi kinachofaa (CSV, XML, JSON, n.k.) kulingana na `format.type` +3. **Tumia Uchujaji wa Awali** - Fanya vichujio na mabadiliko ya kimataifa +4. **Chakata Rekodi** - Kwa kila rekodi ya pembejeo: + Toa data ukitumia njia za chanzo (JSONPath, XPath, majina ya safu) + Tumia mabadiliko ya kiwanja kwa mlolongo + Thibitisha matokeo dhidi ya sheria zilizoelezwa + Tumia maadili chaguu kwa data inayokosekana +5. **Tumia Uchakataji wa Baada** - Fanya uondoaji mara mbili, ukusanyaji, n.k. +6. **Toa Pato** - Toa data katika muundo wa lengo uliotakikana + +## Usaidizi wa Maneno ya Njia + +Aina tofauti za pembejeo hutumia lugha zinazofaa za maneno ya njia: + +**CSV**: Majina ya safu au fahirisi (`"column_name"` au `"[2]"`) +**JSON**: Lugha ya JSONPath (`"$.user.profile.email"`) +**XML**: Maneno ya XPath (`"//product[@id='123']/price"`) +**Upana-uliofanyika**: Majina ya uwanja kutoka maelezo ya uwanja + +## Faida + +**Nambari Moja** - Programu moja ya uingizaji inashughulikia aina tofauti za pembejeo +**Inafaa kwa Mtumiaji** - Watumiaji ambao hawana ujuzi wa kiufundi wanaweza kuunda mipangilio +**Inaweza Kurejeshwa** - Mipangilio inaweza kushirikiwa na kutolewa toleo +**Inafaa** - Mabadiliko magumu bila nambari maalum +**Imara** - Uthibitisho uliounganishwa na utunzaji wa kina wa makosa +**Inaweza Kudumishwa** - Njia ya matangazo hupunguza utata wa utekelezaji + +## Maelezo ya Lugha + +Maelezo ya Muundo wa Data hutumia muundo wa usanidi wa JSON na muundo wa juu unaofuata: + +```json +{ + "version": "1.0", + "metadata": { + "name": "Configuration Name", + "description": "Description of what this config does", + "author": "Author Name", + "created": "2024-01-01T00:00:00Z" + }, + "format": { ... }, + "globals": { ... }, + "preprocessing": [ ... ], + "mappings": [ ... ], + "postprocessing": [ ... ], + "output": { ... } +} +``` + +### Ufafanuzi wa Muundo + +Huainisha muundo wa data ya pembejeo na chaguo za uchakataji: + +```json +{ + "format": { + "type": "csv|json|xml|fixed-width|excel|parquet", + "encoding": "utf-8", + "options": { + // Format-specific options + } + } +} +``` + +#### Chaguo za Muundo wa CSV +```json +{ + "format": { + "type": "csv", + "options": { + "delimiter": ",", + "quote_char": "\"", + "escape_char": "\\", + "skip_rows": 1, + "has_header": true, + "null_values": ["", "NULL", "null", "N/A"] + } + } +} +``` + +#### Chaguo za Muundo wa JSON +```json +{ + "format": { + "type": "json", + "options": { + "root_path": "$.data", + "array_mode": "records|single", + "flatten": false + } + } +} +``` + +#### Chaguo za Muundo wa XML +```json +{ + "format": { + "type": "xml", + "options": { + "root_element": "//records/record", + "namespaces": { + "ns": "http://example.com/namespace" + } + } + } +} +``` + +### Mipangilio ya Ulimwengu + +Fafanua jedwali za utafutaji, vigezo, na usanidi wa jumla: + +```json +{ + "globals": { + "variables": { + "current_date": "2024-01-01", + "batch_id": "BATCH_001", + "default_confidence": 0.8 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "UK": "United Kingdom", + "CA": "Canada" + }, + "status_mapping": { + "1": "active", + "0": "inactive" + } + }, + "constants": { + "source_system": "legacy_crm", + "import_type": "full" + } + } +} +``` + +### Ramani za Vyanzo vya Habari + +Eleza jinsi data kutoka chanzo inavyolingana na vyanzo vya habari vya lengo, pamoja na mabadiliko: + +```json +{ + "mappings": [ + { + "target_field": "person_name", + "source": "$.name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"}, + {"type": "required"} + ], + "validation": [ + {"type": "min_length", "value": 2}, + {"type": "max_length", "value": 100}, + {"type": "pattern", "value": "^[A-Za-z\\s]+$"} + ] + }, + { + "target_field": "age", + "source": "$.age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 150} + ] + }, + { + "target_field": "country", + "source": "$.country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ] +} +``` + +### Aina za Ubadilishaji + +Kazi zinazopatikana za kubadilisha: + +#### Ubadilishaji wa Mfumo wa Herufi +```json +{"type": "trim"}, +{"type": "upper"}, +{"type": "lower"}, +{"type": "title_case"}, +{"type": "replace", "pattern": "old", "replacement": "new"}, +{"type": "regex_replace", "pattern": "\\d+", "replacement": "XXX"}, +{"type": "substring", "start": 0, "end": 10}, +{"type": "pad_left", "length": 10, "char": "0"} +``` + +#### Tafsiri za Aina +```json +{"type": "to_string"}, +{"type": "to_int"}, +{"type": "to_float"}, +{"type": "to_bool"}, +{"type": "to_date", "format": "YYYY-MM-DD"}, +{"type": "parse_json"} +``` + +#### Operesheni za Data +```json +{"type": "default", "value": "default_value"}, +{"type": "lookup", "table": "table_name"}, +{"type": "concat", "values": ["field1", " - ", "field2"]}, +{"type": "calculate", "expression": "${field1} + ${field2}"}, +{"type": "conditional", "condition": "${age} > 18", "true_value": "adult", "false_value": "minor"} +``` + +### Kanuni za Uthibitisho + +Uchunguzi wa ubora wa data pamoja na udhibiti wa makosa unaoweza kusanidiwa: + +### Uthibitisho Msingi +```json +{"type": "required"}, +{"type": "not_null"}, +{"type": "min_length", "value": 5}, +{"type": "max_length", "value": 100}, +{"type": "range", "min": 0, "max": 1000}, +{"type": "pattern", "value": "^[A-Z]{2,3}$"}, +{"type": "in_list", "values": ["active", "inactive", "pending"]} +``` + +#### Uthibitisho Maalum +```json +{ + "type": "custom", + "expression": "${age} >= 18 && ${country} == 'US'", + "message": "Must be 18+ and in US" +}, +{ + "type": "cross_field", + "fields": ["start_date", "end_date"], + "expression": "${start_date} < ${end_date}", + "message": "Start date must be before end date" +} +``` + +### Maandalizi na Urekebishaji + +Operesheni za jumla zinazotumiwa kabla na baada ya uhamishaji wa data: + +```json +{ + "preprocessing": [ + { + "type": "filter", + "condition": "${status} != 'deleted'" + }, + { + "type": "sort", + "field": "created_date", + "order": "asc" + } + ], + "postprocessing": [ + { + "type": "deduplicate", + "key_fields": ["email", "phone"] + }, + { + "type": "aggregate", + "group_by": ["country"], + "functions": { + "total_count": {"type": "count"}, + "avg_age": {"type": "avg", "field": "age"} + } + } + ] +} +``` + +### Usanidi wa Matokeo + +Eleza jinsi data iliyochakatwa inapaswa kuonyeshwa: + +```json +{ + "output": { + "format": "trustgraph-objects", + "schema_name": "person", + "options": { + "batch_size": 1000, + "confidence": 0.9, + "source_span_field": "raw_text", + "metadata": { + "source": "crm_import", + "version": "1.0" + } + }, + "error_handling": { + "on_validation_error": "skip|fail|log", + "on_transform_error": "skip|fail|default", + "max_errors": 100, + "error_output": "errors.json" + } + } +} +``` + +## Mfano Kamili + +```json +{ + "version": "1.0", + "metadata": { + "name": "Customer Import from CRM CSV", + "description": "Imports customer data from legacy CRM system", + "author": "Data Team", + "created": "2024-01-01T00:00:00Z" + }, + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true, + "skip_rows": 1 + } + }, + "globals": { + "variables": { + "import_date": "2024-01-01", + "default_confidence": 0.85 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "CA": "Canada", + "UK": "United Kingdom" + } + } + }, + "preprocessing": [ + { + "type": "filter", + "condition": "${status} == 'active'" + } + ], + "mappings": [ + { + "target_field": "full_name", + "source": "customer_name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"} + ], + "validation": [ + {"type": "required"}, + {"type": "min_length", "value": 2} + ] + }, + { + "target_field": "email", + "source": "email_address", + "transforms": [ + {"type": "trim"}, + {"type": "lower"} + ], + "validation": [ + {"type": "pattern", "value": "^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$"} + ] + }, + { + "target_field": "age", + "source": "age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 120} + ] + }, + { + "target_field": "country", + "source": "country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ], + "output": { + "format": "trustgraph-objects", + "schema_name": "customer", + "options": { + "confidence": "${default_confidence}", + "batch_size": 500 + }, + "error_handling": { + "on_validation_error": "log", + "max_errors": 50 + } + } +} +``` + +## Maagizo ya LLM kwa Ajili ya Uundaji wa Maelezo + +Maagizo yafuatayo yanaweza kutumika ili LLM iweze kuchanganua data ya mfano na kuunda usanidi wa maelezo: + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +The descriptor should follow this specification: +- version: "1.0" +- metadata: Configuration name, description, author, and creation date +- format: Input format type and parsing options +- globals: Variables, lookup tables, and constants +- preprocessing: Filters and transformations applied before mapping +- mappings: Field-by-field mapping from source to target with transformations and validations +- postprocessing: Operations like deduplication or aggregation +- output: Target format and error handling configuration + +ANALYZE THE DATA: +1. Identify the format (CSV, JSON, XML, etc.) +2. Detect delimiters, encodings, and structure +3. Find data types for each field +4. Identify patterns and constraints +5. Look for fields that need cleaning or transformation +6. Find relationships between fields +7. Identify lookup opportunities (codes that map to values) +8. Detect required vs optional fields + +CREATE THE DESCRIPTOR: +For each field in the sample data: +- Map it to an appropriate target field name +- Add necessary transformations (trim, case conversion, type casting) +- Include appropriate validations (required, patterns, ranges) +- Set defaults for missing values + +Include preprocessing if needed: +- Filters to exclude invalid records +- Sorting requirements + +Include postprocessing if beneficial: +- Deduplication on key fields +- Aggregation for summary data + +Configure output for TrustGraph: +- format: "trustgraph-objects" +- schema_name: Based on the data entity type +- Appropriate error handling + +DATA SAMPLE: +[Insert data sample here] + +ADDITIONAL CONTEXT (optional): +- Target schema name: [if known] +- Business rules: [any specific requirements] +- Data quality issues to address: [known problems] + +Generate a complete, valid Structured Data Descriptor configuration that will properly import this data into TrustGraph. Include comments explaining key decisions. +``` + +### Mfano wa Matumizi + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +[Standard instructions from above...] + +DATA SAMPLE: +```csv +Kitambulisho cha Mteja,Jina,Barua pepe,Umri,Nchi,Hali,Tarehe ya Kujiunga,Ununuzi Jumla +1001,"Smith, John",john.smith@email.com,35,US,1,2023-01-15,5420.50 +1002,"doe, jane",JANE.DOE@GMAIL.COM,28,CA,1,2023-03-22,3200.00 +1003,"Bob Johnson",bob@,62,UK,0,2022-11-01,0 +1004,"Alice Chen","alice.chen@company.org",41,US,1,2023-06-10,8900.25 +1005,,invalid-email,25,XX,1,2024-01-01,100 +``` + +ADDITIONAL CONTEXT: +- Target schema name: customer +- Business rules: Email should be valid and lowercase, names should be title case +- Data quality issues: Some emails are invalid, some names are missing, country codes need mapping +``` + +### Ombi la Kuchanganua Data Zilizopo Bila Sampuli + +``` +I need you to help me create a Structured Data Descriptor configuration for importing [data type] data. + +The source data has these characteristics: +- Format: [CSV/JSON/XML/etc] +- Fields: [list the fields] +- Data quality issues: [describe any known issues] +- Volume: [approximate number of records] + +Requirements: +- [List any specific transformation needs] +- [List any validation requirements] +- [List any business rules] + +Please generate a Structured Data Descriptor configuration that will: +1. Parse the input format correctly +2. Clean and standardize the data +3. Validate according to the requirements +4. Handle errors gracefully +5. Output in TrustGraph ExtractedObject format + +Focus on making the configuration robust and reusable. +``` \ No newline at end of file diff --git a/docs/tech-specs/structured-data-descriptor.tr.md b/docs/tech-specs/structured-data-descriptor.tr.md new file mode 100644 index 00000000..27aad454 --- /dev/null +++ b/docs/tech-specs/structured-data-descriptor.tr.md @@ -0,0 +1,559 @@ +# Yapılandırılmış Veri Tanımlayıcı Özellikleri + +## Genel Bakış + +Yapılandırılmış Veri Tanımlayıcı, JSON tabanlı bir yapılandırma dilidir ve TrustGraph'a yapılandırılmış verilerin nasıl ayrıştırıldığı, dönüştürüldüğü ve içe aktarıldığını tanımlar. Veri içe aktarma için deklaratif bir yaklaşım sunar, çoklu giriş formatlarını ve özel kod gerektirmeden karmaşık dönüşüm süreçlerini destekler. + +## Temel Kavramlar + +### 1. Format Tanımı +Giriş dosya türünü ve ayrıştırma seçeneklerini tanımlar. Hangi ayrıştırıcının kullanılacağını ve kaynak verilerin nasıl yorumlanacağını belirler. + +### 2. Alan Eşlemeleri +Kaynak yollarını hedef alanlarla dönüşümlerle eşler. Verilerin kaynaklardan çıktı şema alanlarına nasıl aktığını tanımlar. + +### 3. Dönüşüm Süreci +Alan değerlerine uygulanabilecek veri dönüşüm zinciri. Şunları içerir: +Veri temizleme (boşlukları kaldırma, normalleştirme) +Biçim dönüştürme (tarih ayrıştırma, tür dönüştürme) +Hesaplamalar (aritmetik işlemler, dize manipülasyonu) +Arama tabloları (referans tabloları, eşleştirmeler) + +### 4. Doğrulama Kuralları +Veri bütünlüğünü sağlamak için uygulanan veri kalitesi kontrolleri: +Tür doğrulama +Aralık kontrolleri +Desen eşleştirme (regex) +Gerekli alan doğrulama +Özel doğrulama mantığı + +### 5. Genel Ayarlar +Tüm içe aktarma sürecine uygulanan yapılandırma: +Veri zenginleştirme için arama tabloları +Küresel değişkenler ve sabitler +Çıktı biçimi özellikleri +Hata işleme politikaları + +## Uygulama Stratejisi + +İçe aktarıcı uygulaması aşağıdaki süreci izler: + +1. **Yapılandırmayı Ayrıştır** - JSON tanımlayıcısını yükleyin ve doğrulayın +2. **Ayrıştırıcıyı Başlat** - `format.type`'a göre uygun ayrıştırıcıyı yükleyin (CSV, XML, JSON, vb.) +3. **Ön İşleme Uygula** - Küresel filtreleri ve dönüşümleri çalıştırın +4. **Kayıtları İşle** - Her giriş kaydı için: + Kaynak yollarını (JSONPath, XPath, sütun adları) kullanarak verileri çıkarın + Alan düzeyindeki dönüşümleri sırayla uygulayın + Sonuçları tanımlı kurallara göre doğrulayın + Eksik veriler için varsayılan değerleri uygulayın +5. **Son İşleme Uygula** - Tekilleştirme, birleştirme, vb. işlemlerini gerçekleştirin +6. **Çıktıyı Oluştur** - Verileri belirtilen hedef biçimde oluşturun + +## Yol İfadesi Desteği + +Farklı giriş formatları, uygun yol ifadesi dillerini kullanır: + +**CSV**: Sütun adları veya indeksler (`"column_name"` veya `"[2]"`) +**JSON**: JSONPath sözdizimi (`"$.user.profile.email"`) +**XML**: XPath ifadeleri (`"//product[@id='123']/price"`) +**Sabit genişlik**: Alan tanımlarından alan adları + +## Avantajlar + +**Tek Kod Tabanı** - Tek bir içe aktarıcı, çoklu giriş formatlarını işler +**Kullanıcı Dostu** - Teknik olmayan kullanıcılar, yapılandırmalar oluşturabilir +**Yeniden Kullanılabilir** - Yapılandırmalar paylaşılabilir ve sürüm kontrolüne tabi tutulabilir +**Esnek** - Özel kodlama olmadan karmaşık dönüşümler +**Sağlam** - Yerleşik doğrulama ve kapsamlı hata işleme +**Bakımı Kolay** - Deklaratif yaklaşım, uygulama karmaşıklığını azaltır + +## Dil Özellikleri + +Yapılandırılmış Veri Tanımlayıcı, aşağıdaki üst düzey yapıya sahip bir JSON yapılandırma biçimi kullanır: + +```json +{ + "version": "1.0", + "metadata": { + "name": "Configuration Name", + "description": "Description of what this config does", + "author": "Author Name", + "created": "2024-01-01T00:00:00Z" + }, + "format": { ... }, + "globals": { ... }, + "preprocessing": [ ... ], + "mappings": [ ... ], + "postprocessing": [ ... ], + "output": { ... } +} +``` + +### Biçim Tanımı + +Giriş verisi biçimini ve ayrıştırma seçeneklerini açıklar: + +```json +{ + "format": { + "type": "csv|json|xml|fixed-width|excel|parquet", + "encoding": "utf-8", + "options": { + // Format-specific options + } + } +} +``` + +#### CSV Format Seçenekleri +```json +{ + "format": { + "type": "csv", + "options": { + "delimiter": ",", + "quote_char": "\"", + "escape_char": "\\", + "skip_rows": 1, + "has_header": true, + "null_values": ["", "NULL", "null", "N/A"] + } + } +} +``` + +#### JSON Formatı Seçenekleri +```json +{ + "format": { + "type": "json", + "options": { + "root_path": "$.data", + "array_mode": "records|single", + "flatten": false + } + } +} +``` + +#### XML Formatı Seçenekleri +```json +{ + "format": { + "type": "xml", + "options": { + "root_element": "//records/record", + "namespaces": { + "ns": "http://example.com/namespace" + } + } + } +} +``` + +### Küresel Ayarlar + +Arama tablolarını, değişkenleri ve genel yapılandırmayı tanımlayın: + +```json +{ + "globals": { + "variables": { + "current_date": "2024-01-01", + "batch_id": "BATCH_001", + "default_confidence": 0.8 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "UK": "United Kingdom", + "CA": "Canada" + }, + "status_mapping": { + "1": "active", + "0": "inactive" + } + }, + "constants": { + "source_system": "legacy_crm", + "import_type": "full" + } + } +} +``` + +### Alan Eşlemeleri + +Dönüşümlerle birlikte kaynak verilerinin hedef alanlara nasıl eşlendiğini tanımlayın: + +```json +{ + "mappings": [ + { + "target_field": "person_name", + "source": "$.name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"}, + {"type": "required"} + ], + "validation": [ + {"type": "min_length", "value": 2}, + {"type": "max_length", "value": 100}, + {"type": "pattern", "value": "^[A-Za-z\\s]+$"} + ] + }, + { + "target_field": "age", + "source": "$.age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 150} + ] + }, + { + "target_field": "country", + "source": "$.country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ] +} +``` + +### Dönüşüm Türleri + +Kullanılabilir dönüşüm fonksiyonları: + +#### String Dönüşümleri +```json +{"type": "trim"}, +{"type": "upper"}, +{"type": "lower"}, +{"type": "title_case"}, +{"type": "replace", "pattern": "old", "replacement": "new"}, +{"type": "regex_replace", "pattern": "\\d+", "replacement": "XXX"}, +{"type": "substring", "start": 0, "end": 10}, +{"type": "pad_left", "length": 10, "char": "0"} +``` + +#### Tür Dönüşümleri +```json +{"type": "to_string"}, +{"type": "to_int"}, +{"type": "to_float"}, +{"type": "to_bool"}, +{"type": "to_date", "format": "YYYY-MM-DD"}, +{"type": "parse_json"} +``` + +#### Veri İşlemleri +```json +{"type": "default", "value": "default_value"}, +{"type": "lookup", "table": "table_name"}, +{"type": "concat", "values": ["field1", " - ", "field2"]}, +{"type": "calculate", "expression": "${field1} + ${field2}"}, +{"type": "conditional", "condition": "${age} > 18", "true_value": "adult", "false_value": "minor"} +``` + +### Doğrulama Kuralları + +Yapılandırılabilir hata yönetimi ile veri kalitesi kontrolleri: + +#### Temel Doğrulamalar +```json +{"type": "required"}, +{"type": "not_null"}, +{"type": "min_length", "value": 5}, +{"type": "max_length", "value": 100}, +{"type": "range", "min": 0, "max": 1000}, +{"type": "pattern", "value": "^[A-Z]{2,3}$"}, +{"type": "in_list", "values": ["active", "inactive", "pending"]} +``` + +#### Özel Doğrulamalar +```json +{ + "type": "custom", + "expression": "${age} >= 18 && ${country} == 'US'", + "message": "Must be 18+ and in US" +}, +{ + "type": "cross_field", + "fields": ["start_date", "end_date"], + "expression": "${start_date} < ${end_date}", + "message": "Start date must be before end date" +} +``` + +### Ön İşleme ve Son İşleme + +Alan eşlemesi öncesinde/sonrasında uygulanan genel işlemler: + +```json +{ + "preprocessing": [ + { + "type": "filter", + "condition": "${status} != 'deleted'" + }, + { + "type": "sort", + "field": "created_date", + "order": "asc" + } + ], + "postprocessing": [ + { + "type": "deduplicate", + "key_fields": ["email", "phone"] + }, + { + "type": "aggregate", + "group_by": ["country"], + "functions": { + "total_count": {"type": "count"}, + "avg_age": {"type": "avg", "field": "age"} + } + } + ] +} +``` + +### Çıktı Yapılandırması + +İşlenmiş verilerin nasıl çıktı olarak verilmesi gerektiğini tanımlayın: + +```json +{ + "output": { + "format": "trustgraph-objects", + "schema_name": "person", + "options": { + "batch_size": 1000, + "confidence": 0.9, + "source_span_field": "raw_text", + "metadata": { + "source": "crm_import", + "version": "1.0" + } + }, + "error_handling": { + "on_validation_error": "skip|fail|log", + "on_transform_error": "skip|fail|default", + "max_errors": 100, + "error_output": "errors.json" + } + } +} +``` + +## Tam Bir Örnek + +```json +{ + "version": "1.0", + "metadata": { + "name": "Customer Import from CRM CSV", + "description": "Imports customer data from legacy CRM system", + "author": "Data Team", + "created": "2024-01-01T00:00:00Z" + }, + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true, + "skip_rows": 1 + } + }, + "globals": { + "variables": { + "import_date": "2024-01-01", + "default_confidence": 0.85 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "CA": "Canada", + "UK": "United Kingdom" + } + } + }, + "preprocessing": [ + { + "type": "filter", + "condition": "${status} == 'active'" + } + ], + "mappings": [ + { + "target_field": "full_name", + "source": "customer_name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"} + ], + "validation": [ + {"type": "required"}, + {"type": "min_length", "value": 2} + ] + }, + { + "target_field": "email", + "source": "email_address", + "transforms": [ + {"type": "trim"}, + {"type": "lower"} + ], + "validation": [ + {"type": "pattern", "value": "^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$"} + ] + }, + { + "target_field": "age", + "source": "age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 120} + ] + }, + { + "target_field": "country", + "source": "country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ], + "output": { + "format": "trustgraph-objects", + "schema_name": "customer", + "options": { + "confidence": "${default_confidence}", + "batch_size": 500 + }, + "error_handling": { + "on_validation_error": "log", + "max_errors": 50 + } + } +} +``` + +## Açıklayıcı Oluşturma İçin LLM İstem + +Aşağıdaki istem, bir LLM'nin örnek verileri analiz etmesi ve bir açıklayıcı yapılandırma oluşturması için kullanılabilir: + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +The descriptor should follow this specification: +- version: "1.0" +- metadata: Configuration name, description, author, and creation date +- format: Input format type and parsing options +- globals: Variables, lookup tables, and constants +- preprocessing: Filters and transformations applied before mapping +- mappings: Field-by-field mapping from source to target with transformations and validations +- postprocessing: Operations like deduplication or aggregation +- output: Target format and error handling configuration + +ANALYZE THE DATA: +1. Identify the format (CSV, JSON, XML, etc.) +2. Detect delimiters, encodings, and structure +3. Find data types for each field +4. Identify patterns and constraints +5. Look for fields that need cleaning or transformation +6. Find relationships between fields +7. Identify lookup opportunities (codes that map to values) +8. Detect required vs optional fields + +CREATE THE DESCRIPTOR: +For each field in the sample data: +- Map it to an appropriate target field name +- Add necessary transformations (trim, case conversion, type casting) +- Include appropriate validations (required, patterns, ranges) +- Set defaults for missing values + +Include preprocessing if needed: +- Filters to exclude invalid records +- Sorting requirements + +Include postprocessing if beneficial: +- Deduplication on key fields +- Aggregation for summary data + +Configure output for TrustGraph: +- format: "trustgraph-objects" +- schema_name: Based on the data entity type +- Appropriate error handling + +DATA SAMPLE: +[Insert data sample here] + +ADDITIONAL CONTEXT (optional): +- Target schema name: [if known] +- Business rules: [any specific requirements] +- Data quality issues to address: [known problems] + +Generate a complete, valid Structured Data Descriptor configuration that will properly import this data into TrustGraph. Include comments explaining key decisions. +``` + +### Örnek Kullanım İsteği + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +[Standard instructions from above...] + +DATA SAMPLE: +```csv +MüşteriID,Ad,E-posta,Yaş,Ülke,Durum,KayıtTarihi,ToplamSatınAlımlar +1001,"Smith, John",john.smith@email.com,35,US,1,2023-01-15,5420.50 +1002,"doe, jane",JANE.DOE@GMAIL.COM,28,CA,1,2023-03-22,3200.00 +1003,"Bob Johnson",bob@,62,UK,0,2022-11-01,0 +1004,"Alice Chen","alice.chen@company.org",41,US,1,2023-06-10,8900.25 +1005,,invalid-email,25,XX,1,2024-01-01,100 +``` + +ADDITIONAL CONTEXT: +- Target schema name: customer +- Business rules: Email should be valid and lowercase, names should be title case +- Data quality issues: Some emails are invalid, some names are missing, country codes need mapping +``` + +### Mevcut Verileri Örnek Olmadan Analiz Etme İsteği + +``` +I need you to help me create a Structured Data Descriptor configuration for importing [data type] data. + +The source data has these characteristics: +- Format: [CSV/JSON/XML/etc] +- Fields: [list the fields] +- Data quality issues: [describe any known issues] +- Volume: [approximate number of records] + +Requirements: +- [List any specific transformation needs] +- [List any validation requirements] +- [List any business rules] + +Please generate a Structured Data Descriptor configuration that will: +1. Parse the input format correctly +2. Clean and standardize the data +3. Validate according to the requirements +4. Handle errors gracefully +5. Output in TrustGraph ExtractedObject format + +Focus on making the configuration robust and reusable. +``` \ No newline at end of file diff --git a/docs/tech-specs/structured-data-descriptor.zh-cn.md b/docs/tech-specs/structured-data-descriptor.zh-cn.md new file mode 100644 index 00000000..232110b4 --- /dev/null +++ b/docs/tech-specs/structured-data-descriptor.zh-cn.md @@ -0,0 +1,559 @@ +# 结构化数据描述符规范 + +## 概述 + +结构化数据描述符是一种基于 JSON 的配置语言,用于描述如何解析、转换和导入结构化数据到 TrustGraph 中。它提供了一种声明式的数据导入方法,支持多种输入格式和复杂的转换流程,而无需自定义代码。 + +## 核心概念 + +### 1. 格式定义 +描述输入文件类型和解析选项。确定要使用的解析器以及如何解释源数据。 + +### 2. 字段映射 +将源路径映射到目标字段,并进行转换。定义数据如何从输入源流向输出模式字段。 + +### 3. 转换流程 +一系列应用于字段值的转换,包括: +数据清洗(修剪、标准化) +格式转换(日期解析、类型转换) +计算(算术运算、字符串操作) +查找(引用表、替换) + +### 4. 验证规则 +应用于确保数据完整性的数据质量检查: +类型验证 +范围检查 +模式匹配(正则表达式) +必填字段验证 +自定义验证逻辑 + +### 5. 全局设置 +适用于整个导入过程的配置: +用于数据增强的查找表 +全局变量和常量 +输出格式规范 +错误处理策略 + +## 实施策略 + +导入器的实现遵循以下流程: + +1. **解析配置** - 加载和验证 JSON 描述符 +2. **初始化解析器** - 根据 `format.type` 加载适当的解析器(CSV、XML、JSON 等) +3. **应用预处理** - 执行全局过滤器和转换 +4. **处理记录** - 对于每个输入记录: + 使用源路径(JSONPath、XPath、列名)提取数据 + 按照顺序应用字段级别的转换 + 根据定义的规则验证结果 + 为缺失数据应用默认值 +5. **应用后处理** - 执行去重、聚合等操作 +6. **生成输出** - 以指定的目标格式生成数据 + +## 路径表达式支持 + +不同的输入格式使用适当的路径表达式语言: + +**CSV**: 列名或索引(`"column_name"` 或 `"[2]"`) +**JSON**: JSONPath 语法(`"$.user.profile.email"`) +**XML**: XPath 表达式(`"//product[@id='123']/price"`) +**定宽**: 来自字段定义的字段名 + +## 优点 + +**单一代码库** - 一个导入器处理多种输入格式 +**用户友好** - 非技术用户可以创建配置 +**可重用** - 可以共享和版本控制配置 +**灵活** - 无需自定义代码即可进行复杂的转换 +**健壮** - 内置验证和全面的错误处理 +**可维护** - 声明式方法减少了实施复杂性 + +## 语言规范 + +结构化数据描述符使用基于 JSON 的配置格式,其顶级结构如下: + +```json +{ + "version": "1.0", + "metadata": { + "name": "Configuration Name", + "description": "Description of what this config does", + "author": "Author Name", + "created": "2024-01-01T00:00:00Z" + }, + "format": { ... }, + "globals": { ... }, + "preprocessing": [ ... ], + "mappings": [ ... ], + "postprocessing": [ ... ], + "output": { ... } +} +``` + +### 格式定义 + +描述输入数据格式和解析选项: + +```json +{ + "format": { + "type": "csv|json|xml|fixed-width|excel|parquet", + "encoding": "utf-8", + "options": { + // Format-specific options + } + } +} +``` + +#### CSV 格式选项 +```json +{ + "format": { + "type": "csv", + "options": { + "delimiter": ",", + "quote_char": "\"", + "escape_char": "\\", + "skip_rows": 1, + "has_header": true, + "null_values": ["", "NULL", "null", "N/A"] + } + } +} +``` + +#### JSON 格式选项 +```json +{ + "format": { + "type": "json", + "options": { + "root_path": "$.data", + "array_mode": "records|single", + "flatten": false + } + } +} +``` + +#### XML 格式选项 +```json +{ + "format": { + "type": "xml", + "options": { + "root_element": "//records/record", + "namespaces": { + "ns": "http://example.com/namespace" + } + } + } +} +``` + +### 全局设置 + +定义查找表、变量和全局配置: + +```json +{ + "globals": { + "variables": { + "current_date": "2024-01-01", + "batch_id": "BATCH_001", + "default_confidence": 0.8 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "UK": "United Kingdom", + "CA": "Canada" + }, + "status_mapping": { + "1": "active", + "0": "inactive" + } + }, + "constants": { + "source_system": "legacy_crm", + "import_type": "full" + } + } +} +``` + +### 字段映射 + +定义如何将源数据映射到目标字段,并进行转换: + +```json +{ + "mappings": [ + { + "target_field": "person_name", + "source": "$.name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"}, + {"type": "required"} + ], + "validation": [ + {"type": "min_length", "value": 2}, + {"type": "max_length", "value": 100}, + {"type": "pattern", "value": "^[A-Za-z\\s]+$"} + ] + }, + { + "target_field": "age", + "source": "$.age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 150} + ] + }, + { + "target_field": "country", + "source": "$.country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ] +} +``` + +### 转换类型 + +可用的转换函数: + +#### 字符串转换 +```json +{"type": "trim"}, +{"type": "upper"}, +{"type": "lower"}, +{"type": "title_case"}, +{"type": "replace", "pattern": "old", "replacement": "new"}, +{"type": "regex_replace", "pattern": "\\d+", "replacement": "XXX"}, +{"type": "substring", "start": 0, "end": 10}, +{"type": "pad_left", "length": 10, "char": "0"} +``` + +#### 类型转换 +```json +{"type": "to_string"}, +{"type": "to_int"}, +{"type": "to_float"}, +{"type": "to_bool"}, +{"type": "to_date", "format": "YYYY-MM-DD"}, +{"type": "parse_json"} +``` + +#### 数据操作 +```json +{"type": "default", "value": "default_value"}, +{"type": "lookup", "table": "table_name"}, +{"type": "concat", "values": ["field1", " - ", "field2"]}, +{"type": "calculate", "expression": "${field1} + ${field2}"}, +{"type": "conditional", "condition": "${age} > 18", "true_value": "adult", "false_value": "minor"} +``` + +### 验证规则 + +数据质量检查,具有可配置的错误处理: + +#### 基础验证 +```json +{"type": "required"}, +{"type": "not_null"}, +{"type": "min_length", "value": 5}, +{"type": "max_length", "value": 100}, +{"type": "range", "min": 0, "max": 1000}, +{"type": "pattern", "value": "^[A-Z]{2,3}$"}, +{"type": "in_list", "values": ["active", "inactive", "pending"]} +``` + +#### 自定义验证 +```json +{ + "type": "custom", + "expression": "${age} >= 18 && ${country} == 'US'", + "message": "Must be 18+ and in US" +}, +{ + "type": "cross_field", + "fields": ["start_date", "end_date"], + "expression": "${start_date} < ${end_date}", + "message": "Start date must be before end date" +} +``` + +### 预处理和后处理 + +在字段映射之前/之后应用的全局操作: + +```json +{ + "preprocessing": [ + { + "type": "filter", + "condition": "${status} != 'deleted'" + }, + { + "type": "sort", + "field": "created_date", + "order": "asc" + } + ], + "postprocessing": [ + { + "type": "deduplicate", + "key_fields": ["email", "phone"] + }, + { + "type": "aggregate", + "group_by": ["country"], + "functions": { + "total_count": {"type": "count"}, + "avg_age": {"type": "avg", "field": "age"} + } + } + ] +} +``` + +### 输出配置 + +定义如何输出处理后的数据: + +```json +{ + "output": { + "format": "trustgraph-objects", + "schema_name": "person", + "options": { + "batch_size": 1000, + "confidence": 0.9, + "source_span_field": "raw_text", + "metadata": { + "source": "crm_import", + "version": "1.0" + } + }, + "error_handling": { + "on_validation_error": "skip|fail|log", + "on_transform_error": "skip|fail|default", + "max_errors": 100, + "error_output": "errors.json" + } + } +} +``` + +## 完整示例 + +```json +{ + "version": "1.0", + "metadata": { + "name": "Customer Import from CRM CSV", + "description": "Imports customer data from legacy CRM system", + "author": "Data Team", + "created": "2024-01-01T00:00:00Z" + }, + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true, + "skip_rows": 1 + } + }, + "globals": { + "variables": { + "import_date": "2024-01-01", + "default_confidence": 0.85 + }, + "lookup_tables": { + "country_codes": { + "US": "United States", + "CA": "Canada", + "UK": "United Kingdom" + } + } + }, + "preprocessing": [ + { + "type": "filter", + "condition": "${status} == 'active'" + } + ], + "mappings": [ + { + "target_field": "full_name", + "source": "customer_name", + "transforms": [ + {"type": "trim"}, + {"type": "title_case"} + ], + "validation": [ + {"type": "required"}, + {"type": "min_length", "value": 2} + ] + }, + { + "target_field": "email", + "source": "email_address", + "transforms": [ + {"type": "trim"}, + {"type": "lower"} + ], + "validation": [ + {"type": "pattern", "value": "^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$"} + ] + }, + { + "target_field": "age", + "source": "age", + "transforms": [ + {"type": "to_int"}, + {"type": "default", "value": 0} + ], + "validation": [ + {"type": "range", "min": 0, "max": 120} + ] + }, + { + "target_field": "country", + "source": "country_code", + "transforms": [ + {"type": "lookup", "table": "country_codes"}, + {"type": "default", "value": "Unknown"} + ] + } + ], + "output": { + "format": "trustgraph-objects", + "schema_name": "customer", + "options": { + "confidence": "${default_confidence}", + "batch_size": 500 + }, + "error_handling": { + "on_validation_error": "log", + "max_errors": 50 + } + } +} +``` + +## 用于描述符生成的 LLM 提示 + +以下提示可用于让 LLM 分析样本数据并生成描述符配置: + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +The descriptor should follow this specification: +- version: "1.0" +- metadata: Configuration name, description, author, and creation date +- format: Input format type and parsing options +- globals: Variables, lookup tables, and constants +- preprocessing: Filters and transformations applied before mapping +- mappings: Field-by-field mapping from source to target with transformations and validations +- postprocessing: Operations like deduplication or aggregation +- output: Target format and error handling configuration + +ANALYZE THE DATA: +1. Identify the format (CSV, JSON, XML, etc.) +2. Detect delimiters, encodings, and structure +3. Find data types for each field +4. Identify patterns and constraints +5. Look for fields that need cleaning or transformation +6. Find relationships between fields +7. Identify lookup opportunities (codes that map to values) +8. Detect required vs optional fields + +CREATE THE DESCRIPTOR: +For each field in the sample data: +- Map it to an appropriate target field name +- Add necessary transformations (trim, case conversion, type casting) +- Include appropriate validations (required, patterns, ranges) +- Set defaults for missing values + +Include preprocessing if needed: +- Filters to exclude invalid records +- Sorting requirements + +Include postprocessing if beneficial: +- Deduplication on key fields +- Aggregation for summary data + +Configure output for TrustGraph: +- format: "trustgraph-objects" +- schema_name: Based on the data entity type +- Appropriate error handling + +DATA SAMPLE: +[Insert data sample here] + +ADDITIONAL CONTEXT (optional): +- Target schema name: [if known] +- Business rules: [any specific requirements] +- Data quality issues to address: [known problems] + +Generate a complete, valid Structured Data Descriptor configuration that will properly import this data into TrustGraph. Include comments explaining key decisions. +``` + +### 示例用法提示 + +``` +I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format. + +[Standard instructions from above...] + +DATA SAMPLE: +```csv +客户ID,姓名,电子邮件,年龄,国家,状态,加入日期,总购买额 +1001,"Smith, John",john.smith@email.com,35,美国,1,2023-01-15,5420.50 +1002,"doe, jane",JANE.DOE@GMAIL.COM,28,加拿大,1,2023-03-22,3200.00 +1003,"Bob Johnson",bob@,62,英国,0,2022-11-01,0 +1004,"Alice Chen","alice.chen@company.org",41,美国,1,2023-06-10,8900.25 +1005,,invalid-email,25,XX,1,2024-01-01,100 +``` + +ADDITIONAL CONTEXT: +- Target schema name: customer +- Business rules: Email should be valid and lowercase, names should be title case +- Data quality issues: Some emails are invalid, some names are missing, country codes need mapping +``` + +### 用于分析现有数据而无需样本的提示 + +``` +I need you to help me create a Structured Data Descriptor configuration for importing [data type] data. + +The source data has these characteristics: +- Format: [CSV/JSON/XML/etc] +- Fields: [list the fields] +- Data quality issues: [describe any known issues] +- Volume: [approximate number of records] + +Requirements: +- [List any specific transformation needs] +- [List any validation requirements] +- [List any business rules] + +Please generate a Structured Data Descriptor configuration that will: +1. Parse the input format correctly +2. Clean and standardize the data +3. Validate according to the requirements +4. Handle errors gracefully +5. Output in TrustGraph ExtractedObject format + +Focus on making the configuration robust and reusable. +``` \ No newline at end of file diff --git a/docs/tech-specs/structured-data-schemas.pt.md b/docs/tech-specs/structured-data-schemas.pt.md new file mode 100644 index 00000000..aa9ddd14 --- /dev/null +++ b/docs/tech-specs/structured-data-schemas.pt.md @@ -0,0 +1,139 @@ +# Alterações no Esquema Pulsar para Dados Estruturados + +## Visão Geral + +Com base na especificação STRUCTURED_DATA.md, este documento propõe as adições e modificações necessárias no esquema Pulsar para suportar as capacidades de dados estruturados no TrustGraph. + +## Alterações Necessárias no Esquema + +### 1. Melhorias no Esquema Principal + +#### Definição de Campo Aprimorada +A classe `Field` existente em `core/primitives.py` precisa de propriedades adicionais: + +```python +class Field(Record): + name = String() + type = String() # int, string, long, bool, float, double, timestamp + size = Integer() + primary = Boolean() + description = String() + # NEW FIELDS: + required = Boolean() # Whether field is required + enum_values = Array(String()) # For enum type fields + indexed = Boolean() # Whether field should be indexed +``` + +### 2. Novos Esquemas de Conhecimento + +#### 2.1 Submissão de Dados Estruturados +Novo arquivo: `knowledge/structured.py` + +```python +from pulsar.schema import Record, String, Bytes, Map +from ..core.metadata import Metadata + +class StructuredDataSubmission(Record): + metadata = Metadata() + format = String() # "json", "csv", "xml" + schema_name = String() # Reference to schema in config + data = Bytes() # Raw data to ingest + options = Map(String()) # Format-specific options +``` + +### 3. Novos Esquemas de Serviço + +#### 3.1 Serviço de Consulta Estruturada a partir de Processamento de Linguagem Natural +Novo arquivo: `services/nlp_query.py` + +```python +from pulsar.schema import Record, String, Array, Map, Integer, Double +from ..core.primitives import Error + +class NLPToStructuredQueryRequest(Record): + natural_language_query = String() + max_results = Integer() + context_hints = Map(String()) # Optional context for query generation + +class NLPToStructuredQueryResponse(Record): + error = Error() + graphql_query = String() # Generated GraphQL query + variables = Map(String()) # GraphQL variables if any + detected_schemas = Array(String()) # Which schemas the query targets + confidence = Double() +``` + +#### 3.2 Serviço de Consulta Estruturada +Novo arquivo: `services/structured_query.py` + +```python +from pulsar.schema import Record, String, Map, Array +from ..core.primitives import Error + +class StructuredQueryRequest(Record): + query = String() # GraphQL query + variables = Map(String()) # GraphQL variables + operation_name = String() # Optional operation name for multi-operation documents + +class StructuredQueryResponse(Record): + error = Error() + data = String() # JSON-encoded GraphQL response data + errors = Array(String()) # GraphQL errors if any +``` + +#### 2.2 Saída da Extração de Objetos +Novo arquivo: `knowledge/object.py` + +```python +from pulsar.schema import Record, String, Map, Double +from ..core.metadata import Metadata + +class ExtractedObject(Record): + metadata = Metadata() + schema_name = String() # Which schema this object belongs to + values = Map(String()) # Field name -> value + confidence = Double() + source_span = String() # Text span where object was found +``` + +### 4. Esquemas de Conhecimento Aprimorados + +#### 4.1 Aprimoramento de Incorporações de Objetos +Atualizar `knowledge/embeddings.py` para oferecer melhor suporte a incorporações de objetos estruturadas: + +```python +class StructuredObjectEmbedding(Record): + metadata = Metadata() + vectors = Array(Array(Double())) + schema_name = String() + object_id = String() # Primary key value + field_embeddings = Map(Array(Double())) # Per-field embeddings +``` + +## Pontos de Integração + +### Integração de Fluxo + +Os esquemas serão usados por novos módulos de fluxo: +`trustgraph-flow/trustgraph/decoding/structured` - Usa StructuredDataSubmission +`trustgraph-flow/trustgraph/query/nlp_query/cassandra` - Usa esquemas de consulta NLP +`trustgraph-flow/trustgraph/query/objects/cassandra` - Usa esquemas de consulta estruturados +`trustgraph-flow/trustgraph/extract/object/row/` - Consome Chunk, produz ExtractedObject +`trustgraph-flow/trustgraph/storage/objects/cassandra` - Usa o esquema Rows +`trustgraph-flow/trustgraph/embeddings/object_embeddings/qdrant` - Usa esquemas de incorporação de objetos + +## Notas de Implementação + +1. **Versionamento de Esquemas**: Considere adicionar um campo `version` em RowSchema para suporte futuro de migração. +2. **Sistema de Tipos**: O `Field.type` deve suportar todos os tipos nativos do Cassandra. +3. **Operações em Lote**: A maioria dos serviços deve suportar operações individuais e em lote. +4. **Tratamento de Erros**: Relatório de erros consistente em todos os novos serviços. +5. **Compatibilidade com Versões Anteriores**: Os esquemas existentes permanecem inalterados, exceto por pequenos aprimoramentos de campos. + +## Próximos Passos + +1. Implementar os arquivos de esquema na nova estrutura. +2. Atualizar os serviços existentes para reconhecer os novos tipos de esquema. +3. Implementar módulos de fluxo que usem esses esquemas. +4. Adicionar endpoints de gateway/rev-gateway para novos serviços. +5. Criar testes unitários para validação de esquema. diff --git a/docs/tech-specs/structured-data-schemas.tr.md b/docs/tech-specs/structured-data-schemas.tr.md new file mode 100644 index 00000000..6e414a3f --- /dev/null +++ b/docs/tech-specs/structured-data-schemas.tr.md @@ -0,0 +1,139 @@ +# Yapılandırılmış Veri Pulsar Şema Değişiklikleri + +## Genel Bakış + +STRUCTURED_DATA.md spesifikasyonuna dayanarak, bu belge, TrustGraph'ta yapılandırılmış veri yeteneklerini desteklemek için gerekli olan Pulsar şema eklemelerini ve değişikliklerini önermektedir. + +## Gerekli Şema Değişiklikleri + +### 1. Temel Şema Geliştirmeleri + +#### Gelişmiş Alan Tanımı +`core/primitives.py` içindeki mevcut `Field` sınıfı, ek özelliklere ihtiyaç duymaktadır: + +```python +class Field(Record): + name = String() + type = String() # int, string, long, bool, float, double, timestamp + size = Integer() + primary = Boolean() + description = String() + # NEW FIELDS: + required = Boolean() # Whether field is required + enum_values = Array(String()) # For enum type fields + indexed = Boolean() # Whether field should be indexed +``` + +### 2. Yeni Bilgi Şemaları + +#### 2.1 Yapılandırılmış Veri Gönderimi +Yeni dosya: `knowledge/structured.py` + +```python +from pulsar.schema import Record, String, Bytes, Map +from ..core.metadata import Metadata + +class StructuredDataSubmission(Record): + metadata = Metadata() + format = String() # "json", "csv", "xml" + schema_name = String() # Reference to schema in config + data = Bytes() # Raw data to ingest + options = Map(String()) # Format-specific options +``` + +### 3. Yeni Hizmet Şemaları + +#### 3.1 Doğal Dil İşleme'den Yapılandırılmış Sorgu Hizmeti +Yeni dosya: `services/nlp_query.py` + +```python +from pulsar.schema import Record, String, Array, Map, Integer, Double +from ..core.primitives import Error + +class NLPToStructuredQueryRequest(Record): + natural_language_query = String() + max_results = Integer() + context_hints = Map(String()) # Optional context for query generation + +class NLPToStructuredQueryResponse(Record): + error = Error() + graphql_query = String() # Generated GraphQL query + variables = Map(String()) # GraphQL variables if any + detected_schemas = Array(String()) # Which schemas the query targets + confidence = Double() +``` + +#### 3.2 Yapılandırılmış Sorgu Hizmeti +Yeni dosya: `services/structured_query.py` + +```python +from pulsar.schema import Record, String, Map, Array +from ..core.primitives import Error + +class StructuredQueryRequest(Record): + query = String() # GraphQL query + variables = Map(String()) # GraphQL variables + operation_name = String() # Optional operation name for multi-operation documents + +class StructuredQueryResponse(Record): + error = Error() + data = String() # JSON-encoded GraphQL response data + errors = Array(String()) # GraphQL errors if any +``` + +#### 2.2 Nesne Çıkarımı Çıktısı +Yeni dosya: `knowledge/object.py` + +```python +from pulsar.schema import Record, String, Map, Double +from ..core.metadata import Metadata + +class ExtractedObject(Record): + metadata = Metadata() + schema_name = String() # Which schema this object belongs to + values = Map(String()) # Field name -> value + confidence = Double() + source_span = String() # Text span where object was found +``` + +### 4. Gelişmiş Bilgi Şemaları + +#### 4.1 Nesne Gömme İyileştirmeleri +`knowledge/embeddings.py`'ı, yapılandırılmış nesne gömmelerini daha iyi destekleyecek şekilde güncelleyin: + +```python +class StructuredObjectEmbedding(Record): + metadata = Metadata() + vectors = Array(Array(Double())) + schema_name = String() + object_id = String() # Primary key value + field_embeddings = Map(Array(Double())) # Per-field embeddings +``` + +## Entegrasyon Noktaları + +### Akış Entegrasyonu + +Bu şemalar, yeni akış modülleri tarafından kullanılacaktır: +`trustgraph-flow/trustgraph/decoding/structured` - StructuredDataSubmission'ı kullanır +`trustgraph-flow/trustgraph/query/nlp_query/cassandra` - NLP sorgu şemalarını kullanır +`trustgraph-flow/trustgraph/query/objects/cassandra` - Yapılandırılmış sorgu şemalarını kullanır +`trustgraph-flow/trustgraph/extract/object/row/` - Chunk'ı tüketir, ExtractedObject üretir +`trustgraph-flow/trustgraph/storage/objects/cassandra` - Rows şemasını kullanır +`trustgraph-flow/trustgraph/embeddings/object_embeddings/qdrant` - Nesne gömme şemalarını kullanır + +## Uygulama Notları + +1. **Şema Sürümleme**: Gelecekteki geçiş desteği için RowSchema'ya bir `version` alanı eklemeyi düşünün. +2. **Tip Sistemi**: `Field.type`, tüm Cassandra yerel türlerini desteklemelidir. +3. **Toplu İşlemler**: Çoğu hizmet, hem tekil hem de toplu işlemleri desteklemelidir. +4. **Hata Yönetimi**: Tüm yeni hizmetlerde tutarlı hata raporlama. +5. **Geriye Uyumluluk**: Mevcut şemalar, küçük alan geliştirmeleri dışında değişmeden kalacaktır. + +## Sonraki Adımlar + +1. Şema dosyalarını yeni yapıya göre uygulayın. +2. Mevcut hizmetleri, yeni şema türlerini tanıyacak şekilde güncelleyin. +3. Bu şemaları kullanan akış modüllerini uygulayın. +4. Yeni hizmetler için ağ geçidi/geri ağ geçidi uç noktaları ekleyin. +5. Şema doğrulaması için birim testleri oluşturun. diff --git a/docs/tech-specs/structured-data.ar.md b/docs/tech-specs/structured-data.ar.md new file mode 100644 index 00000000..81178f8d --- /dev/null +++ b/docs/tech-specs/structured-data.ar.md @@ -0,0 +1,253 @@ +# المواصفات الفنية للبيانات المهيكلة + +## نظرة عامة + +تصف هذه المواصفات دمج TrustGraph مع تدفقات البيانات المهيكلة، مما يمكّن النظام من العمل مع البيانات التي يمكن تمثيلها كصفوف في الجداول أو كائنات في مخازن الكائنات. يدعم هذا التكامل أربع حالات استخدام رئيسية: + +1. **الاستخراج من غير المهيكل إلى المهيكل**: قراءة مصادر البيانات غير المهيكلة، وتحديد واستخراج هياكل الكائنات، وتخزينها بتنسيق جدولي. +2. **استيعاب البيانات المهيكلة**: تحميل البيانات الموجودة بالفعل بتنسيقات مهيكلة مباشرة إلى المتجر المهيكل جنبًا إلى جنب مع البيانات المستخرجة. +3. **الاستعلام باللغة الطبيعية**: تحويل الأسئلة باللغة الطبيعية إلى استعلامات مهيكلة لاستخراج البيانات المطابقة من المتجر. +4. **الاستعلام المهيكل المباشر**: تنفيذ استعلامات مهيكلة مباشرة مقابل مخزن البيانات لاسترجاع البيانات بدقة. + +## الأهداف + +**واجهة وصول موحدة للبيانات**: توفير واجهة واحدة للوصول إلى كل من البيانات المهيكلة وغير المهيكلة داخل TrustGraph. +**تكامل سلس**: تمكين التوافق السلس بين تمثيل المعرفة القائم على الرسم البياني في TrustGraph وتنسيقات البيانات المهيكلة التقليدية. +**استخراج مرن**: دعم الاستخراج التلقائي للبيانات المهيكلة من مصادر غير مهيكلة متنوعة (المستندات، والنصوص، وما إلى ذلك). +**تنوع الاستعلام**: السماح للمستخدمين بالاستعلام عن البيانات باستخدام كل من اللغة الطبيعية ولغات الاستعلام المهيكلة. +**اتساق البيانات**: الحفاظ على سلامة البيانات واتساقها عبر تمثيلات البيانات المختلفة. +**تحسين الأداء**: ضمان تخزين واسترجاع فعال للبيانات المهيكلة على نطاق واسع. +**مرونة المخطط**: دعم كل من مناهج "المخطط عند الكتابة" و "المخطط عند القراءة" لاستيعاب مصادر البيانات المتنوعة. +**التوافق مع الإصدارات السابقة**: الحفاظ على وظائف TrustGraph الحالية مع إضافة إمكانات البيانات المهيكلة. + +## الخلفية + +تتفوق TrustGraph حاليًا في معالجة البيانات غير المهيكلة وإنشاء الرسوم البيانية المعرفية من مصادر متنوعة. ومع ذلك، تتضمن العديد من حالات الاستخدام في المؤسسات بيانات مهيكلة بشكل متأصل - سجلات العملاء، وسجلات المعاملات، وقواعد بيانات المخزون، ومجموعات بيانات جدولية أخرى. غالبًا ما تحتاج هذه مجموعات البيانات المهيكلة إلى تحليلها جنبًا إلى جنب مع المحتوى غير المهيكل لتقديم رؤى شاملة. + +القيود الحالية تشمل: +لا يوجد دعم أصلي لاستيعاب تنسيقات البيانات المهيكلة مسبقًا (CSV، ومصفوفات JSON، وتصديرات قواعد البيانات). +عدم القدرة على الحفاظ على الهيكل المتأصل عند استخراج البيانات الجدولية من المستندات. +عدم وجود آليات استعلام فعالة لأنماط البيانات المهيكلة. +عدم وجود جسر بين استعلامات تشبه SQL واستعلامات الرسم البياني في TrustGraph. + +تعالج هذه المواصفات هذه الفجوات من خلال تقديم طبقة بيانات مهيكلة تكمل إمكانات TrustGraph الحالية. من خلال دعم البيانات المهيكلة أصلاً، يمكن لـ TrustGraph: +أن تكون منصة موحدة لتحليل كل من البيانات المهيكلة وغير المهيكلة. +تمكين الاستعلامات الهجينة التي تمتد عبر علاقات الرسم البياني والبيانات الجدولية. +توفير واجهات مألوفة للمستخدمين الذين اعتادوا العمل مع البيانات المهيكلة. +إطلاق حالات استخدام جديدة في تكامل البيانات وذكاء الأعمال. + +## التصميم الفني + +### البنية + +يتطلب تكامل البيانات المهيكلة المكونات الفنية التالية: + +1. **خدمة NLP-to-Structured-Query** + تحويل الأسئلة باللغة الطبيعية إلى استعلامات مهيكلة. + يدعم أهداف لغة استعلام متعددة (في البداية بناء الجملة المشابه لـ SQL). + يتكامل مع إمكانات NLP الحالية في TrustGraph. + + الوحدة: trustgraph-flow/trustgraph/query/nlp_query/cassandra + +2. **دعم مخطط التكوين** ✅ **[مكتمل]** + نظام تكوين موسع لتخزين مخططات البيانات المهيكلة. + دعم لتعريف هياكل الجداول وأنواع الحقول والعلاقات. + إمكانيات إصدار وترحيل المخططات. + +3. **وحدة استخراج الكائنات** ✅ **[مكتمل]** + تكامل محسن لتدفق استخراج المعرفة. + تحديد واستخراج كائنات مهيكلة من مصادر غير مهيكلة. + الحفاظ على الأصل ودرجات الثقة. + يسجل معالج تكوين (مثال: trustgraph-flow/trustgraph/prompt/template/service.py) لتلقي بيانات التكوين وفك تشفير معلومات المخطط. + يتلقى الكائنات ويفك تشفيرها إلى كائنات ExtractedObject للتسليم على قائمة الانتظار Pulsar. + ملاحظة: يوجد رمز موجود في `trustgraph-flow/trustgraph/extract/object/row/`. كان هذا محاولة سابقة وسيتطلب إعادة هيكلة كبيرة لأنه لا يتوافق مع واجهات برمجة التطبيقات الحالية. استخدمه إذا كان مفيدًا، وابدأ من البداية إذا لم يكن كذلك. + يتطلب واجهة سطر أوامر: `kg-extract-objects` + + الوحدة: trustgraph-flow/trustgraph/extract/kg/objects/ + +4. **وحدة كاتب المتجر المهيكل** ✅ **[مكتمل]** + يتلقى الكائنات بتنسيق ExtractedObject من قوائم انتظار Pulsar. + التنفيذ الأولي يستهدف Apache Cassandra كمتجر البيانات المهيكل. + يتعامل مع إنشاء الجداول الديناميكي بناءً على المخططات التي تمت مواجهتها. + يدير تعيين المخطط إلى جدول Cassandra وتحويل البيانات. + يوفر عمليات كتابة مجمعة وتدفق لتحسين الأداء. + لا توجد مخرجات Pulsar - هذه خدمة نهائية في تدفق البيانات. + + **معالجة المخططات**: + يراقب رسائل ExtractedObject الواردة للإشارة إلى المخططات. + عندما يتم مواجهة مخطط جديد لأول مرة، يقوم تلقائيًا بإنشاء جدول Cassandra المقابل. + يحتفظ بخزنة للمخططات المعروفة لتجنب محاولات إنشاء جداول متكررة. + يجب أن تأخذ في الاعتبار ما إذا كان سيتم تلقي تعريفات المخططات مباشرة أو الاعتماد على أسماء المخططات في رسائل ExtractedObject. + + **ربط جدول Cassandra**: + يتم تسمية مساحة المفاتيح (Keyspace) بناءً على الحقل `user` من بيانات التعريف (Metadata) الخاصة بـ ExtractedObject. + يتم تسمية الجدول بناءً على الحقل `schema_name` الخاص بـ ExtractedObject. + تصبح المجموعة (Collection) من بيانات التعريف جزءًا من مفتاح التقسيم (partition key) لضمان: + توزيع البيانات بشكل طبيعي عبر عقد Cassandra. + استعلامات فعالة داخل مجموعة معينة. + عزل منطقي بين عمليات استيراد البيانات/المصادر المختلفة. + هيكل المفتاح الأساسي: `PRIMARY KEY ((collection, ), )`. + تكون المجموعة دائمًا المكون الأول من مفتاح التقسيم. + تتبع حقول المفتاح الأساسي المعرفة في المخطط (schema) كجزء من مفتاح التقسيم المركب. + يتطلب هذا تحديد المجموعة في الاستعلامات، مما يضمن أداءً متوقعًا. + يتم تعيين تعريفات الحقول إلى أعمدة Cassandra مع تحويلات الأنواع: + `string` → `text`. + `integer` → `int` أو `bigint` بناءً على تلميح الحجم. + `float` → `float` أو `double` بناءً على احتياجات الدقة. + `boolean` → `boolean`. + `timestamp` → `timestamp`. + `enum` → `text` مع التحقق من الصحة على مستوى التطبيق. + تقوم الحقول المفهرسة بإنشاء فهارس ثانوية لـ Cassandra (باستثناء الحقول الموجودة بالفعل في المفتاح الأساسي). + يتم فرض الحقول المطلوبة على مستوى التطبيق (لا تدعم Cassandra NOT NULL). + + **تخزين الكائنات (Object Storage)**: + يستخرج القيم من خريطة ExtractedObject.values. + يقوم بتحويل النوع والتحقق من الصحة قبل الإدراج. + يتعامل مع الحقول الاختيارية المفقودة بأمان. + يحتفظ ببيانات وصفية حول أصل الكائن (مستند المصدر، درجات الثقة). + يدعم عمليات الكتابة المتطابقة (idempotent writes) للتعامل مع سيناريوهات إعادة إرسال الرسائل. + + **ملاحظات التنفيذ**: + الكود الحالي الموجود في `trustgraph-flow/trustgraph/storage/objects/cassandra/` قديم ولا يتوافق مع واجهات برمجة التطبيقات (APIs) الحالية. + يجب الرجوع إلى `trustgraph-flow/trustgraph/storage/triples/cassandra` كمثال على معالج تخزين يعمل. + يجب تقييم الكود الحالي بحثًا عن أي مكونات قابلة لإعادة الاستخدام قبل اتخاذ قرار بإعادة هيكلة أو إعادة كتابة. + + الوحدة: trustgraph-flow/trustgraph/storage/objects/cassandra + +5. **خدمة الاستعلامات المهيكلة** ✅ **[مكتمل]** + تقبل استعلامات مهيكلة بتنسيقات محددة. + تنفذ الاستعلامات على المستودع المهيكل. + تُرجع الكائنات التي تتطابق مع معايير الاستعلام. + تدعم التقسيم والترشيح للنتائج. + + الوحدة: trustgraph-flow/trustgraph/query/objects/cassandra + +6. **تكامل أدوات الوكيل (Agent Tool Integration)** + فئة أداة جديدة لأطر عمل الوكيل. + تمكن الوكلاء من الاستعلام عن مستودعات البيانات المهيكلة. + توفر واجهات استعلام باللغة الطبيعية والمهيكلة. + تتكامل مع عمليات اتخاذ القرار الحالية للوكلاء. + +7. **خدمة استيعاب البيانات المهيكلة** + تقبل بيانات مهيكلة بتنسيقات متعددة (JSON، CSV، XML). + تقوم بتحليل والتحقق من صحة البيانات الواردة مقابل المخططات المحددة. + تحول البيانات إلى تدفقات كائنات مُنظمة. + تُصدر الكائنات إلى قوائم انتظار الرسائل المناسبة للمعالجة. + تدعم عمليات التحميل المجمعة والاستيعاب المتدفق. + + الوحدة: trustgraph-flow/trustgraph/decoding/structured + +8. **خدمة تضمين الكائنات (Object Embedding Service)** + تولد تضمينات متجهة للكائنات المهيكلة. + تمكن البحث الدلالي عبر البيانات المهيكلة. + تدعم البحث الهجين الذي يجمع بين الاستعلامات المهيكلة والتشابه الدلالي. + تتكامل مع مخازن المتجهات الحالية. + + الوحدة: trustgraph-flow/trustgraph/embeddings/object_embeddings/qdrant + +### نماذج البيانات + +#### آلية تخزين المخططات + +يتم تخزين المخططات في نظام تكوين TrustGraph باستخدام الهيكل التالي: + +**النوع (Type)**: `schema` (قيمة ثابتة لجميع مخططات البيانات المهيكلة). +**المفتاح (Key)**: الاسم/المعرف الفريد للمخطط (مثل `customer_records`، `transaction_log`). +**القيمة (Value)**: تعريف مخطط JSON يحتوي على الهيكل. + +مثال على إدخال التكوين: +``` +Type: schema +Key: customer_records +Value: { + "name": "customer_records", + "description": "Customer information table", + "fields": [ + { + "name": "customer_id", + "type": "string", + "primary_key": true + }, + { + "name": "name", + "type": "string", + "required": true + }, + { + "name": "email", + "type": "string", + "required": true + }, + { + "name": "registration_date", + "type": "timestamp" + }, + { + "name": "status", + "type": "string", + "enum": ["active", "inactive", "suspended"] + } + ], + "indexes": ["email", "registration_date"] +} +``` + +هذا النهج يسمح بما يلي: +تعريف مخطط ديناميكي دون تغييرات في التعليمات البرمجية +تحديثات سهلة للمخططات وإصداراتها +تكامل متسق مع إدارة التكوين الحالية لـ TrustGraph +دعم مخططات متعددة داخل عملية نشر واحدة + +### واجهات برمجة التطبيقات (APIs) + +واجهات برمجة تطبيقات جديدة: + مخططات Pulsar للأنواع المذكورة أعلاه + واجهات Pulsar في التدفقات الجديدة + هناك حاجة إلى وسيلة لتحديد أنواع المخططات في التدفقات حتى تعرف التدفقات + أنواع المخططات التي يجب تحميلها + تمت إضافة واجهات برمجة تطبيقات إلى البوابة والبوابة العكسية + +واجهات برمجة تطبيقات معدلة: +نقاط نهاية استخراج المعرفة - إضافة خيار إخراج كائن منظم +نقاط نهاية الوكيل - إضافة دعم لأدوات البيانات المنظمة + +### تفاصيل التنفيذ + +باتباع الاتفاقيات الحالية - هذه مجرد وحدات معالجة جديدة. +كل شيء موجود في حزم trustgraph-flow باستثناء عناصر المخطط +الموجودة في trustgraph-base. + +هناك حاجة إلى بعض الأعمال لواجهة المستخدم في Workbench لتمكين عرض / تجربة هذه +الإمكانية. + +## اعتبارات الأمان + +لا توجد اعتبارات إضافية. + +## اعتبارات الأداء + +بعض الأسئلة حول استخدام استعلامات وفهارس Cassandra بحيث لا تبطئ الاستعلامات. + +## استراتيجية الاختبار + +استخدم استراتيجية الاختبار الحالية، سيتم إنشاء اختبارات الوحدة والاتفاقية والتكامل. + +## خطة الترحيل + +لا يوجد. + +## الجدول الزمني + + +لم يتم تحديده. + +## أسئلة مفتوحة + +هل يمكن جعل هذا يعمل مع أنواع تخزين أخرى؟ نحن نهدف إلى استخدام + واجهات تجعل الوحدات التي تعمل مع تخزين واحد قابلة للتطبيق على + تخزين آخر. + +## المراجع + +غير متوفر. + diff --git a/docs/tech-specs/structured-data.es.md b/docs/tech-specs/structured-data.es.md new file mode 100644 index 00000000..04211bb3 --- /dev/null +++ b/docs/tech-specs/structured-data.es.md @@ -0,0 +1,253 @@ +# Especificación Técnica de Datos Estructurados + +## Descripción General + +Esta especificación describe la integración de TrustGraph con flujos de datos estructurados, lo que permite que el sistema trabaje con datos que se pueden representar como filas en tablas u objetos en almacenes de objetos. La integración admite cuatro casos de uso principales: + +1. **Extracción de Datos No Estructurados a Estructurados**: Leer fuentes de datos no estructurados, identificar y extraer estructuras de objetos y almacenarlas en un formato tabular. +2. **Ingesta de Datos Estructurados**: Cargar datos que ya están en formatos estructurados directamente en el almacén estructurado junto con los datos extraídos. +3. **Consultas en Lenguaje Natural**: Convertir preguntas en lenguaje natural en consultas estructuradas para extraer datos coincidentes del almacén. +4. **Consultas Estructuradas Directas**: Ejecutar consultas estructuradas directamente contra el almacén de datos para una recuperación de datos precisa. + +## Objetivos + +**Acceso Unificado a Datos**: Proporcionar una única interfaz para acceder tanto a datos estructurados como no estructurados dentro de TrustGraph. +**Integración Fluida**: Permitir una interoperabilidad fluida entre la representación de conocimiento basada en gráficos de TrustGraph y los formatos de datos estructurados tradicionales. +**Extracción Flexible**: Admitir la extracción automática de datos estructurados de diversas fuentes no estructuradas (documentos, texto, etc.). +**Versatilidad de Consulta**: Permitir a los usuarios consultar datos utilizando tanto lenguaje natural como lenguajes de consulta estructurados. +**Consistencia de Datos**: Mantener la integridad y la consistencia de los datos en diferentes representaciones de datos. +**Optimización del Rendimiento**: Garantizar el almacenamiento y la recuperación eficientes de datos estructurados a escala. +**Flexibilidad del Esquema**: Admitir enfoques de esquema-en-escritura y esquema-en-lectura para adaptarse a diversas fuentes de datos. +**Compatibilidad con Versiones Anteriores**: Preservar la funcionalidad existente de TrustGraph al agregar capacidades de datos estructurados. + +## Antecedentes + +Actualmente, TrustGraph destaca en el procesamiento de datos no estructurados y en la creación de gráficos de conocimiento a partir de diversas fuentes. Sin embargo, muchos casos de uso empresariales implican datos que son inherentemente estructurados: registros de clientes, registros de transacciones, bases de datos de inventario y otros conjuntos de datos tabulares. Estos conjuntos de datos estructurados a menudo deben analizarse junto con contenido no estructurado para proporcionar información integral. + +Las limitaciones actuales incluyen: +No hay soporte nativo para la ingesta de formatos de datos preestructurados (CSV, matrices JSON, exportaciones de bases de datos). +Incapacidad para preservar la estructura inherente al extraer datos tabulares de documentos. +Falta de mecanismos de consulta eficientes para patrones de datos estructurados. +Falta de un puente entre las consultas tipo SQL y las consultas de gráficos de TrustGraph. + +Esta especificación aborda estas deficiencias mediante la introducción de una capa de datos estructurados que complementa las capacidades existentes de TrustGraph. Al admitir datos estructurados de forma nativa, TrustGraph puede: +Servir como una plataforma unificada para el análisis tanto de datos estructurados como no estructurados. +Permitir consultas híbridas que abarquen tanto las relaciones de gráficos como los datos tabulares. +Proporcionar interfaces familiares para los usuarios acostumbrados a trabajar con datos estructurados. +Desbloquear nuevos casos de uso en la integración de datos y la inteligencia empresarial. + +## Diseño Técnico + +### Arquitectura + +La integración de datos estructurados requiere los siguientes componentes técnicos: + +1. **Servicio de Conversión de Lenguaje Natural a Consulta Estructurada** + Convierte preguntas en lenguaje natural en consultas estructuradas. + Admite múltiples objetivos de lenguaje de consulta (inicialmente sintaxis tipo SQL). + Se integra con las capacidades existentes de NLP de TrustGraph. + + Módulo: trustgraph-flow/trustgraph/query/nlp_query/cassandra + +2. **Soporte de Esquema de Configuración** ✅ **[COMPLETO]** + Sistema de configuración extendido para almacenar esquemas de datos estructurados. + Soporte para definir estructuras de tablas, tipos de campos y relaciones. + Capacidades de versionado y migración de esquemas. + +3. **Módulo de Extracción de Objetos** ✅ **[COMPLETO]** + Integración mejorada del flujo de extracción de conocimiento. + Identifica y extrae objetos estructurados de fuentes no estructuradas. + Mantiene el origen y las puntuaciones de confianza. + Registra un controlador de configuración (ejemplo: trustgraph-flow/trustgraph/prompt/template/service.py) para recibir datos de configuración y decodificar información del esquema. + Recibe objetos y los decodifica en objetos ExtractedObject para su entrega en la cola de Pulsar. + NOTA: Existe código en `trustgraph-flow/trustgraph/extract/object/row/`. Este fue un intento anterior y deberá refactorizarse por completo, ya que no se ajusta a las API actuales. Úselo si es útil, comience desde cero si no. + Requiere una interfaz de línea de comandos: `kg-extract-objects` + + Módulo: trustgraph-flow/trustgraph/extract/kg/objects/ + +4. **Módulo de Escritura de Almacén Estructurado** ✅ **[COMPLETO]** + Recibe objetos en formato ExtractedObject de las colas de Pulsar. + Implementación inicial dirigida a Apache Cassandra como el almacén de datos estructurados. + Maneja la creación dinámica de tablas basada en los esquemas encontrados. + Administra el mapeo de esquemas a tablas de Cassandra y la transformación de datos. + Proporciona operaciones de escritura por lotes y en streaming para la optimización del rendimiento. + No hay salidas de Pulsar: este es un servicio terminal en el flujo de datos. + + **Manejo de Esquemas**: + Supervisa los mensajes ExtractedObject entrantes en busca de referencias de esquema. + Cuando se encuentra un nuevo esquema por primera vez, crea automáticamente la tabla correspondiente en Cassandra. + Mantiene una caché de esquemas conocidos para evitar intentos redundantes de creación de tablas. + Se debe considerar si se reciben definiciones de esquema directamente o si se confía en los nombres de esquema en los mensajes ExtractedObject. + + **Mapeo de Tablas de Cassandra**: + El espacio de claves tiene el nombre derivado del campo `user` del campo de metadatos de ExtractedObject. + La tabla tiene el nombre derivado del campo `schema_name` de ExtractedObject. + La colección del metadato se convierte en parte de la clave de partición para garantizar: + Distribución de datos natural en los nodos de Cassandra. + Consultas eficientes dentro de una colección específica. + Aislamiento lógico entre diferentes importaciones de datos/fuentes. + Estructura de la clave primaria: `PRIMARY KEY ((collection, ), )` + La colección siempre es el primer componente de la clave de partición. + Los campos de la clave primaria definidos en el esquema siguen como parte de la clave de partición compuesta. + Esto requiere que las consultas especifiquen la colección, lo que garantiza un rendimiento predecible. + Las definiciones de campos se mapean a columnas de Cassandra con conversiones de tipo: + `string` → `text` + `integer` → `int` o `bigint` según la sugerencia de tamaño. + `float` → `float` o `double` según las necesidades de precisión. + `boolean` → `boolean` + `timestamp` → `timestamp` + `enum` → `text` con validación a nivel de aplicación. + Los campos indexados crean índices secundarios de Cassandra (excluyendo los campos que ya están en la clave primaria). + Los campos obligatorios se imponen a nivel de aplicación (Cassandra no admite NOT NULL). + + **Almacenamiento de Objetos**: + Extrae valores del mapa ExtractedObject.values. + Realiza la conversión de tipo y la validación antes de la inserción. + Maneja los campos opcionales faltantes de forma elegante. + Mantiene metadatos sobre el origen del objeto (documento de origen, puntajes de confianza). + Admite escrituras idempotentes para manejar escenarios de retransmisión de mensajes. + + **Notas de Implementación**: + El código existente en `trustgraph-flow/trustgraph/storage/objects/cassandra/` está obsoleto y no cumple con las API actuales. + Debe referenciar `trustgraph-flow/trustgraph/storage/triples/cassandra` como un ejemplo de un procesador de almacenamiento que funciona. + Es necesario evaluar el código existente para identificar cualquier componente reutilizable antes de decidir refactorizar o reescribir. + + Módulo: trustgraph-flow/trustgraph/storage/objects/cassandra + +5. **Servicio de Consulta Estructurada** ✅ **[COMPLETO]** + Acepta consultas estructuradas en formatos definidos. + Ejecuta consultas contra el almacén estructurado. + Devuelve objetos que coinciden con los criterios de la consulta. + Admite paginación y filtrado de resultados. + + Módulo: trustgraph-flow/trustgraph/query/objects/cassandra + +6. **Integración de Herramientas de Agente** + Nueva clase de herramienta para marcos de agentes. + Permite que los agentes consulten almacenes de datos estructurados. + Proporciona interfaces de consulta de lenguaje natural y estructuradas. + Se integra con los procesos de toma de decisiones existentes de los agentes. + +7. **Servicio de Ingestión de Datos Estructurados** + Acepta datos estructurados en múltiples formatos (JSON, CSV, XML). + Analiza y valida los datos entrantes según los esquemas definidos. + Convierte los datos en flujos de objetos normalizados. + Emite objetos a colas de mensajes apropiadas para su procesamiento. + Admite cargas masivas e ingestión en streaming. + + Módulo: trustgraph-flow/trustgraph/decoding/structured + +8. **Servicio de Incrustación de Objetos** + Genera incrustaciones vectoriales para objetos estructurados. + Permite la búsqueda semántica en datos estructurados. + Admite la búsqueda híbrida que combina consultas estructuradas con similitud semántica. + Se integra con almacenes de vectores existentes. + + Módulo: trustgraph-flow/trustgraph/embeddings/object_embeddings/qdrant + +### Modelos de Datos + +#### Mecanismo de Almacenamiento de Esquemas + +Los esquemas se almacenan en el sistema de configuración de TrustGraph utilizando la siguiente estructura: + +**Tipo**: `schema` (valor fijo para todos los esquemas de datos estructurados) +**Clave**: El nombre/identificador único del esquema (por ejemplo, `customer_records`, `transaction_log`) +**Valor**: Definición de esquema JSON que contiene la estructura + +Ejemplo de entrada de configuración: +``` +Type: schema +Key: customer_records +Value: { + "name": "customer_records", + "description": "Customer information table", + "fields": [ + { + "name": "customer_id", + "type": "string", + "primary_key": true + }, + { + "name": "name", + "type": "string", + "required": true + }, + { + "name": "email", + "type": "string", + "required": true + }, + { + "name": "registration_date", + "type": "timestamp" + }, + { + "name": "status", + "type": "string", + "enum": ["active", "inactive", "suspended"] + } + ], + "indexes": ["email", "registration_date"] +} +``` + +Este enfoque permite: +Definición dinámica del esquema sin cambios en el código +Actualizaciones y versiones de esquema fáciles +Integración consistente con la gestión de configuración de TrustGraph existente +Soporte para múltiples esquemas dentro de un único despliegue + +### APIs + +Nuevas APIs: + Esquemas de Pulsar para los tipos anteriores + Interfaces de Pulsar en nuevos flujos + Se necesita un medio para especificar los tipos de esquema en los flujos para que los flujos sepan qué + tipos de esquema cargar + APIs añadidas a la puerta de enlace y a la puerta de enlace de revisión + +APIs modificadas: +Puntos finales de extracción de conocimiento: añadir opción de salida de objeto estructurado +Puntos finales de agentes: añadir soporte para herramientas de datos estructurados + +### Detalles de implementación + +Siguiendo las convenciones existentes: estos son simplemente nuevos módulos de procesamiento. +Todo está en los paquetes de trustgraph-flow, excepto los elementos del esquema +en trustgraph-base. + +Se necesita algo de trabajo de interfaz de usuario en el Workbench para poder demostrar / probar +esta funcionalidad. + +## Consideraciones de seguridad + +No hay consideraciones adicionales. + +## Consideraciones de rendimiento + +Algunas preguntas sobre el uso de consultas e índices de Cassandra para que las consultas +no ralenticen el sistema. + +## Estrategia de pruebas + +Utilizar la estrategia de pruebas existente, se crearán pruebas unitarias, de contrato e de integración. + +## Plan de migración + +Ninguno. + +## Cronograma + +No especificado. + +## Preguntas abiertas + +¿Se puede hacer que esto funcione con otros tipos de almacenamiento? Nuestro objetivo es utilizar + interfaces que hagan que los módulos que funcionan con un almacenamiento sean aplicables a + otros almacenamientos. + +## Referencias + +n/a. + diff --git a/docs/tech-specs/structured-data.he.md b/docs/tech-specs/structured-data.he.md new file mode 100644 index 00000000..348db3bf --- /dev/null +++ b/docs/tech-specs/structured-data.he.md @@ -0,0 +1,253 @@ +# מפרט טכני של נתונים מובנים + +## סקירה כללית + +מפרט זה מתאר את השילוב של TrustGraph עם זרימות נתונים מובנים, המאפשר למערכת לעבוד עם נתונים שניתן לייצג אותם כשורות בטבלאות או כאובייקטים במאגרי אובייקטים. השילוב תומך בארבעה תרחישי שימוש עיקריים: + +1. **חילוץ מנתונים לא מובנים לנתונים מובנים**: קריאת מקורות נתונים לא מובנים, זיהוי וחילוץ מבני אובייקטים, ואחסונם בפורמט טבלאי. +2. **טעינת נתונים מובנים**: טעינת נתונים שכבר נמצאים בפורמטים מובנים ישירות לחנות הנתונים המובנים, יחד עם נתונים מחולצים. +3. **שאילתות בשפה טבעית**: המרת שאלות בשפה טבעית לשאילתות מובנות כדי לחלץ נתונים תואמים מהחנות. +4. **שאילתות מובנות ישירות**: ביצוע שאילתות מובנות ישירות מול מאגר הנתונים לשליפת נתונים מדויקת. + +## מטרות + +**גישה מאוחדת לנתונים**: מתן ממשק יחיד לגישה הן לנתונים מובנים והן לנתונים לא מובנים בתוך TrustGraph. +**שילוב חלק**: אפשור תאימות הדוקה בין ייצוג הידע מבוסס הגרף של TrustGraph לבין פורמטים מובנים מסורתיים. +**חילוץ גמיש**: תמיכה בחילוץ אוטומטי של נתונים מובנים ממקורות לא מובנים שונים (מסמכים, טקסט וכו'). +**גמישות שאילתא**: לאפשר למשתמשים לשאול נתונים באמצעות שפה טבעית ושפות שאילתא מובנות. +**עקביות נתונים**: שמירה על שלמות ועקביות הנתונים בייצוגי נתונים שונים. +**אופטימיזציה של ביצועים**: הבטחת אחסון ושליפה יעילים של נתונים מובנים בקנה מידה גדול. +**גמישות סכימה**: תמיכה בגישות "סכימה בכתיבה" ו"סכימה בקריאה" כדי להתאים למקורות נתונים מגוונים. +**תאימות לאחור**: שמירה על פונקציונליות קיימת של TrustGraph תוך הוספת יכולות נתונים מובנים. + +## רקע + +TrustGraph מצטיינת כיום בעיבוד נתונים לא מובנים ובבניית גרפי ידע ממקורות מגוונים. עם זאת, תרחישי שימוש רבים בארגונים כוללים נתונים המובנים מטבעם - רשומות לקוחות, יומני עסקאות, מסדי נתונים של מלאי וערכות נתונים טבלאיים אחרים. ערכות נתונים מובנות אלו לעתים קרובות צריכות להיות מנותחות יחד עם תוכן לא מובנה כדי לספק תובנות מקיפות. + +מגבלות נוכחיות כוללות: +חוסר תמיכה מובנית בטעינת פורמטים מובנים מראש (CSV, מערכי JSON, יצוא מסדי נתונים). +חוסר יכולת לשמור על המבנה הטבעי בעת חילוץ נתונים טבלאיים ממסמכים. +היעדר מנגנוני שאילתא יעילים עבור דפוסי נתונים מובנים. +חוסר גשר בין שאילתות בסגנון SQL לשאילתות גרפיות של TrustGraph. + +מפרט זה מתייחס לפערים אלה על ידי הצגת שכבת נתונים מובנים המשלימה את היכולות הקיימות של TrustGraph. על ידי תמיכה בנתונים מובנים באופן טבעי, TrustGraph יכולה: +לשמש כפלטפורמה מאוחדת לניתוח נתונים מובנים ולא מובנים. +לאפשר שאילתות היברידיות החוצות קשרי גרף ונתונים טבלאיים. +לספק ממשקים מוכרים למשתמשים המורגלים לעבודה עם נתונים מובנים. +לפתוח תרחישי שימוש חדשים בשילוב נתונים ובינה עסקית. + +## עיצוב טכני + +### ארכיטקטורה + +השילוב של נתונים מובנים דורש את הרכיבים הטכניים הבאים: + +1. **שירות NLP ל-Structured-Query** + ממיר שאלות בשפה טבעית לשאילתות מובנות. + תומך במספר יעדי שפת שאילתא (בשלב הראשוני תחביר בסגנון SQL). + משתלב עם יכולות NLP קיימות של TrustGraph. + + מודול: trustgraph-flow/trustgraph/query/nlp_query/cassandra + +2. **תמיכה בסכימה לתצורה** ✅ **[הושלם]** + מערכת תצורה מורחבת לאחסון סכימות נתונים מובנים. + תמיכה בהגדרת מבני טבלאות, סוגי שדות ויחסים. + יכולות גרסאות סכימה ומיגרציה. + +3. **מודול חילוץ אובייקטים** ✅ **[הושלם]** + שילוב משופר של זרימת חילוץ ידע. + מזהה ומחלץ אובייקטים מובנים ממקורות לא מובנים. + שומר על מוצא וציוני אמון. + רושם מטפל תצורה (לדוגמה: trustgraph-flow/trustgraph/prompt/template/service.py) כדי לקבל נתוני תצורה ולפענח מידע סכימה. + מקבל אובייקטים ומפענח אותם לאובייקטים של ExtractedObject לצורך העברה בתורת ההודעות Pulsar. + הערה: קיים קוד ב-`trustgraph-flow/trustgraph/extract/object/row/`. זו הייתה ניסיון קודם וצריך לשכתב אותו באופן משמעותי מכיוון שהוא אינו תואם ל-APIs הנוכחיים. השתמש בו אם זה שימושי, התחל מאפס אם לא. + דורש ממשק שורת פקודה: `kg-extract-objects` + + מודול: trustgraph-flow/trustgraph/extract/kg/objects/ + +4. **מודול כתיבת אחסון מובנה** ✅ **[הושלם]** + מקבל אובייקטים בפורמט ExtractedObject מתורי Pulsar. + יישום ראשוני המכוון ל-Apache Cassandra כאחסון נתונים מובנים. + מטפל ביצירת טבלאות דינמית על סמך סכימות המתגלות. + מנהל מיפוי סכימה לטבלאות Cassandra והמרת נתונים. + מספק פעולות כתיבה באצווה ובסטרימינג לשיפור ביצועים. + אין פלטים של Pulsar - זוהי שירות סופי בזרימת הנתונים. + + **טיפול בסכימה**: + מנטר הודעות ExtractedObject נכנסות עבור הפניות סכימה. + כאשר מתגלה סכימה חדשה בפעם הראשונה, יוצרת טבלה באופן אוטומטי. + תומך בגישות "סכימה בקריאה" ו"סכימה בכתיבה" כדי להתאים למקורות נתונים מגוונים. + +פלט חוזה (יש לעקוב בדיוק אחר הפורמט הבא). + **מיפוי טבלאות Cassandra**: + מרחב הנתונים (Keyspace) נקרא על שם השדה `user` מתוך מטא-הנתונים של ExtractedObject. + הטבלה נקראת על שם השדה `schema_name` מתוך ExtractedObject. + אוסף מתוך מטא-הנתונים הופך לחלק ממפתח המחיצה (partition key) כדי להבטיח: + התפלגות נתונים טבעית על פני צמתים של Cassandra. + שאילתות יעילות בתוך אוסף ספציפי. + בידוד לוגי בין יבוא נתונים/מקורות שונים. + מבנה מפתח ראשי: `PRIMARY KEY ((collection, ), )`. + האוסף הוא תמיד הרכיב הראשון של מפתח המחיצה. + שדות מפתח ראשי המוגדרים בסכימה מופיעים כחלק ממפתח המחיצה המורכב. + זה דורש ששאילתות יציינו את האוסף, מה שמבטיח ביצועים צפויים. + הגדרות שדות ממופות לעמודות של Cassandra עם המרות סוג: + `string` → `text`. + `integer` → `int` או `bigint` בהתאם לרמז לגודל. + `float` → `float` או `double` בהתאם לדרישות דיוק. + `boolean` → `boolean`. + `timestamp` → `timestamp`. + `enum` → `text` עם אימות ברמת היישום. + שדות עם אינדקס יוצרים אינדקסים משניים של Cassandra (למעט שדות שכבר נמצאים במפתח הראשי). + שדות חובה מיושמים ברמת היישום (Cassandra אינה תומכת ב-NOT NULL). + + **אחסון אובייקטים**: + מחלץ ערכים ממפת ExtractedObject.values. + מבצע המרת סוג ואימות לפני הכנסה. + מטפל בשדות אופציונליים חסרים בצורה חלקה. + שומר על מטא-נתונים לגבי מקור האובייקט (מסמך מקור, ציוני אמון). + תומך בכתיבות אידמפוטנטיות כדי לטפל בתרחישי שידור חוזר של הודעות. + + **הערות יישום**: + קוד קיים ב-`trustgraph-flow/trustgraph/storage/objects/cassandra/` מיושן ואינו תואם ל-APIs הנוכחיים. + יש להתייחס ל-`trustgraph-flow/trustgraph/storage/triples/cassandra` כדוגמה למעבד אחסון תקין. + יש להעריך את הקוד הקיים כדי לזהות רכיבים שניתן לעשות בהם שימוש חוזר לפני שמחליטים לבצע שינוי מבני או כתיבה מחדש. + + מודול: trustgraph-flow/trustgraph/storage/objects/cassandra + +5. **שירות שאילתות מובנה** ✅ **[הושלם]** + מקבל שאילתות מובנות בפורמטים מוגדרים. + מבצע שאילתות על הנתונים המובנים. + מחזיר אובייקטים התואמים לקריטריוני השאילתה. + תומך בדפדוף וסינון תוצאות. + + מודול: trustgraph-flow/trustgraph/query/objects/cassandra + +6. **אינטגרציה עם כלי סוכן**: + מחלקת כלי חדשה עבור מסגרות סוכן. + מאפשר לסוכנים לשאול נתונים מובנים. + מספק ממשקי שפה טבעית ושאילתות מובנות. + משתלב עם תהליכי קבלת החלטות קיימים של סוכנים. + +7. **שירות הכנסת נתונים מובנים**: + מקבל נתונים מובנים בפורמטים מרובים (JSON, CSV, XML). + מנתח ומאמת נתונים נכנסים בהתאם לסכימות מוגדרות. + ממיר נתונים לזרמי אובייקטים מנורמלים. + פולט אובייקטים לתורי הודעות מתאימים לעיבוד. + תומך בהעלאות אצווה ובהכנסה רציפה. + + מודול: trustgraph-flow/trustgraph/decoding/structured + +8. **שירות הטמעת אובייקטים**: + מייצר הטמעות וקטוריות עבור אובייקטים מובנים. + מאפשר חיפוש סמנטי על פני נתונים מובנים. + תומך בחיפוש היברידי המשלב שאילתות מובנות עם דמיון סמנטי. + משתלב עם מאגרי וקטורים קיימים. + + מודול: trustgraph-flow/trustgraph/embeddings/object_embeddings/qdrant + +### מודלים של נתונים + +#### מנגנון אחסון סכימות + +סכימות מאוחסנות במערכת התצורה של TrustGraph באמצעות המבנה הבא: + +**סוג**: `schema` (ערך קבוע עבור כל סכימות הנתונים המובנים). +**מפתח**: השם/מזהה הייחודי של הסכימה (לדוגמה, `customer_records`, `transaction_log`). +**ערך**: הגדרת סכימת JSON המכילה את המבנה. + +רשומה לדוגמה בתצורה: +``` +Type: schema +Key: customer_records +Value: { + "name": "customer_records", + "description": "Customer information table", + "fields": [ + { + "name": "customer_id", + "type": "string", + "primary_key": true + }, + { + "name": "name", + "type": "string", + "required": true + }, + { + "name": "email", + "type": "string", + "required": true + }, + { + "name": "registration_date", + "type": "timestamp" + }, + { + "name": "status", + "type": "string", + "enum": ["active", "inactive", "suspended"] + } + ], + "indexes": ["email", "registration_date"] +} +``` + +גישה זו מאפשרת: +הגדרה דינמית של סכימה ללא שינויים בקוד +עדכונים וגרסאות קלים של הסכימה +אינטגרציה עקבית עם ניהול התצורה הקיים של TrustGraph +תמיכה במספר סכימות בתוך פריסה אחת + +### ממשקי API + +ממשקי API חדשים: + סכימות Pulsar עבור הסוגים שלעיל + ממשקי Pulsar בזרמים חדשים + נדרש אמצעי לציין סוגי סכימה בזרמים כך שהזרמים ידעו אילו + סוגי סכימה לטעון + ממשקי API נוספו לשער ולשער ההיפוך + +ממשקי API ששונו: +נקודות קצה לחילוץ ידע - הוספת אפשרות פלט של אובייקט מובנה +נקודות קצה של סוכנים - הוספת תמיכה בכלי נתונים מובנים + +### פרטי יישום + +בהתאם לקונבנציות קיימות - אלו מודולים חדשים לעיבוד בלבד. +הכל נמצא בחבילות trustgraph-flow למעט פריטי סכימה +ב-trustgraph-base. + +נדרשת עבודה כלשהי בממשק המשתמש ב-Workbench כדי שניתן יהיה להדגים / לבצע פיילוט +ליכולת זו. + +## שיקולי אבטחה + +אין שיקולים נוספים. + +## שיקולי ביצועים + +ישנן שאלות בנוגע לשימוש בשאילתות ואינדקסים של Cassandra כך ששאלות +לא יאטו את העבודה. + +## אסטרטגיית בדיקה + +יש להשתמש באסטרטגיית בדיקה קיימת, ייבנו בדיקות יחידה, חוזה ואינטגרציה. + +## תוכנית מעבר + +אין. + +## ציר זמן + +לא צוין. + +## שאלות פתוחות + +האם ניתן לגרום לזה לעבוד עם סוגי אחסון אחרים? אנו שואפים להשתמש + בממשקים אשר הופכים מודולים שעובדים עם אחסון אחד ליישומיים + לאחסון אחר. + +## הפניות + +n/a. + diff --git a/docs/tech-specs/structured-data.hi.md b/docs/tech-specs/structured-data.hi.md new file mode 100644 index 00000000..1fa1ceff --- /dev/null +++ b/docs/tech-specs/structured-data.hi.md @@ -0,0 +1,253 @@ +# संरचित डेटा तकनीकी विनिर्देश + +## अवलोकन + +यह विनिर्देश ट्रस्टग्राफ को संरचित डेटा प्रवाह के साथ एकीकृत करने का वर्णन करता है, जिससे सिस्टम डेटा के साथ काम कर सके जिसे तालिकाओं में पंक्तियों या ऑब्जेक्ट स्टोर में ऑब्जेक्ट के रूप में दर्शाया जा सकता है। यह एकीकरण चार प्राथमिक उपयोग मामलों का समर्थन करता है: + +1. **असंरचित से संरचित निष्कर्षण**: असंरचित डेटा स्रोतों को पढ़ें, ऑब्जेक्ट संरचनाओं की पहचान करें और उन्हें निकालें, और उन्हें एक सारणीबद्ध प्रारूप में संग्रहीत करें। +2. **संरचित डेटा का अंतर्ग्रहण**: डेटा को जो पहले से ही संरचित प्रारूपों में है, उसे सीधे संरचित स्टोर में निकाले गए डेटा के साथ लोड करें। +3. **प्राकृतिक भाषा प्रश्न**: प्राकृतिक भाषा के प्रश्नों को संरचित प्रश्नों में परिवर्तित करें ताकि स्टोर से मिलान करने वाले डेटा को निकाला जा सके। +4. **प्रत्यक्ष संरचित प्रश्न**: सटीक डेटा पुनर्प्राप्ति के लिए डेटा स्टोर के खिलाफ सीधे संरचित प्रश्नों को निष्पादित करें। + +## लक्ष्य + +**एकीकृत डेटा एक्सेस**: ट्रस्टग्राफ के भीतर संरचित और असंरचित दोनों डेटा तक पहुंचने के लिए एक एकल इंटरफ़ेस प्रदान करें। +**निर्बाध एकीकरण**: ट्रस्टग्राफ के ग्राफ-आधारित ज्ञान प्रतिनिधित्व और पारंपरिक संरचित डेटा प्रारूपों के बीच सुचारू अंतर-संचालन को सक्षम करें। +**लचीला निष्कर्षण**: विभिन्न असंरचित स्रोतों (दस्तावेज़, पाठ, आदि) से संरचित डेटा के स्वचालित निष्कर्षण का समर्थन करें। +**प्रश्न बहुमुखी प्रतिभा**: उपयोगकर्ताओं को प्राकृतिक भाषा और संरचित प्रश्न भाषाओं दोनों का उपयोग करके डेटा क्वेरी करने की अनुमति दें। +**डेटा स्थिरता**: विभिन्न डेटा प्रतिनिधित्व में डेटा अखंडता और स्थिरता बनाए रखें। +**प्रदर्शन अनुकूलन**: पैमाने पर संरचित डेटा के कुशल भंडारण और पुनर्प्राप्ति सुनिश्चित करें। +**स्कीमा लचीलापन**: विभिन्न डेटा स्रोतों को समायोजित करने के लिए स्कीमा-ऑन-राइट और स्कीमा-ऑन-रीड दोनों दृष्टिकोणों का समर्थन करें। +**पिछड़ा संगतता**: संरचित डेटा क्षमताओं को जोड़ते समय मौजूदा ट्रस्टग्राफ कार्यक्षमता को संरक्षित करें। + +## पृष्ठभूमि + +ट्रस्टग्राफ वर्तमान में असंरचित डेटा को संसाधित करने और विभिन्न स्रोतों से ज्ञान ग्राफ बनाने में उत्कृष्ट है। हालाँकि, कई उद्यम उपयोग मामलों में डेटा शामिल होता है जो स्वाभाविक रूप से संरचित होता है - ग्राहक रिकॉर्ड, लेनदेन लॉग, इन्वेंट्री डेटाबेस और अन्य सारणीबद्ध डेटासेट। इन संरचित डेटासेट का अक्सर व्यापक अंतर्दृष्टि प्रदान करने के लिए असंरचित सामग्री के साथ विश्लेषण करने की आवश्यकता होती है। + +वर्तमान सीमाएँ शामिल हैं: +पूर्व-संरचित डेटा प्रारूपों (CSV, JSON सरणियों, डेटाबेस निर्यात) को अंतर्ग्रहण करने के लिए कोई देशी समर्थन नहीं। +दस्तावेज़ों से सारणीबद्ध डेटा निकालते समय अंतर्निहित संरचना को संरक्षित करने में असमर्थता। +संरचित डेटा पैटर्न के लिए कुशल प्रश्न तंत्र की कमी। +SQL-जैसे प्रश्नों और ट्रस्टग्राफ के ग्राफ प्रश्नों के बीच कोई पुल नहीं। + +यह विनिर्देश इन कमियों को एक संरचित डेटा परत पेश करके संबोधित करता है जो ट्रस्टग्राफ की मौजूदा क्षमताओं को पूरक करता है। संरचित डेटा का मूल रूप से समर्थन करके, ट्रस्टग्राफ: +संरचित और असंरचित दोनों डेटा विश्लेषण के लिए एक एकीकृत मंच के रूप में कार्य कर सकता है। +ग्राफ संबंधों और सारणीबद्ध डेटा दोनों को कवर करने वाले हाइब्रिड प्रश्नों को सक्षम कर सकता है। +संरचित डेटा के साथ काम करने के लिए अभ्यस्त उपयोगकर्ताओं के लिए परिचित इंटरफेस प्रदान कर सकता है। +डेटा एकीकरण और व्यावसायिक बुद्धिमत्ता में नए उपयोग मामलों को अनलॉक कर सकता है। + +## तकनीकी डिजाइन + +### वास्तुकला + +संरचित डेटा एकीकरण के लिए निम्नलिखित तकनीकी घटकों की आवश्यकता होती है: + +1. **एनएलपी-टू-स्ट्रक्चर्ड-क्वेरी सेवा** + प्राकृतिक भाषा के प्रश्नों को संरचित प्रश्नों में परिवर्तित करता है। + कई प्रश्न भाषा लक्ष्यों का समर्थन करता है (प्रारंभ में SQL-जैसे सिंटैक्स)। + मौजूदा ट्रस्टग्राफ एनएलपी क्षमताओं के साथ एकीकृत होता है। + + मॉड्यूल: trustgraph-flow/trustgraph/query/nlp_query/cassandra + +2. **कॉन्फ़िगरेशन स्कीमा समर्थन** ✅ **[पूर्ण]** + संरचित डेटा स्कीमा को संग्रहीत करने के लिए विस्तारित कॉन्फ़िगरेशन सिस्टम। + तालिका संरचनाओं, फ़ील्ड प्रकारों और संबंधों को परिभाषित करने का समर्थन। + स्कीमा संस्करण और माइग्रेशन क्षमताएं। + +3. **ऑब्जेक्ट निष्कर्षण मॉड्यूल** ✅ **[पूर्ण]** + बेहतर ज्ञान निष्कर्षण प्रवाह एकीकरण। + असंरचित स्रोतों से संरचित ऑब्जेक्ट की पहचान और निष्कर्षण। + उत्पत्ति और आत्मविश्वास स्कोर बनाए रखता है। + एक कॉन्फ़िग हैंडलर (उदाहरण: trustgraph-flow/trustgraph/prompt/template/service.py) को कॉन्फ़िग डेटा प्राप्त करने और स्कीमा जानकारी को डिकोड करने के लिए पंजीकृत करता है। + ऑब्जेक्ट प्राप्त करता है और उन्हें पल्सर कतार पर डिलीवरी के लिए एक्सट्रैक्टेडऑब्जेक्ट ऑब्जेक्ट में डिकोड करता है। + ध्यान दें: `trustgraph-flow/trustgraph/extract/object/row/` पर मौजूदा कोड है। यह एक पिछला प्रयास था और इसे वर्तमान एपीआई के अनुरूप नहीं होने के कारण प्रमुख रूप से फिर से तैयार करने की आवश्यकता होगी। यदि यह उपयोगी है तो इसका उपयोग करें, यदि नहीं तो इसे खरोंच से शुरू करें। + एक कमांड-लाइन इंटरफ़ेस की आवश्यकता है: `kg-extract-objects` + + मॉड्यूल: trustgraph-flow/trustgraph/extract/kg/objects/ + +4. **संरचित स्टोर लेखक मॉड्यूल** ✅ **[पूर्ण]** + पल्सर कतारों से एक्सट्रैक्टेडऑब्जेक्ट प्रारूप में ऑब्जेक्ट प्राप्त करता है। + Apache Cassandra को संरचित डेटा स्टोर के रूप में लक्षित करने वाला प्रारंभिक कार्यान्वयन। + सामना किए गए स्कीमा के आधार पर गतिशील तालिका निर्माण को संभालता है। + स्कीमा-से-कैसेंड्रा तालिका मैपिंग और डेटा परिवर्तन का प्रबंधन करता है। + प्रदर्शन अनुकूलन के लिए बैच और स्ट्रीमिंग लेखन संचालन प्रदान करता है। + कोई पल्सर आउटपुट नहीं - यह डेटा प्रवाह में एक टर्मिनल सेवा है। + + **स्कीमा हैंडलिंग**: + स्कीमा संदर्भों के लिए आने वाले एक्सट्रैक्टेडऑब्जेक्ट संदेशों की निगरानी करता है। + पहली बार जब एक नया स्कीमा सामना किया जाता है, तो स्वचालित रूप से संबंधित कैसेंड्रा तालिका बनाता है। + ज्ञात स्कीमा के एक कैश को बनाए रखता है ताकि अनावश्यक तालिका निर्माण प्रयासों से बचा जा सके। + इस पर विचार करना चाहिए कि स्कीमा परिभाषाएँ सीधे प्राप्त की जानी चाहिए या एक्सट्रैक्टेडऑब्जेक्ट संदेशों में स्कीमा नामों पर भरोसा किया जाना चाहिए। + + **कैसेंड्रा टेबल मैपिंग**: + कीस्पेस का नाम एक्सट्रैक्टेडऑब्जेक्ट के मेटाडेटा से `user` फ़ील्ड से लिया गया है। + टेबल का नाम एक्सट्रैक्टेडऑब्जेक्ट से `schema_name` फ़ील्ड से लिया गया है। + मेटाडेटा से कलेक्शन को पार्टीशन कुंजी का हिस्सा बनाया जाता है ताकि: + कैसेंड्रा नोड्स में डेटा का प्राकृतिक वितरण सुनिश्चित हो सके। + एक विशिष्ट कलेक्शन के भीतर कुशल क्वेरीज़ संभव हों। + विभिन्न डेटा आयात/स्रोत के बीच तार्किक अलगाव सुनिश्चित हो सके। + प्राइमरी की संरचना: `PRIMARY KEY ((collection, ), )` + कलेक्शन हमेशा पार्टीशन कुंजी का पहला घटक होता है। + स्कीमा-परिभाषित प्राइमरी की फ़ील्ड, समग्र पार्टीशन कुंजी का हिस्सा होते हैं। + इसके लिए क्वेरीज़ में कलेक्शन को निर्दिष्ट करने की आवश्यकता होती है, जिससे प्रदर्शन पूर्वानुमेय रहता है। + फ़ील्ड परिभाषाएँ कैसेंड्रा कॉलम में टाइप रूपांतरण के साथ मैप होती हैं: + `string` → `text` + `integer` → `int` या `bigint`, आकार के संकेत के आधार पर। + `float` → `float` या `double`, परिशुद्धता की आवश्यकताओं के आधार पर। + `boolean` → `boolean` + `timestamp` → `timestamp` + `enum` → `text`, एप्लिकेशन-स्तरीय सत्यापन के साथ। + अनुक्रमित फ़ील्ड कैसेंड्रा सेकेंडरी इंडेक्स बनाते हैं (प्राइमरी कुंजी में पहले से मौजूद फ़ील्ड को छोड़कर)। + आवश्यक फ़ील्ड एप्लिकेशन स्तर पर लागू किए जाते हैं (कैसेंड्रा NOT NULL का समर्थन नहीं करता है)। + + **ऑब्जेक्ट स्टोरेज**: + एक्सट्रैक्टेडऑब्जेक्ट.वैल्यूज़ मैप से मान निकाले जाते हैं। + सम्मिलन से पहले टाइप रूपांतरण और सत्यापन किया जाता है। + गुम वैकल्पिक फ़ील्ड को कुशलतापूर्वक संभाला जाता है। + ऑब्जेक्ट की उत्पत्ति के बारे में मेटाडेटा बनाए रखा जाता है (स्रोत दस्तावेज़, आत्मविश्वास स्कोर)। + संदेश पुनरावृत्ति परिदृश्यों को संभालने के लिए आइडेंपोटेंट राइट का समर्थन करता है। + + **कार्यान्वयन नोट्स**: + `trustgraph-flow/trustgraph/storage/objects/cassandra/` पर मौजूद मौजूदा कोड पुराना है और वर्तमान एपीआई के अनुरूप नहीं है। + `trustgraph-flow/trustgraph/storage/triples/cassandra` को एक कार्यशील स्टोरेज प्रोसेसर के उदाहरण के रूप में संदर्भित किया जाना चाहिए। + पुन: उपयोग करने योग्य घटकों के लिए मौजूदा कोड का मूल्यांकन किया जाना चाहिए, फिर रिफैक्टर या फिर से लिखने का निर्णय लिया जाना चाहिए। + + मॉड्यूल: trustgraph-flow/trustgraph/storage/objects/cassandra + +5. **स्ट्रक्चर्ड क्वेरी सर्विस** ✅ **[पूर्ण]** + परिभाषित प्रारूपों में संरचित क्वेरी स्वीकार करता है। + संरचित स्टोर के खिलाफ क्वेरी निष्पादित करता है। + क्वेरी मानदंडों से मेल खाने वाले ऑब्जेक्ट लौटाता है। + पेजिंग और परिणाम फ़िल्टरिंग का समर्थन करता है। + + मॉड्यूल: trustgraph-flow/trustgraph/query/objects/cassandra + +6. **एजेंट टूल इंटीग्रेशन**: + एजेंट फ्रेमवर्क के लिए एक नया टूल क्लास। + एजेंटों को संरचित डेटा स्टोर से क्वेरी करने में सक्षम बनाता है। + प्राकृतिक भाषा और संरचित क्वेरी इंटरफेस प्रदान करता है। + मौजूदा एजेंट निर्णय लेने की प्रक्रियाओं के साथ एकीकृत होता है। + +7. **स्ट्रक्चर्ड डेटा इंजेक्शन सर्विस**: + कई प्रारूपों (JSON, CSV, XML) में संरचित डेटा स्वीकार करता है। + परिभाषित स्कीमा के खिलाफ आने वाले डेटा को पार्स और सत्यापित करता है। + डेटा को सामान्यीकृत ऑब्जेक्ट स्ट्रीम में परिवर्तित करता है। + प्रसंस्करण के लिए उपयुक्त संदेश कतारों में ऑब्जेक्ट उत्सर्जित करता है। + बल्क अपलोड और स्ट्रीमिंग इंजेक्शन का समर्थन करता है। + + मॉड्यूल: trustgraph-flow/trustgraph/decoding/structured + +8. **ऑब्जेक्ट एम्बेडिंग सर्विस**: + संरचित ऑब्जेक्ट के लिए वेक्टर एम्बेडिंग उत्पन्न करता है। + संरचित डेटा में सिमेंटिक खोज को सक्षम करता है। + संरचित क्वेरी के साथ सिमेंटिक समानता को मिलाकर हाइब्रिड खोज का समर्थन करता है। + मौजूदा वेक्टर स्टोर के साथ एकीकृत होता है। + + मॉड्यूल: trustgraph-flow/trustgraph/embeddings/object_embeddings/qdrant + +### डेटा मॉडल: + +#### स्कीमा स्टोरेज मैकेनिज्म: + +स्कीमा को ट्रस्टग्राफ की कॉन्फ़िगरेशन प्रणाली में निम्नलिखित संरचना का उपयोग करके संग्रहीत किया जाता है: + +**टाइप**: `schema` (सभी संरचित डेटा स्कीमा के लिए एक निश्चित मान)। +**की**: स्कीमा का अद्वितीय नाम/पहचानकर्ता (जैसे, `customer_records`, `transaction_log`)। +**वैल्यू**: संरचना वाली JSON स्कीमा परिभाषा। + +उदाहरण कॉन्फ़िगरेशन प्रविष्टि: +``` +Type: schema +Key: customer_records +Value: { + "name": "customer_records", + "description": "Customer information table", + "fields": [ + { + "name": "customer_id", + "type": "string", + "primary_key": true + }, + { + "name": "name", + "type": "string", + "required": true + }, + { + "name": "email", + "type": "string", + "required": true + }, + { + "name": "registration_date", + "type": "timestamp" + }, + { + "name": "status", + "type": "string", + "enum": ["active", "inactive", "suspended"] + } + ], + "indexes": ["email", "registration_date"] +} +``` + +यह दृष्टिकोण निम्नलिखित कार्य करने की अनुमति देता है: +कोड में बदलाव किए बिना गतिशील स्कीमा परिभाषा +आसान स्कीमा अपडेट और संस्करण +मौजूदा ट्रस्टग्राफ कॉन्फ़िगरेशन प्रबंधन के साथ सुसंगत एकीकरण +एक ही परिनियोजन में एकाधिक स्कीमा के लिए समर्थन + +### एपीआई + +नए एपीआई: + ऊपर दिए गए प्रकारों के लिए पल्सर स्कीमा + नए फ्लो में पल्सर इंटरफेस + फ्लो को यह जानने के लिए कि कौन से + स्कीमा प्रकार लोड करने हैं, फ्लो में स्कीमा प्रकारों को निर्दिष्ट करने का एक तरीका आवश्यक है। + गेटवे और रिव-गेटवे में जोड़े गए एपीआई + +संशोधित एपीआई: +नॉलेज एक्सट्रैक्शन एंडपॉइंट - संरचित ऑब्जेक्ट आउटपुट विकल्प जोड़ें +एजेंट एंडपॉइंट - संरचित डेटा टूल समर्थन जोड़ें + +### कार्यान्वयन विवरण + +मौजूदा सम्मेलनों का पालन करें - ये केवल नए प्रोसेसिंग मॉड्यूल हैं। +सब कुछ ट्रस्टग्राफ-फ्लो पैकेजों में है, सिवाय ट्रस्टग्राफ-बेस में स्कीमा आइटम के। + + +इस क्षमता का प्रदर्शन/पायलट करने के लिए वर्कबेंच में कुछ यूआई कार्य की आवश्यकता है। + + +## सुरक्षा संबंधी विचार + +कोई अतिरिक्त विचार नहीं। + +## प्रदर्शन संबंधी विचार + +कैसेंड्रा प्रश्नों और इंडेक्स का उपयोग करने के बारे में कुछ प्रश्न हैं ताकि प्रश्न धीमे न हों। + +## परीक्षण रणनीति + +मौजूदा परीक्षण रणनीति का उपयोग करें, यूनिट, कॉन्ट्रैक्ट और एकीकरण परीक्षण बनाए जाएंगे। + +## माइग्रेशन योजना + +कोई नहीं। + +## समयरेखा + +निर्दिष्ट नहीं है। + +## खुले प्रश्न + + +क्या इसे अन्य स्टोर प्रकारों के साथ काम करने के लिए बनाया जा सकता है? हम इंटरफेस का उपयोग करने का लक्ष्य रख रहे हैं जो एक स्टोर के साथ काम करने वाले मॉड्यूल को अन्य स्टोर पर लागू करने योग्य बनाते हैं। + + ## संदर्भ + +लागू नहीं। + + + diff --git a/docs/tech-specs/structured-data.pt.md b/docs/tech-specs/structured-data.pt.md new file mode 100644 index 00000000..02dd93d5 --- /dev/null +++ b/docs/tech-specs/structured-data.pt.md @@ -0,0 +1,253 @@ +# Especificação Técnica de Dados Estruturados + +## Visão Geral + +Esta especificação descreve a integração do TrustGraph com fluxos de dados estruturados, permitindo que o sistema trabalhe com dados que podem ser representados como linhas em tabelas ou objetos em armazenamentos de objetos. A integração suporta quatro casos de uso primários: + +1. **Extração de Não Estruturado para Estruturado**: Ler fontes de dados não estruturados, identificar e extrair estruturas de objetos e armazená-las em um formato tabular. +2. **Ingestão de Dados Estruturados**: Carregar dados que já estão em formatos estruturados diretamente no armazenamento estruturado, juntamente com os dados extraídos. +3. **Consulta em Linguagem Natural**: Converter perguntas em linguagem natural em consultas estruturadas para extrair dados correspondentes do armazenamento. +4. **Consulta Estruturada Direta**: Executar consultas estruturadas diretamente contra o armazenamento de dados para recuperação precisa de dados. + +## Objetivos + +**Acesso Unificado a Dados**: Fornecer uma única interface para acessar dados estruturados e não estruturados dentro do TrustGraph. +**Integração Perfeita**: Permitir interoperabilidade perfeita entre a representação de conhecimento baseada em grafo do TrustGraph e formatos de dados estruturados tradicionais. +**Extração Flexível**: Suportar a extração automática de dados estruturados de várias fontes não estruturadas (documentos, texto, etc.). +**Versatilidade de Consulta**: Permitir que os usuários consultem dados usando linguagem natural e linguagens de consulta estruturadas. +**Consistência de Dados**: Manter a integridade e a consistência dos dados em diferentes representações de dados. +**Otimização de Desempenho**: Garantir o armazenamento e a recuperação eficientes de dados estruturados em grande escala. +**Flexibilidade de Esquema**: Suportar abordagens de esquema-na-escrita e esquema-na-leitura para acomodar diversas fontes de dados. +**Compatibilidade com Versões Anteriores**: Preservar a funcionalidade existente do TrustGraph, adicionando recursos de dados estruturados. + +## Contexto + +Atualmente, o TrustGraph se destaca no processamento de dados não estruturados e na construção de grafos de conhecimento a partir de diversas fontes. No entanto, muitos casos de uso empresariais envolvem dados que são inerentemente estruturados - registros de clientes, logs de transações, bancos de dados de inventário e outros conjuntos de dados tabulares. Esses conjuntos de dados estruturados geralmente precisam ser analisados ​​juntamente com conteúdo não estruturado para fornecer insights abrangentes. + +As limitações atuais incluem: +Ausência de suporte nativo para ingestão de formatos de dados pré-estruturados (CSV, arrays JSON, exportações de banco de dados). +Impossibilidade de preservar a estrutura inerente ao extrair dados tabulares de documentos. +Falta de mecanismos de consulta eficientes para padrões de dados estruturados. +Falta de uma ponte entre consultas semelhantes a SQL e as consultas de grafo do TrustGraph. + +Esta especificação aborda essas lacunas, introduzindo uma camada de dados estruturados que complementa as capacidades existentes do TrustGraph. Ao suportar dados estruturados nativamente, o TrustGraph pode: +Servir como uma plataforma unificada para análise de dados estruturados e não estruturados. +Permitir consultas híbridas que abrangem relacionamentos de grafo e dados tabulares. +Fornecer interfaces familiares para usuários acostumados a trabalhar com dados estruturados. +Desbloquear novos casos de uso em integração de dados e inteligência de negócios. + +## Design Técnico + +### Arquitetura + +A integração de dados estruturados requer os seguintes componentes técnicos: + +1. **Serviço de Conversão de Linguagem Natural para Consulta Estruturada** + Converte perguntas em linguagem natural em consultas estruturadas. + Suporta vários alvos de linguagem de consulta (inicialmente sintaxe semelhante a SQL). + Integra-se com as capacidades existentes de NLP do TrustGraph. + + Módulo: trustgraph-flow/trustgraph/query/nlp_query/cassandra + +2. **Suporte para Esquema de Configuração** ✅ **[COMPLETO]** + Sistema de configuração estendido para armazenar esquemas de dados estruturados. + Suporte para definir estruturas de tabela, tipos de campo e relacionamentos. + Versionamento de esquema e capacidades de migração. + +3. **Módulo de Extração de Objetos** ✅ **[COMPLETO]** + Integração aprimorada do fluxo de extração de conhecimento. + Identifica e extrai objetos estruturados de fontes não estruturadas. + Mantém a rastreabilidade e as pontuações de confiança. + Registra um manipulador de configuração (exemplo: trustgraph-flow/trustgraph/prompt/template/service.py) para receber dados de configuração e decodificar informações de esquema. + Recebe objetos e os decodifica em objetos ExtractedObject para entrega na fila Pulsar. + OBS: Existe código existente em `trustgraph-flow/trustgraph/extract/object/row/`. Esta foi uma tentativa anterior e precisará ser refatorada significativamente, pois não está em conformidade com as APIs atuais. Use-o se for útil, comece do zero se não for. + Requer uma interface de linha de comando: `kg-extract-objects` + + Módulo: trustgraph-flow/trustgraph/extract/kg/objects/ + +4. **Módulo de Escrita de Armazenamento Estruturado** ✅ **[COMPLETO]** + Recebe objetos no formato ExtractedObject de filas Pulsar. + Implementação inicial direcionada ao Apache Cassandra como o armazenamento de dados estruturados. + Lida com a criação dinâmica de tabelas com base nos esquemas encontrados. + Gerencia o mapeamento de esquema para tabela Cassandra e a transformação de dados. + Fornece operações de gravação em lote e em streaming para otimização de desempenho. + Sem saídas Pulsar - este é um serviço terminal no fluxo de dados. + + **Manipulação de Esquema**: + Monitora mensagens ExtractedObject recebidas para referências de esquema. + Quando um novo esquema é encontrado pela primeira vez, cria automaticamente a tabela Cassandra correspondente. + Mantém um cache de esquemas conhecidos para evitar tentativas redundantes de criação de tabela. + Deve considerar se deve receber definições de esquema diretamente ou confiar em nomes de esquema em mensagens ExtractedObject. + + **Mapeamento de Tabela Cassandra**: + O keyspace é nomeado a partir do campo `user` do Metadata do ExtractedObject. + A tabela é nomeada a partir do campo `schema_name` do ExtractedObject. + A coleção do Metadata se torna parte da chave de partição para garantir: + Distribuição natural dos dados em todos os nós do Cassandra. + Consultas eficientes dentro de uma coleção específica. + Isolamento lógico entre diferentes importações/fontes de dados. + Estrutura da chave primária: `PRIMARY KEY ((collection, ), )`. + A coleção é sempre o primeiro componente da chave de partição. + Os campos da chave primária definidos no esquema seguem como parte da chave de partição composta. + Isso requer que as consultas especifiquem a coleção, garantindo um desempenho previsível. + As definições de campos são mapeadas para colunas do Cassandra com conversões de tipo: + `string` → `text`. + `integer` → `int` ou `bigint` com base na dica de tamanho. + `float` → `float` ou `double` com base nas necessidades de precisão. + `boolean` → `boolean`. + `timestamp` → `timestamp`. + `enum` → `text` com validação no nível da aplicação. + Campos indexados criam índices secundários do Cassandra (excluindo campos já na chave primária). + Campos obrigatórios são aplicados no nível da aplicação (o Cassandra não suporta NOT NULL). + + **Armazenamento de Objetos**: + Extrai valores do mapa ExtractedObject.values. + Realiza conversão de tipo e validação antes da inserção. + Lida com campos opcionais ausentes de forma elegante. + Mantém metadados sobre a origem do objeto (documento de origem, pontuações de confiança). + Suporta escritas idempotentes para lidar com cenários de repetição de mensagens. + + **Observações de Implementação**: + O código existente em `trustgraph-flow/trustgraph/storage/objects/cassandra/` está desatualizado e não está em conformidade com as APIs atuais. + Deve referenciar `trustgraph-flow/trustgraph/storage/triples/cassandra` como um exemplo de um processador de armazenamento funcional. + É necessário avaliar o código existente para identificar quaisquer componentes reutilizáveis antes de decidir refatorar ou reescrever. + + Módulo: trustgraph-flow/trustgraph/storage/objects/cassandra + +5. **Serviço de Consulta Estruturada** ✅ **[COMPLETO]** + Aceita consultas estruturadas em formatos definidos. + Executa consultas no armazenamento estruturado. + Retorna objetos que correspondem aos critérios da consulta. + Suporta paginação e filtragem de resultados. + + Módulo: trustgraph-flow/trustgraph/query/objects/cassandra + +6. **Integração com Ferramenta de Agente** + Nova classe de ferramenta para frameworks de agente. + Permite que agentes consultem armazenamentos de dados estruturados. + Fornece interfaces de consulta em linguagem natural e estruturada. + Integra-se com os processos de tomada de decisão existentes dos agentes. + +7. **Serviço de Ingestão de Dados Estruturados** + Aceita dados estruturados em vários formatos (JSON, CSV, XML). + Analisa e valida os dados recebidos de acordo com os esquemas definidos. + Converte os dados em fluxos de objetos normalizados. + Emite objetos para as filas de mensagens apropriadas para processamento. + Suporta uploads em lote e ingestão em streaming. + + Módulo: trustgraph-flow/trustgraph/decoding/structured + +8. **Serviço de Incorporação de Objetos** + Gera incorporações vetoriais para objetos estruturados. + Permite a pesquisa semântica em dados estruturados. + Suporta pesquisa híbrida combinando consultas estruturadas com similaridade semântica. + Integra-se com armazenamentos de vetores existentes. + + Módulo: trustgraph-flow/trustgraph/embeddings/object_embeddings/qdrant + +### Modelos de Dados + +#### Mecanismo de Armazenamento de Esquemas + +Os esquemas são armazenados no sistema de configuração do TrustGraph usando a seguinte estrutura: + +**Type**: `schema` (valor fixo para todos os esquemas de dados estruturados) +**Key**: O nome/identificador exclusivo do esquema (por exemplo, `customer_records`, `transaction_log`) +**Value**: Definição de esquema JSON contendo a estrutura + +Exemplo de entrada de configuração: +``` +Type: schema +Key: customer_records +Value: { + "name": "customer_records", + "description": "Customer information table", + "fields": [ + { + "name": "customer_id", + "type": "string", + "primary_key": true + }, + { + "name": "name", + "type": "string", + "required": true + }, + { + "name": "email", + "type": "string", + "required": true + }, + { + "name": "registration_date", + "type": "timestamp" + }, + { + "name": "status", + "type": "string", + "enum": ["active", "inactive", "suspended"] + } + ], + "indexes": ["email", "registration_date"] +} +``` + +Esta abordagem permite: +Definição dinâmica de esquema sem alterações de código +Atualizações e versionamento de esquema fáceis +Integração consistente com o gerenciamento de configuração existente do TrustGraph +Suporte para vários esquemas dentro de um único ambiente de implantação + +### APIs + +Novas APIs: + Esquemas Pulsar para os tipos acima + Interfaces Pulsar em novos fluxos + É necessário um meio de especificar os tipos de esquema nos fluxos para que os fluxos saibam quais + tipos de esquema carregar + APIs adicionadas ao gateway e rev-gateway + +APIs modificadas: +Pontos de extremidade de extração de conhecimento - Adicionar opção de saída de objeto estruturado +Pontos de extremidade do agente - Adicionar suporte para ferramentas de dados estruturados + +### Detalhes da Implementação + +Seguindo as convenções existentes - estes são apenas novos módulos de processamento. +Tudo está nos pacotes trustgraph-flow, exceto os itens de esquema +em trustgraph-base. + +É necessário algum trabalho de interface do usuário no Workbench para poder demonstrar / testar +essa funcionalidade. + +## Considerações de Segurança + +Nenhuma consideração adicional. + +## Considerações de Desempenho + +Algumas perguntas sobre o uso de consultas e índices do Cassandra para que as consultas +não diminuam a velocidade. + +## Estratégia de Teste + +Use a estratégia de teste existente, serão criados testes unitários, de contrato e de integração. + +## Plano de Migração + +Nenhum. + +## Cronograma + +Não especificado. + +## Perguntas Abertas + +Isso pode ser adaptado para funcionar com outros tipos de armazenamento? Estamos buscando usar + interfaces que tornem os módulos que funcionam com um armazenamento aplicáveis a + outros armazenamentos. + +## Referências + +n/a. + diff --git a/docs/tech-specs/structured-data.ru.md b/docs/tech-specs/structured-data.ru.md new file mode 100644 index 00000000..490a94e5 --- /dev/null +++ b/docs/tech-specs/structured-data.ru.md @@ -0,0 +1,253 @@ +# Техническая спецификация структурированных данных + +## Обзор + +Эта спецификация описывает интеграцию TrustGraph с потоками структурированных данных, что позволяет системе работать с данными, которые могут быть представлены в виде строк в таблицах или объектов в хранилищах объектов. Интеграция поддерживает четыре основных сценария использования: + +1. **Извлечение неструктурированных данных в структурированные**: Чтение неструктурированных источников данных, выявление и извлечение объектных структур и хранение их в табличном формате. +2. **Импорт структурированных данных**: Загрузка данных, которые уже находятся в структурированных форматах, непосредственно в структурированное хранилище вместе с извлеченными данными. +3. **Запросы на естественном языке**: Преобразование вопросов, заданных на естественном языке, в структурированные запросы для извлечения соответствующих данных из хранилища. +4. **Прямые структурированные запросы**: Выполнение структурированных запросов непосредственно к хранилищу данных для точного извлечения данных. + +## Цели + +**Унифицированный доступ к данным**: Предоставление единого интерфейса для доступа как к структурированным, так и к неструктурированным данным в TrustGraph. +**Бесшовная интеграция**: Обеспечение плавного взаимодействия между графовым представлением знаний TrustGraph и традиционными форматами структурированных данных. +**Гибкое извлечение**: Поддержка автоматического извлечения структурированных данных из различных неструктурированных источников (документов, текста и т.д.). +**Универсальность запросов**: Предоставление пользователям возможности выполнять запросы к данным как на естественном языке, так и с использованием структурированных языков запросов. +**Согласованность данных**: Поддержание целостности и согласованности данных в различных представлениях. +**Оптимизация производительности**: Обеспечение эффективного хранения и извлечения структурированных данных в масштабе. +**Гибкость схемы**: Поддержка как подходов "схема при записи", так и "схема при чтении" для адаптации к различным источникам данных. +**Обратная совместимость**: Сохранение существующей функциональности TrustGraph при добавлении возможностей работы со структурированными данными. + +## Предыстория + +В настоящее время TrustGraph отлично справляется с обработкой неструктурированных данных и построением графов знаний из различных источников. Однако, многие корпоративные сценарии использования включают данные, которые изначально являются структурированными - записи о клиентах, журналы транзакций, базы данных инвентаризации и другие табличные наборы данных. Эти структурированные наборы данных часто необходимо анализировать вместе с неструктурированным контентом для получения всесторонних сведений. + +Текущие ограничения включают: +Отсутствие встроенной поддержки импорта данных в предварительно структурированных форматах (CSV, массивы JSON, экспорты баз данных). +Невозможность сохранения исходной структуры при извлечении табличных данных из документов. +Отсутствие эффективных механизмов запросов для структурированных данных. +Отсутствие моста между запросами, похожими на SQL, и графовыми запросами TrustGraph. + +Эта спецификация решает эти проблемы, вводя слой структурированных данных, который дополняет существующие возможности TrustGraph. Поддерживая структурированные данные нативно, TrustGraph может: +Служить унифицированной платформой для анализа как структурированных, так и неструктурированных данных. +Обеспечивать гибридные запросы, охватывающие как графовые отношения, так и табличные данные. +Предоставлять знакомые интерфейсы для пользователей, привыкших работать со структурированными данными. +Открывать новые сценарии использования в интеграции данных и бизнес-аналитике. + +## Технический дизайн + +### Архитектура + +Интеграция структурированных данных требует следующих технических компонентов: + +1. **Сервис преобразования естественного языка в структурированные запросы** + Преобразует вопросы, заданные на естественном языке, в структурированные запросы. + Поддерживает несколько целевых языков запросов (изначально синтаксис, похожий на SQL). + Интегрируется с существующими возможностями NLP TrustGraph. + + Модуль: trustgraph-flow/trustgraph/query/nlp_query/cassandra + +2. **Поддержка схемы конфигурации** ✅ **[ПОЛНО]** + Расширенная система конфигурации для хранения схем структурированных данных. + Поддержка определения структуры таблиц, типов полей и взаимосвязей. + Возможности версионирования и миграции схем. + +3. **Модуль извлечения объектов** ✅ **[ПОЛНО]** + Улучшенная интеграция потока извлечения знаний. + Определяет и извлекает структурированные объекты из неструктурированных источников. + Сохраняет информацию о происхождении и коэффициенты уверенности. + Регистрирует обработчик конфигурации (например: trustgraph-flow/trustgraph/prompt/template/service.py) для получения данных конфигурации и декодирования информации о схеме. + Получает объекты и декодирует их в объекты ExtractedObject для передачи в очередь Pulsar. + ВАЖНО: Существует существующий код по адресу `trustgraph-flow/trustgraph/extract/object/row/`. Это была предыдущая попытка, и его потребуется серьезно переработать, поскольку он не соответствует текущим API. Используйте его, если это полезно, начните с нуля, если нет. + Требуется интерфейс командной строки: `kg-extract-objects` + + Модуль: trustgraph-flow/trustgraph/extract/kg/objects/ + +4. **Модуль записи структурированных данных** ✅ **[ПОЛНО]** + Получает объекты в формате ExtractedObject из очередей Pulsar. + Первоначальная реализация, ориентированная на Apache Cassandra в качестве хранилища структурированных данных. + Обрабатывает динамическое создание таблиц на основе обнаруженных схем. + Управляет сопоставлением схем и таблиц Cassandra и преобразованием данных. + Предоставляет операции пакетной и потоковой записи для оптимизации производительности. + Не имеет выходных данных Pulsar - это терминальный сервис в потоке данных. + + **Обработка схем**: + Отслеживает входящие сообщения ExtractedObject на наличие ссылок на схемы. + При первом обнаружении новой схемы автоматически создает соответствующую таблицу Cassandra. + Поддерживает кэш известных схем, чтобы избежать повторных попыток создания таблиц. + Следует рассмотреть, следует ли получать определения схем напрямую или полагаться на имена схем в сообщениях ExtractedObject. + + **Сопоставление таблиц Cassandra**: + Имя пространства ключей (keyspace) берется из поля `user` из метаданных объекта ExtractedObject. + Имя таблицы берется из поля `schema_name` объекта ExtractedObject. + Коллекция из метаданных становится частью ключа секции (partition key) для обеспечения: + Естественного распределения данных между узлами Cassandra. + Эффективных запросов внутри определенной коллекции. + Логической изоляции между различными импортами данных/источниками. + Структура первичного ключа: `PRIMARY KEY ((collection, ), )`. + Коллекция всегда является первым компонентом ключа секции. + Поля, определенные в схеме, следуют за первичным ключом в виде составного ключа секции. + Это требует, чтобы запросы указывали коллекцию, что обеспечивает предсказуемую производительность. + Определение полей сопоставляется с столбцами Cassandra с преобразованием типов: + `string` → `text`. + `integer` → `int` или `bigint` в зависимости от размера. + `float` → `float` или `double` в зависимости от требуемой точности. + `boolean` → `boolean`. + `timestamp` → `timestamp`. + `enum` → `text` с проверкой на уровне приложения. + Индексированные поля создают вторичные индексы Cassandra (за исключением полей, которые уже находятся в первичном ключе). + Обязательные поля проверяются на уровне приложения (Cassandra не поддерживает NOT NULL). + + **Хранилище объектов**: + Извлекает значения из карты ExtractedObject.values. + Выполняет преобразование типов и проверку перед вставкой. + Обрабатывает отсутствующие необязательные поля корректно. + Поддерживает метаданные об источнике объекта (исходный документ, показатели достоверности). + Поддерживает идемпотентные записи для обработки сценариев повторной отправки сообщений. + + **Примечания к реализации**: + Существующий код, расположенный по адресу `trustgraph-flow/trustgraph/storage/objects/cassandra/`, устарел и не соответствует текущим API. + Следует использовать `trustgraph-flow/trustgraph/storage/triples/cassandra` в качестве примера работающего процессора хранилища. + Необходимо оценить существующий код на предмет наличия компонентов, которые можно повторно использовать, прежде чем принимать решение о рефакторинге или переписывании. + + Модуль: trustgraph-flow/trustgraph/storage/objects/cassandra + +5. **Сервис структурированных запросов** ✅ **[ЗАВЕРШЕНО]** + Принимает структурированные запросы в определенных форматах. + Выполняет запросы к структурированному хранилищу. + Возвращает объекты, соответствующие критериям запроса. + Поддерживает постраничную выдачу и фильтрацию результатов. + + Модуль: trustgraph-flow/trustgraph/query/objects/cassandra + +6. **Интеграция с инструментами агентов**: + Новый класс инструмента для фреймворков агентов. + Позволяет агентам выполнять запросы к структурированным хранилищам данных. + Предоставляет интерфейсы структурированных запросов и запросов на естественном языке. + Интегрируется с существующими процессами принятия решений агентами. + +7. **Сервис приема структурированных данных**: + Принимает структурированные данные в нескольких форматах (JSON, CSV, XML). + Разбирает и проверяет входящие данные в соответствии с определенными схемами. + Преобразует данные в нормализованные потоки объектов. + Отправляет объекты в соответствующие очереди сообщений для обработки. + Поддерживает массовую загрузку и потоковую передачу данных. + + Модуль: trustgraph-flow/trustgraph/decoding/structured + +8. **Сервис встраивания объектов**: + Генерирует векторные представления для структурированных объектов. + Обеспечивает семантический поиск по структурированным данным. + Поддерживает гибридный поиск, сочетающий структурированные запросы с семантической схожестью. + Интегрируется с существующими векторными хранилищами. + + Модуль: trustgraph-flow/trustgraph/embeddings/object_embeddings/qdrant + +### Модели данных + +#### Механизм хранения схем + +Схемы хранятся в системе конфигурации TrustGraph со следующей структурой: + +**Тип**: `schema` (фиксированное значение для всех схем структурированных данных). +**Ключ**: Уникальное имя/идентификатор схемы (например, `customer_records`, `transaction_log`). +**Значение**: Определение схемы JSON, содержащее структуру. + +Пример записи конфигурации: +``` +Type: schema +Key: customer_records +Value: { + "name": "customer_records", + "description": "Customer information table", + "fields": [ + { + "name": "customer_id", + "type": "string", + "primary_key": true + }, + { + "name": "name", + "type": "string", + "required": true + }, + { + "name": "email", + "type": "string", + "required": true + }, + { + "name": "registration_date", + "type": "timestamp" + }, + { + "name": "status", + "type": "string", + "enum": ["active", "inactive", "suspended"] + } + ], + "indexes": ["email", "registration_date"] +} +``` + +Этот подход позволяет: +Динамическое определение схемы без внесения изменений в код +Простое обновление и версионирование схемы +Последовательная интеграция с существующим управлением конфигурацией TrustGraph +Поддержка нескольких схем в рамках одного развертывания + +### API + +Новые API: + Схемы Pulsar для вышеперечисленных типов + Интерфейсы Pulsar в новых потоках + Необходим способ указания типов схем в потоках, чтобы потоки знали, какие + типы схем загружать + API добавлены в шлюз и обратный шлюз + +Измененные API: +Конечные точки извлечения знаний - Добавлена опция структурированного объектного вывода +Конечные точки агентов - Добавлена поддержка инструментов для структурированных данных + +### Детали реализации + +В соответствии с существующими соглашениями - это просто новые модули обработки. +Все находится в пакетах trustgraph-flow, за исключением элементов схемы, +находящихся в trustgraph-base. + +Требуется некоторая работа в пользовательском интерфейсе Workbench, чтобы +продемонстрировать / протестировать эту +возможность. + +## Вопросы безопасности + +Нет дополнительных соображений. + +## Вопросы производительности + +Некоторые вопросы, касающиеся использования запросов и индексов Cassandra, чтобы +запросы не замедлялись. + +## Стратегия тестирования + +Используйте существующую стратегию тестирования, будут созданы модульные, +контрактные и интеграционные тесты. + +## План миграции + +Отсутствует. + +## Сроки + +Не указаны. + +## Открытые вопросы + + Можно ли сделать так, чтобы это работало с другими типами хранилищ? Мы стремимся +использовать интерфейсы, которые делают модули, работающие с одним хранилищем, +применимыми к другим хранилищам. + +## Ссылки + diff --git a/docs/tech-specs/structured-data.sw.md b/docs/tech-specs/structured-data.sw.md new file mode 100644 index 00000000..0256493f --- /dev/null +++ b/docs/tech-specs/structured-data.sw.md @@ -0,0 +1,253 @@ +# Vipimo vya Teknisia vya Data Iliyoainishwa + +## Muhtasari + +Maelekezo haya yanaelezea jinsi TrustGraph inavyounganishwa na mtiririko wa data iliyoainishwa, na kuwezesha mfumo kufanya kazi na data ambayo inaweza kuwakilishwa kama mistari katika meza au vitu katika maduka ya vitu. Uunganisho huu unaunga mkono matumizi manne makuu: + +1. **Utoaji kutoka kwa Data Isiyoainishwa hadi Imeinishwa**: Soma vyanzo vya data visivyoainishwa, tambua na uondoe muundo wa vitu, na uihifadhi katika umbizo wa meza. +2. **Uingizaji wa Data Imeinishwa**: Pakia data ambayo tayari iko katika umbizo iliyoainishwa moja kwa moja katika duka la data iliyoainishwa pamoja na data iliyoondolewa. +3. **Uulizaje kwa Lugha Asilia**: Badilisha maswali ya lugha asilia katika maswali iliyoainishwa ili kuchuja data inayolingana kutoka kwa duka. +4. **Uulizaje wa Moja kwa Moja wa Imeinishwa**: Fanya maswali iliyoainishwa moja kwa moja dhidi ya duka la data ili kupata data kwa usahihi. + +## Lengo + +**Ufikiaji Umoja wa Data**: Toa kiungo kimoja cha kufikia data zote, iliyoainishwa na isiyoainishwa, ndani ya TrustGraph. +**Uunganisho Kamili**: Uwezesha utendaji wa pamoja kati ya uwakilishi wa maarifa wa TrustGraph unaotegemea chati na umbizo wa jadi wa data iliyoainishwa. +**Utoaji Wenye Ugumu**: Unga uondoleaji wa moja kwa moja wa data iliyoainishwa kutoka kwa vyanzo mbalimbali visivyoainishwa (nyaraka, maandishi, n.k.). +**Uwezekano wa Uulizaje**: Ruhusu watumiaji kuuliza data kwa kutumia lugha ya asilia na lugha za uulizaje iliyoainishwa. +**Ulinganifu wa Data**: Dumishe uadilifu na ulinganifu wa data katika uwakilishi tofauti wa data. +**Uboreshaji wa Utendaji**: Hakikisha uhifadhi na upekuzi wa ufanisi wa data iliyoainishwa kwa kiwango kikubwa. +**Uwezekano wa Mfumo**: Unga mifumo ya "andika-mfumo" na "soma-mfumo" ili kukidhi vyanzo tofauti vya data. +**Ulinganifu na Mifumo ya Zamani**: Dumishe utendaji wa sasa wa TrustGraph huku uongezwa uwezekano wa data iliyoainishwa. + +## Asili + +Hivi sasa, TrustGraph inafaa katika kuchakata data isiyoainishwa na kuunda chati za maarifa kutoka kwa vyanzo tofauti. Hata hivyo, matumizi mengi ya kampuni yanahusisha data ambayo ina muundo - rekodi za wateja, magogo ya miamala, hifadhi za bidhaa, na mengineyo ya seti za data za meza. Data hii iliyoainishwa mara nyingi inahitaji kuchanganuliwa pamoja na maudhui isiyoainishwa ili kutoa ufahamu kamili. + +Mapungufu ya sasa ni pamoja na: +Hakuna msaada wa asili kwa kuingiza umbizo la awali la data (CSV, safu za JSON, mauzo ya hifadhi ya data). +Uwezekano wa kutohifadhi muundo halisi wakati wa kuondoa data ya meza kutoka kwa nyaraka. +Ukosefu wa mitambo ya uulizaje ya ufanisi kwa muundo wa data iliyoainishwa. +Upungufu wa daraja kati ya maswali kama ya SQL na maswali ya chati ya TrustGraph. + +Maelekezo haya yanaashiria pengo hizi kwa kuleta safu ya data iliyoainishwa ambayo inakamilisha uwezekano wa sasa wa TrustGraph. Kwa kusaidia data iliyoainishwa kwa asili, TrustGraph inaweza: +Kutoa jukwaa la umoja kwa uchanganuzi wa data iliyoainishwa na isiyoainishwa. +Kuwezesha maswali ya mchanganyiko ambayo yanaenea katika uhusiano wa chati na data ya meza. +Kutoa kiungo cha kawaida kwa watumiaji ambao wamezoea kufanya kazi na data iliyoainishwa. +Kufungua matumizi mapya katika ujumuishaji wa data na ujasusi wa biashara. + +## Muundo wa Kiufundi + +### Usanifu + +Uunganisho wa data iliyoainishwa unahitaji vipengele vifuatavyo vya kiufundi: + +1. **Huduma ya NLP-kwa-Uulizaje-Imeinishwa** + Inabadilisha maswali ya lugha asilia katika maswali iliyoainishwa. + Inasaidia malengo mengi ya lugha ya uulizaje (hasa, usanifu kama wa SQL). + Inaunganishwa na uwezekano wa sasa wa NLP ya TrustGraph. + + Moduli: trustgraph-flow/trustgraph/query/nlp_query/cassandra + +2. **Usaidizi wa Mfumo wa Mpangilio** ✅ **[IMEKAMILIKA]** + Mfumo ulioongezwa wa mpangilio ili kuhifadhi umbizo wa data iliyoainishwa. + Usaidizi wa kufafanua muundo wa meza, aina za sehemu, na uhusiano. + Utoleaji wa toleo na uwezekano wa uhamishaji wa mfumo. + +3. **Moduli ya Utoaji wa Vitu** ✅ **[IMEKAMILIKA]** + Uunganisho uliorekebishwa wa mtiririko wa uondoleaji wa maarifa. + Inatambua na kuondoa vitu vilivyoainishwa kutoka kwa vyanzo visivyoainishwa. + Inahifadhi asili na alama za uaminifu. + Inasajili kiungo cha usanidi (mfano: trustgraph-flow/trustgraph/prompt/template/service.py) ili kupokea data ya usanidi na kuondoa maelezo ya mfumo. + Inapokea vitu na kuyaondoa kuwa vitu vya ExtractedObject ili kuwasilisha kwenye folyo ya Pulsar. + NOTE: Kuna msimbo uliopo kwenye `trustgraph-flow/trustgraph/extract/object/row/`. Hii ilikuwa jaribio la awali na itahitaji marekebisho makubwa kwani haikubaliana na API za sasa. Tumia ikiwa ni muhimu, anza kutoka mwanzo ikiwa sio. + Inahitaji kiungo cha mstari wa amri: `kg-extract-objects` + + Moduli: trustgraph-flow/trustgraph/extract/kg/objects/ + +4. **Moduli ya Kuandika ya Duka la Imeinishwa** ✅ **[IMEKAMILIKA]** + Inapokea vitu katika umbizo wa ExtractedObject kutoka kwa folyo za Pulsar. + Utumiaji wa awali unalenga Apache Cassandra kama duka la data iliyoainishwa. + Inashughulikia uundaji wa meza ya moja kwa moja kulingana na umbizo uliokutana. + Inadhibiti ramani ya mfumo-kwa-meza ya Cassandra na ubadilishaji wa data. + Inatoa operesheni za kuandika za kundi na za mtiririko kwa uboreshaji wa utendaji. + Hakuna matokeo ya Pulsar - hii ni huduma ya mwisho katika mtiririko wa data. + + **Ushughulikiaji wa Mfumo**: + Inafuatilia meseji zinazoingia za ExtractedObject kwa marejeleo ya mfumo. + + + Inapaswa kuzingatia kama itapokea maelezo ya muundo moja kwa moja au itategemea majina ya muundo katika ujumbe wa ExtractedObject. + + **Ramapishi ya Jedwali la Cassandra**: + Jina la keyspace linatokana na sehemu `user` kutoka Metadata ya ExtractedObject + Jina la jedwali linatokana na sehemu `schema_name` kutoka ExtractedObject + Mkusanyiko kutoka Metadata unakuwa sehemu ya ufunguo wa partition ili kuhakikisha: + Usambazaji wa data kwa njia ya asili katika nodi za Cassandra + Maswali (queries) bora ndani ya mkusanyiko maalum + Utengano wa mantiki kati ya uingizaji wa data tofauti/vyanzo + Muundo wa ufunguo mkuu: `PRIMARY KEY ((collection, ), )` + Mkusanyiko huwa sehemu ya kwanza ya ufunguo wa partition + Sehemu za ufunguo mkuu zilizobainishwa katika schema zinafuata kama sehemu ya ufunguo wa partition iliyounganishwa + Hii inahitaji maswali (queries) yataonyesha mkusanyiko, kuhakikisha utendaji unaoweza kutabirika + Ufafanuzi wa sehemu unahusishwa na safu za Cassandra na mabadiliko ya aina: + `string` → `text` + `integer` → `int` au `bigint` kulingana na ukubwa + `float` → `float` au `double` kulingana na mahitaji ya usahihi + `boolean` → `boolean` + `timestamp` → `timestamp` + `enum` → `text` na uthibitishaji wa kiwango cha programu + Sehemu zilizo na fahirisi huunda fahirisi za sekondari za Cassandra (isipokuwa sehemu zilizopo katika ufunguo mkuu) + Sehemu zinazohitajika zinafanywa katika kiwango cha programu (Cassandra haitumii NOT NULL) + + **Hifadhi ya Data (Object Storage)**: + Inatoa maadili kutoka ramani ya ExtractedObject.values + Inafanya mabadiliko ya aina na uthibitishaji kabla ya kuingizwa + Inashughulikia sehemu za hiari ambazo hazipo kwa utulivu + Inahifadhi metadata kuhusu asili ya data (hati ya chanzo, alama za uaminifu) + Inasaidia uandikaji ambao unaweza kufanywa tena ili kushughulikia hali za kucheza tena ujumbe + + **Maelezo ya Utendaji**: + Msimbo uliopo katika `trustgraph-flow/trustgraph/storage/objects/cassandra/` ni wa zamani na haukidhi vipimo vya sasa vya API + Inapaswa kurejelea `trustgraph-flow/trustgraph/storage/triples/cassandra` kama mfano wa mchakato wa hifadhi unaofanya kazi + Inahitaji tathmini ya msimbo uliopo ili kuona ikiwa kuna sehemu ambazo zinaweza kutumika tena kabla ya kuamua kufanya marekebisho au kuandika upya + + Moduli: trustgraph-flow/trustgraph/storage/objects/cassandra + +5. **Huduma ya Maswali (Structured Query Service)** ✅ **[IMEKAMILIKA]** + Inakubali maswali ya muundo katika muundo uliotolewa + Inatekeleza maswali dhidi ya hifadhi ya muundo + Inarudisha data inayolingana na vigezo vya swali + Inasaidia upangishaji na uchujaji wa matokeo + + Moduli: trustgraph-flow/trustgraph/query/objects/cassandra + +6. **Uunganisho wa Zana za Wakala (Agent Tool Integration)** + Darasa jipya la zana kwa mifumo ya wakala + Inaruhusu wakala kuuliza hifadhi za data zilizopangwa + Inatoa interfaces ya lugha ya asili na maswali ya muundo + Inajumuishwa na michakato iliyopo ya wakala ya kufanya maamuzi + +7. **Huduma ya Uingizaji wa Data Iliyopangwa (Structured Data Ingestion Service)** + Inakubali data iliyopangwa katika muundo mbalimbali (JSON, CSV, XML) + Inachanganua na kuthibitisha data inayokuja dhidi ya schemas zilizobainishwa + Inabadilisha data kuwa mitirisho ya data iliyopangwa + Inatoa data kwa folyo za ujumbe zinazofaa kwa usindikaji + Inasaidia upakiaji wa wingi na uingizaji wa mtiririko + + Moduli: trustgraph-flow/trustgraph/decoding/structured + +8. **Huduma ya Uwekaji wa Data (Object Embedding Service)** + Inazalisha uwekaji wa vector kwa data iliyopangwa + Inaruhusu utafutaji wa semantic katika data iliyopangwa + Inasaidia utafutaji wa mchanganyiko unaounganisha maswali ya muundo na ufanano wa semantic + Inajumuishwa na hifadhi za vector zilizopo + + Moduli: trustgraph-flow/trustgraph/embeddings/object_embeddings/qdrant + +### Mifano ya Data + +#### Utaratibu wa Uhifadhi wa Schema + +Schemas zinawekwa katika mfumo wa usanidi wa TrustGraph kwa kutumia muundo ufuatao: + +**Aina**: `schema` (thamani iliyobainishwa kwa schemas zote za data iliyopangwa) +**Ufunguo**: Jina/kitambulisho cha kipekee cha schema (k.m., `customer_records`, `transaction_log`) +**Thamani**: Ufafanuzi wa schema ya JSON unao na muundo + +Ingizo la usanidi wa mfano: +``` +Type: schema +Key: customer_records +Value: { + "name": "customer_records", + "description": "Customer information table", + "fields": [ + { + "name": "customer_id", + "type": "string", + "primary_key": true + }, + { + "name": "name", + "type": "string", + "required": true + }, + { + "name": "email", + "type": "string", + "required": true + }, + { + "name": "registration_date", + "type": "timestamp" + }, + { + "name": "status", + "type": "string", + "enum": ["active", "inactive", "suspended"] + } + ], + "indexes": ["email", "registration_date"] +} +``` + +Mbinu hii inaruhusu: +Ufafanuzi wa muundo (schema) unaobadilika bila mabadiliko ya programu +Marekebisho na matoleo ya muundo (schema) rahisi +Uunganishaji thabiti na usimamizi wa usanidi wa TrustGraph uliopo +Usaidizi wa muundo (schemas) nyingi ndani ya matumizi moja + +### API + +API mpya: + Muundo (schemas) za Pulsar kwa aina zilizo hapo juu + Vifaa vya Pulsar katika mtiririko mpya + Inahitajika njia ya kutaja aina za muundo (schema) katika mitiririko ili mitiririko iweze kujua + aina gani za muundo (schema) kupakua + API zimeongezwa kwenye lango na lango la marekebisho + +API zilizobadilishwa: +Vifaa vya utoaji wa maarifa - Ongeza chaguo la pato la kitu kilicho na muundo +Vifaa vya wakala - Ongeza usaidizi wa zana za data iliyo na muundo + +### Maelezo ya Utendaji + +Kufuata mbinu zilizopo - haya ni moduli mpya tu za usindikaji. +Kila kitu kiko katika vifurushi vya trustgraph-flow isipokuwa vipengele vya muundo (schema) +katika trustgraph-base. + +Inahitajika kazi ya UI katika Workbench ili kuweza kuonyesha / majaribio ya +uwezo huu. + +## Masuala ya Usalama + +Hakuna masuala ya ziada. + +## Masuala ya Utendaji + +Maswali kadhaa kuhusu matumizi ya maswali na fahirisi za Cassandra ili maswali +yasichanganye. + +## Mkakati wa Majaribio + +Tumia mkakati wa majaribio uliopo, tutaunda majaribio ya kitengo, mkataba na ujumuishaji. + +## Mpango wa Uhamisho + +Hakuna. + +## Muda + +Haikubainishwa. + +## Maswali Yaliyofunguliwa + +Je, hii inaweza kufanywa ili kufanya kazi na aina zingine za hifadhi? Tunalenga kutumia + vifaa ambavyo hufanya moduli zinazofanya kazi na hifadhi moja kuwa zinapatikana kwa + hifadhi zingine. + +## Marejeleo + +n/a. + diff --git a/docs/tech-specs/structured-data.tr.md b/docs/tech-specs/structured-data.tr.md new file mode 100644 index 00000000..cb23190e --- /dev/null +++ b/docs/tech-specs/structured-data.tr.md @@ -0,0 +1,253 @@ +# Yapılandırılmış Veri Teknik Özellikleri + +## Genel Bakış + +Bu özellik, TrustGraph'ın yapılandırılmış veri akışlarıyla entegrasyonunu tanımlar ve sistemin, satırlar halinde tablolarda veya nesne depolarında temsil edilebilen verilerle çalışmasını sağlar. Bu entegrasyon, dört birincil kullanım senaryosunu destekler: + +1. **Yapısızdan Yapılandırılmışa Çıkarma**: Yapısız veri kaynaklarını okuyun, nesne yapılarını belirleyin ve çıkarın ve bunları tablo formatında saklayın. +2. **Yapılandırılmış Veri Alma**: Zaten yapılandırılmış formatlarda olan verileri, çıkarılan verilerle birlikte yapılandırılmış depoya doğrudan yükleyin. +3. **Doğal Dil Sorgulama**: Doğal dil sorularını, depodan eşleşen verileri çıkarmak için yapılandırılmış sorgulara dönüştürün. +4. **Doğrudan Yapılandırılmış Sorgulama**: Hassas veri alımı için yapılandırılmış sorguları doğrudan veri deposuna çalıştırın. + +## Hedefler + +**Birleşik Veri Erişimi**: TrustGraph içinde hem yapılandırılmış hem de yapılandırılmamış verilere erişmek için tek bir arayüz sağlayın. +**Sorunsuz Entegrasyon**: TrustGraph'ın grafik tabanlı bilgi gösterimi ile geleneksel yapılandırılmış veri formatları arasındaki sorunsuz uyumluluğu sağlayın. +**Esnek Çıkarma**: Çeşitli yapılandırılmamış kaynaklardan (belgeler, metin vb.) yapılandırılmış verilerin otomatik olarak çıkarılmasını destekleyin. +**Sorgu Çeşitliliği**: Kullanıcıların verilere hem doğal dil hem de yapılandırılmış sorgu dilleriyle sorgu yapmasına izin verin. +**Veri Tutarlılığı**: Farklı veri gösterimleri arasında veri bütünlüğünü ve tutarlılığını koruyun. +**Performans Optimizasyonu**: Ölçekte yapılandırılmış verilerin verimli bir şekilde depolanmasını ve alınmasını sağlayın. +**Şema Esnekliği**: Çeşitli veri kaynaklarına uyum sağlamak için hem şema-yazma hem de şema-okuma yaklaşımlarını destekleyin. +**Geriye Dönük Uyumluluk**: Yapılandırılmış veri yetenekleri eklerken mevcut TrustGraph işlevselliğini koruyun. + +## Arka Plan + +TrustGraph şu anda yapılandırılmamış verileri işleme ve çeşitli kaynaklardan bilgi grafikleri oluşturma konusunda mükemmeldir. Ancak, birçok kurumsal kullanım senaryosu, müşteri kayıtları, işlem günlükleri, envanter veritabanları ve diğer tablo veri kümeleri gibi doğası gereği yapılandırılmış verileri içerir. Bu yapılandırılmış veri kümeleri genellikle kapsamlı bilgiler sağlamak için yapılandırılmamış içerikle birlikte analiz edilmelidir. + +Mevcut sınırlamalar şunlardır: +Önceden yapılandırılmış veri formatlarını (CSV, JSON dizileri, veritabanı dışa aktarmaları) alma konusunda yerel destek yoktur. +Belgelerden tablo verilerini çıkarırken, yerleşik yapıyı koruyamama. +Yapılandırılmış veri kalıpları için verimli sorgulama mekanizmalarının olmaması. +SQL benzeri sorgular ile TrustGraph'ın grafik sorguları arasındaki köprünün olmaması. + +Bu özellik, TrustGraph'ın mevcut yeteneklerini tamamlayan bir yapılandırılmış veri katmanı tanıtarak bu boşlukları giderir. Yapılandırılmış verilere yerel olarak destek sağlayarak, TrustGraph şunları yapabilir: +Hem yapılandırılmış hem de yapılandırılmamış veri analizleri için birleşik bir platform görevi görmek. +Hem grafik ilişkilerini hem de tablo verilerini kapsayan hibrit sorguları etkinleştirmek. +Yapılandırılmış verilerle çalışmaya alışkın kullanıcılar için tanıdık arayüzler sağlamak. +Veri entegrasyonu ve iş zekası alanlarında yeni kullanım senaryolarını açmak. + +## Teknik Tasarım + +### Mimari + +Yapılandırılmış veri entegrasyonu, aşağıdaki teknik bileşenleri gerektirir: + +1. **NLP'den Yapılandırılmış Sorgu Hizmetine** + Doğal dil sorularını yapılandırılmış sorgulara dönüştürür. + Birden çok sorgu dili hedefi (başlangıçta SQL benzeri sözdizimi) destekler. + Mevcut TrustGraph NLP yetenekleriyle entegre olur. + + Modül: trustgraph-flow/trustgraph/query/nlp_query/cassandra + +2. **Yapılandırma Şema Desteği** ✅ **[TAMAMLANDI]** + Yapılandırılmış veri şemalarını depolamak için genişletilmiş yapılandırma sistemi. + Tablo yapılarını, alan türlerini ve ilişkileri tanımlama desteği. + Şema sürümleme ve geçiş yetenekleri. + +3. **Nesne Çıkarma Modülü** ✅ **[TAMAMLANDI]** + Gelişmiş bilgi çıkarıcı akışı entegrasyonu. + Yapısız kaynaklardan yapılandırılmış nesneleri tanımlar ve çıkarır. + Kaynak ve güven puanlarını korur. + Yapılandırma verilerini almak ve şema bilgilerini çözmek için bir yapılandırma işleyici (örneğin: trustgraph-flow/trustgraph/prompt/template/service.py) kaydeder. + Nesneleri alır ve bunları Pulsar kuyruğuna teslim etmek üzere ExtractedObject nesnelerine dönüştürür. + NOT: `trustgraph-flow/trustgraph/extract/object/row/` adresinde mevcut kod bulunmaktadır. Bu, önceki bir girişimdir ve mevcut API'lere uymadığından büyük ölçüde yeniden düzenlenmesi gerekecektir. Kullanışlıysa kullanın, değilse sıfırdan başlayın. + Bir komut satırı arayüzü gerektirir: `kg-extract-objects` + + Modül: trustgraph-flow/trustgraph/extract/kg/objects/ + +4. **Yapılandırılmış Depo Yazma Modülü** ✅ **[TAMAMLANDI]** + ExtractedObject formatında nesneleri Pulsar kuyruklarından alır. + İlk uygulama, yapılandırılmış veri deposu olarak Apache Cassandra'yı hedef alır. + Karşılaşılan şemalara göre dinamik olarak tablo oluşturmayı yönetir. + Şema-Cassandra tablo eşlemesini ve veri dönüşümünü yönetir. + Performans optimizasyonu için toplu ve akışlı yazma işlemleri sağlar. + Pulsar çıktıları yok - bu, veri akışında bir terminal hizmetidir. + + **Şema İşleme**: + Yeni bir şema ilk kez karşılaşıldığında, otomatik olarak ilgili Cassandra tablosunu oluşturur. + Tekrarlayan tablo oluşturma girişimlerinden kaçınmak için bilinen şemaların bir önbelleğini korur. + Şema tanımlarını doğrudan alıp almamak veya ExtractedObject mesajlarındaki şema adlarına güvenip güvenmemek konusunda dikkat edilmesi gereken bir durum. + + + **Cassandra Tablo Eşlemesi**: + Anahtar alanı, ExtractedObject'in Meta Verilerinden gelen `user` alanından alınır. + Tablo, ExtractedObject'in `schema_name` alanından alınır. + Meta Verilerden gelen Koleksiyon, Cassandra düğümleri arasında doğal veri dağılımını sağlamak için bölüm anahtarının bir parçası haline gelir: + Cassandra düğümleri arasında verilerin doğal bir şekilde dağıtılmasını sağlar. + Belirli bir koleksiyon içindeki sorguların verimli bir şekilde çalışmasını sağlar. + Farklı veri aktarımları/kaynakları arasında mantıksal bir izolasyon sağlar. + Birincil anahtar yapısı: `PRIMARY KEY ((collection, ), )` + Koleksiyon, her zaman bölüm anahtarının ilk bileşenidir. + Şema tanımlı birincil anahtar alanları, birleşik bölüm anahtarının bir parçası olarak gelir. + Bu, sorguların koleksiyonu belirtmesini gerektirir ve öngörülebilir bir performans sağlar. + Alan tanımları, Cassandra sütunlarına tür dönüşümleriyle eşlenir: + `string` → `text` + `integer` → `int` veya `bigint` (boyut ipucuna bağlı olarak) + `float` → `float` veya `double` (doğruluk gereksinimlerine bağlı olarak) + `boolean` → `boolean` + `timestamp` → `timestamp` + `enum` → `text` (uygulama seviyesinde doğrulama ile) + İndeksli alanlar, Cassandra ikincil indekslerini oluşturur (birincil anahtarda zaten bulunan alanlar hariç). + Gerekli alanlar, uygulama seviyesinde zorunlu kılınır (Cassandra NOT NULL'ı desteklemez). + + **Nesne Depolama**: + ExtractedObject.values haritasından değerleri çıkarır. + Eklemeden önce tür dönüşümü ve doğrulama yapar. + Eksik isteğe bağlı alanları zarif bir şekilde işler. + Nesne kökeni hakkında meta verileri korur (kaynak belge, güvenilirlik puanları). + Mesaj tekrar senaryolarını işlemek için idempotent yazma işlemlerini destekler. + + **Uygulama Notları**: + `trustgraph-flow/trustgraph/storage/objects/cassandra/` adresindeki mevcut kod güncel değildir ve mevcut API'lere uygun değildir. + Çalışan bir depolama işlemcisinin örneği olarak `trustgraph-flow/trustgraph/storage/triples/cassandra`'a başvurulmalıdır. + Yeniden düzenleme veya yeniden yazma kararı vermeden önce, yeniden kullanılabilir bileşenler için mevcut kodun değerlendirilmesi gerekir. + + Modül: trustgraph-flow/trustgraph/storage/objects/cassandra + +5. **Yapılandırılmış Sorgu Hizmeti** ✅ **[TAMAMLANDI]** + Tanımlanmış formatlarda yapılandırılmış sorguları kabul eder. + Yapılandırılmış depoya karşı sorguları yürütür. + Sorgu kriterlerine uyan nesneleri döndürür. + Sayfalama ve sonuç filtrelemeyi destekler. + + Modül: trustgraph-flow/trustgraph/query/objects/cassandra + +6. **Ajan Aracı Entegrasyonu** + Ajan çerçeveleri için yeni bir araç sınıfı. + Ajanların yapılandırılmış veri depolarını sorgulamasına olanak tanır. + Doğal dil ve yapılandırılmış sorgu arayüzleri sağlar. + Mevcut ajan karar verme süreçleriyle entegre olur. + +7. **Yapılandırılmış Veri Alma Hizmeti** + Yapılandırılmış verileri çeşitli formatlarda (JSON, CSV, XML) kabul eder. + Gelen verileri tanımlanmış şemalara göre ayrıştırır ve doğrular. + Verileri normalleştirilmiş nesne akışlarına dönüştürür. + Nesneleri işleme için uygun mesaj kuyruklarına gönderir. + Toplu yüklemeleri ve akışlı almayı destekler. + + Modül: trustgraph-flow/trustgraph/decoding/structured + +8. **Nesne Gömme Hizmeti** + Yapılandırılmış nesneler için vektör gömmeleri oluşturur. + Yapılandırılmış veriler arasında semantik aramayı sağlar. + Yapılandırılmış sorguları semantik benzerlikle birleştiren hibrit aramayı destekler. + Mevcut vektör depolarıyla entegre olur. + + Modül: trustgraph-flow/trustgraph/embeddings/object_embeddings/qdrant + +### Veri Modelleri + +#### Şema Depolama Mekanizması + +Şemalar, aşağıdaki yapı kullanılarak TrustGraph'ın yapılandırma sisteminde saklanır: + +**Türü**: `schema` (tüm yapılandırılmış veri şemaları için sabit değer) +**Anahtar**: Şemanın benzersiz adı/tanımlayıcısı (örneğin, `customer_records`, `transaction_log`) +**Değer**: Yapıyı içeren JSON şema tanımı + +Örnek yapılandırma girişi: +``` +Type: schema +Key: customer_records +Value: { + "name": "customer_records", + "description": "Customer information table", + "fields": [ + { + "name": "customer_id", + "type": "string", + "primary_key": true + }, + { + "name": "name", + "type": "string", + "required": true + }, + { + "name": "email", + "type": "string", + "required": true + }, + { + "name": "registration_date", + "type": "timestamp" + }, + { + "name": "status", + "type": "string", + "enum": ["active", "inactive", "suspended"] + } + ], + "indexes": ["email", "registration_date"] +} +``` + +Bu yaklaşım şunları sağlar: +Kod değişiklikleri olmadan dinamik şema tanımı +Kolay şema güncellemeleri ve sürüm yönetimi +Mevcut TrustGraph yapılandırma yönetimi ile tutarlı entegrasyon +Tek bir dağıtım içinde birden fazla şema desteği + +### API'ler + +Yeni API'ler: + Yukarıdaki türler için Pulsar şemaları + Yeni akışlarda Pulsar arayüzleri + Akışların hangi şema türlerini yükleyeceğini bilmesi için, şema türlerini akışlarda belirtmenin bir yolu gereklidir + Ağ geçidi ve ters ağ geçidine eklenen API'ler + + +Değiştirilen API'ler: +Bilgi çıkarma uç noktaları - Yapılandırılmış nesne çıktısı seçeneği ekleyin +Ajan uç noktaları - Yapılandırılmış veri aracı desteği ekleyin + +### Uygulama Detayları + +Mevcut kurallara uygun olarak, bunlar sadece yeni işleme modülleridir. +Her şey trustgraph-flow paketlerinde yer almaktadır, şema öğeleri ise trustgraph-base'de bulunmaktadır. + + +Bu özelliği tanıtmak/denemek için Workbench'te bazı kullanıcı arayüzü (UI) çalışmaları yapılması gerekmektedir. + + +## Güvenlik Hususları + +Ek hususlar bulunmamaktadır. + +## Performans Hususları + +Sorguların yavaşlamasını önlemek için Cassandra sorgularının ve indekslerinin kullanımına ilişkin bazı sorular bulunmaktadır. + + +## Test Stratejisi + +Mevcut test stratejisi kullanılacak, birim, sözleşme ve entegrasyon testleri oluşturulacaktır. + +## Geçiş Planı + +Yok. + +## Zaman Çizelgesi + +Belirtilmemiştir. + +## Açık Sorular + +Bu, diğer depolama türleriyle de çalışacak şekilde yapılabilir mi? Tek bir depolamayla çalışan modüllerin, diğer depolamalara da uygulanabilmesi için arayüzler kullanmayı hedefliyoruz. + + +## Referanslar + + +n/a. + diff --git a/docs/tech-specs/structured-data.zh-cn.md b/docs/tech-specs/structured-data.zh-cn.md new file mode 100644 index 00000000..4080e1ec --- /dev/null +++ b/docs/tech-specs/structured-data.zh-cn.md @@ -0,0 +1,253 @@ +# 结构化数据技术规范 + +## 概述 + +本规范描述了 TrustGraph 与结构化数据流的集成,使系统能够处理可以表示为表格中的行或对象存储中的对象的结构化数据。该集成支持四个主要用例: + +1. **非结构化到结构化提取**: 读取非结构化数据源,识别和提取对象结构,并将它们存储在表格格式中。 +2. **结构化数据导入**: 将已经采用结构化格式的数据直接导入到结构化存储中,与提取的数据一起存储。 +3. **自然语言查询**: 将自然语言问题转换为结构化查询,以从存储中提取匹配的数据。 +4. **直接结构化查询**: 直接对数据存储执行结构化查询,以进行精确的数据检索。 + +## 目标 + +**统一数据访问**: 提供一个用于访问 TrustGraph 中结构化和非结构化数据的单一接口。 +**无缝集成**: 实现 TrustGraph 的基于图的知识表示与传统结构化数据格式之间的平滑互操作性。 +**灵活提取**: 支持从各种非结构化源(文档、文本等)自动提取结构化数据。 +**查询灵活性**: 允许用户使用自然语言和结构化查询语言查询数据。 +**数据一致性**: 维护不同数据表示形式之间的数据完整性和一致性。 +**性能优化**: 确保在大规模下高效地存储和检索结构化数据。 +**模式灵活性**: 支持“写时模式”和“读时模式”两种方法,以适应各种数据源。 +**向后兼容性**: 在添加结构化数据功能的同时,保留现有的 TrustGraph 功能。 + +## 背景 + +TrustGraph 目前擅长处理非结构化数据并从各种来源构建知识图。然而,许多企业用例涉及本质上是结构化的数据,例如客户记录、事务日志、库存数据库和其他表格数据集。这些结构化数据集通常需要与非结构化内容一起进行分析,以提供全面的见解。 + +当前的局限性包括: +不支持导入预结构化数据格式(CSV、JSON 数组、数据库导出)。 +无法在从文档中提取表格数据时保留其固有的结构。 +缺乏用于结构化数据模式的有效查询机制。 +SQL 样式的查询与 TrustGraph 的图查询之间的桥梁缺失。 + +本规范通过引入补充 TrustGraph 现有功能的结构化数据层来解决这些差距。通过原生支持结构化数据,TrustGraph 可以: +作为结构化和非结构化数据分析的统一平台。 +实现跨图关系和表格数据的混合查询。 +为习惯于处理结构化数据的用户提供熟悉的接口。 +释放数据集成和商业智能中的新用例。 + +## 技术设计 + +### 架构 + +结构化数据集成需要以下技术组件: + +1. **NLP-to-Structured-Query 服务** + 将自然语言问题转换为结构化查询。 + 支持多种查询语言目标(最初为 SQL 样式的语法)。 + 与现有的 TrustGraph NLP 功能集成。 + + 模块: trustgraph-flow/trustgraph/query/nlp_query/cassandra + +2. **配置模式支持** ✅ **[完成]** + 扩展配置系统以存储结构化数据模式。 + 支持定义表结构、字段类型和关系。 + 模式版本控制和迁移功能。 + +3. **对象提取模块** ✅ **[完成]** + 增强的知识提取流程集成。 + 从非结构化源识别和提取结构化对象。 + 维护溯源信息和置信度分数。 + 注册一个配置处理程序(例如:trustgraph-flow/trustgraph/prompt/template/service.py),以接收配置数据并解码模式信息。 + 接收对象并将其解码为 ExtractedObject 对象,并通过 Pulsar 队列进行传递。 + 注意:存在于 `trustgraph-flow/trustgraph/extract/object/row/` 的现有代码。这是一个之前的尝试,需要进行重大重构,因为它不符合当前的 API。如果有用,可以使用它,否则从头开始。 + 需要一个命令行界面:`kg-extract-objects` + + 模块: trustgraph-flow/trustgraph/extract/kg/objects/ + +4. **结构化存储写入模块** ✅ **[完成]** + 从 Pulsar 队列接收 ExtractedObject 格式的对象。 + 初始实现针对 Apache Cassandra 作为结构化数据存储。 + 处理基于遇到的模式动态创建表。 + 管理模式到 Cassandra 表的映射以及数据转换。 + 提供批量和流式写入操作以进行性能优化。 + 没有 Pulsar 输出 - 这是一个数据流中的终端服务。 + + **模式处理**: + 监控传入的 ExtractedObject 消息以查找模式引用。 + 首次遇到新模式时,自动创建相应的 Cassandra 表。 + 维护已知模式的缓存,以避免重复的表创建尝试。 + 应该考虑是直接接收模式定义,还是依赖于 ExtractedObject 消息中的模式名称。 + + **Cassandra 表映射**: + 键空间(Keyspace)的名称源自 ExtractedObject 的 Metadata 中的 `user` 字段。 + 表的名称源自 ExtractedObject 中的 `schema_name` 字段。 + Metadata 中的集合(Collection)成为分区键的一部分,以确保: + Cassandra 节点之间的数据自然分布。 + 特定集合内的查询效率。 + 不同数据导入/来源之间的逻辑隔离。 + 主键结构:`PRIMARY KEY ((collection, ), )` + 集合始终是分区键的第一部分。 + 遵循定义的模式的主键字段作为组合分区键的一部分。 + 这要求查询指定集合,以确保可预测的性能。 + 字段定义映射到 Cassandra 列,并进行类型转换: + `string` → `text` + `integer` → `int` 或 `bigint`,具体取决于大小提示。 + `float` → `float` 或 `double`,具体取决于精度需求。 + `boolean` → `boolean` + `timestamp` → `timestamp` + `enum` → `text`,并进行应用程序级别的验证。 + 索引字段创建 Cassandra 的二级索引(不包括主键中的字段)。 + 必需字段在应用程序级别强制执行(Cassandra 不支持 NOT NULL)。 + + **对象存储**: + 从 ExtractedObject.values 映射中提取值。 + 在插入之前执行类型转换和验证。 + 优雅地处理缺失的可选字段。 + 维护有关对象来源的元数据(源文档、置信度分数)。 + 支持幂等写入,以处理消息重放场景。 + + **实现说明**: + 位于 `trustgraph-flow/trustgraph/storage/objects/cassandra/` 的现有代码已过时,不符合当前的 API。 + 应该参考 `trustgraph-flow/trustgraph/storage/triples/cassandra` 作为工作存储处理器的示例。 + 在决定重构或重写之前,需要评估现有代码以查找任何可重用组件。 + + 模块:trustgraph-flow/trustgraph/storage/objects/cassandra + +5. **结构化查询服务** ✅ **[完成]** + 接受定义格式的结构化查询。 + 对结构化存储执行查询。 + 返回与查询条件匹配的对象。 + 支持分页和结果过滤。 + + 模块:trustgraph-flow/trustgraph/query/objects/cassandra + +6. **代理工具集成** + 用于代理框架的新工具类。 + 使代理能够查询结构化数据存储。 + 提供自然语言和结构化查询接口。 + 与现有的代理决策过程集成。 + +7. **结构化数据摄取服务** + 接受多种格式(JSON、CSV、XML)的结构化数据。 + 根据定义的模式解析和验证传入数据。 + 将数据转换为规范化的对象流。 + 将对象发送到适当的消息队列进行处理。 + 支持批量上传和流式摄取。 + + 模块:trustgraph-flow/trustgraph/decoding/structured + +8. **对象嵌入服务** + 为结构化对象生成向量嵌入。 + 启用结构化数据的语义搜索。 + 支持结合结构化查询和语义相似性的混合搜索。 + 与现有的向量存储集成。 + + 模块:trustgraph-flow/trustgraph/embeddings/object_embeddings/qdrant + +### 数据模型 + +#### 模式存储机制 + +模式存储在 TrustGraph 的配置系统中使用以下结构: + +**类型**: `schema`(所有结构化数据模式的固定值) +**键**: 模式的唯一名称/标识符(例如,`customer_records`、`transaction_log`) +**值**: 包含结构的 JSON 模式定义 + +示例配置条目: +``` +Type: schema +Key: customer_records +Value: { + "name": "customer_records", + "description": "Customer information table", + "fields": [ + { + "name": "customer_id", + "type": "string", + "primary_key": true + }, + { + "name": "name", + "type": "string", + "required": true + }, + { + "name": "email", + "type": "string", + "required": true + }, + { + "name": "registration_date", + "type": "timestamp" + }, + { + "name": "status", + "type": "string", + "enum": ["active", "inactive", "suspended"] + } + ], + "indexes": ["email", "registration_date"] +} +``` + +此方法允许: +动态模式定义,无需代码更改 +轻松的模式更新和版本控制 +与现有 TrustGraph 配置管理的一致集成 +支持在单个部署中使用的多个模式 + +### API + +新增 API: + 用于上述类型的 Pulsar 模式 + 新流程中的 Pulsar 接口 + 需要一种方法来指定模式类型,以便流程知道要加载哪些 + 模式类型 + 向网关和反向网关添加了 API + +修改后的 API: +知识提取端点 - 添加结构化对象输出选项 +代理端点 - 添加结构化数据工具支持 + +### 实施细节 + +遵循现有约定 - 这些只是新的处理模块。 +除了 trustgraph-base 中的模式项之外,所有内容都位于 trustgraph-flow 包中。 + + +需要在 Workbench 中进行一些 UI 工作,以便演示/试用此 +功能。 + +## 安全注意事项 + +没有额外的注意事项。 + +## 性能注意事项 + +关于使用 Cassandra 查询和索引的一些问题,以确保查询 +不会降低速度。 + +## 测试策略 + +使用现有的测试策略,将构建单元测试、契约测试和集成测试。 + +## 迁移计划 + +无。 + +## 时间线 + +未指定。 + +## 开放问题 + +是否可以使其与其它存储类型一起工作? 我们的目标是使用 + 接口,使适用于一种存储的模块也适用于 + 其他存储。 + +## 参考文献 + +n/a。 + diff --git a/docs/tech-specs/structured-diag-service.ar.md b/docs/tech-specs/structured-diag-service.ar.md new file mode 100644 index 00000000..61068bed --- /dev/null +++ b/docs/tech-specs/structured-diag-service.ar.md @@ -0,0 +1,273 @@ +# المواصفات الفنية لخدمة تشخيص البيانات المهيكلة + +## نظرة عامة + +تصف هذه المواصفات خدمة جديدة قابلة للاستدعاء لتشخيص وتحليل البيانات المهيكلة داخل TrustGraph. تستخرج الخدمة الوظائف من أداة سطر الأوامر `tg-load-structured-data` الحالية وتعرضها كخدمة طلب/استجابة، مما يتيح الوصول البرمجي إلى قدرات اكتشاف أنواع البيانات وإنشاء الوصف. + +تدعم الخدمة ثلاث عمليات رئيسية: + +1. **اكتشاف نوع البيانات**: تحليل عينة بيانات لتحديد تنسيقها (CSV أو JSON أو XML) +2. **إنشاء الوصف**: إنشاء وصف بيانات مهيكلة لـ TrustGraph لعينة بيانات معينة ونوع +3. **التشخيص المدمج**: إجراء كل من اكتشاف النوع وإنشاء الوصف بالتسلسل + +## الأهداف + +**تجزئة تحليل البيانات**: استخراج منطق تشخيص البيانات من واجهة سطر الأوامر إلى مكونات خدمة قابلة لإعادة الاستخدام +**تمكين الوصول البرمجي**: توفير وصول قائم على واجهة برمجة التطبيقات (API) إلى قدرات تحليل البيانات +**دعم تنسيقات بيانات متعددة**: التعامل مع تنسيقات بيانات CSV و JSON و XML بشكل متسق +**إنشاء أوصاف دقيقة**: إنتاج أوصاف بيانات مهيكلة تعكس بدقة بيانات المصدر إلى مخططات TrustGraph +**الحفاظ على التوافق مع الإصدارات السابقة**: التأكد من أن وظائف واجهة سطر الأوامر الحالية تظل تعمل +**تمكين تجميع الخدمات**: السماح للخدمات الأخرى بالاستفادة من قدرات تشخيص البيانات +**تحسين إمكانية الاختبار**: فصل منطق الأعمال عن واجهة سطر الأوامر لتحسين الاختبار +**دعم التحليل المتدفق**: تمكين تحليل عينات البيانات دون تحميل الملفات بأكملها + +## الخلفية + +حاليًا، يوفر الأمر `tg-load-structured-data` وظائف شاملة لتحليل البيانات المهيكلة وإنشاء الأوصاف. ومع ذلك، فإن هذه الوظائف مرتبطة ارتباطًا وثيقًا بواجهة سطر الأوامر، مما يحد من إمكانية إعادة استخدامها. + +تشمل القيود الحالية: +منطق تشخيص البيانات مضمن في كود واجهة سطر الأوامر +لا يوجد وصول برمجي إلى اكتشاف النوع وإنشاء الوصف +من الصعب دمج قدرات التشخيص في خدمات أخرى +قدرة محدودة على تجميع سير عمل تحليل البيانات + +تعالج هذه المواصفات هذه الفجوات من خلال إنشاء خدمة مخصصة لتشخيص البيانات المهيكلة. من خلال تعريض هذه القدرات كخدمة، يمكن لـ TrustGraph: +تمكين خدمات أخرى من تحليل البيانات برمجيًا +دعم مسارات معالجة بيانات أكثر تعقيدًا +تسهيل التكامل مع الأنظمة الخارجية +تحسين قابلية الصيانة من خلال الفصل بين المهام + +## التصميم الفني + +### البنية + +تتطلب خدمة تشخيص البيانات المهيكلة المكونات الفنية التالية: + +1. **معالج خدمة التشخيص** + يتعامل مع طلبات التشخيص الواردة + يقوم بتنسيق اكتشاف النوع وإنشاء الوصف + يُرجع استجابات مهيكلة مع نتائج التشخيص + + الوحدة: `trustgraph-flow/trustgraph/diagnosis/structured_data/service.py` + +2. **كاشف نوع البيانات** + يستخدم الكشف الخوارزمي لتحديد تنسيق البيانات (CSV أو JSON أو XML) + يحلل هيكل البيانات والفواصل وأنماط بناء الجملة + يُرجع التنسيق المكتشف ودرجات الثقة + + الوحدة: `trustgraph-flow/trustgraph/diagnosis/structured_data/type_detector.py` + +3. **مولد الوصف** + يستخدم خدمة المطالبة لإنشاء الأوصاف + يستدعي المطالبات الخاصة بالتنسيق (diagnose-csv أو diagnose-json أو diagnose-xml) + يربط حقول البيانات بحقول مخطط TrustGraph من خلال استجابات المطالبة + + الوحدة: `trustgraph-flow/trustgraph/diagnosis/structured_data/descriptor_generator.py` + +### نماذج البيانات + +#### StructuredDataDiagnosisRequest + +رسالة طلب لعمليات تشخيص البيانات المهيكلة: + +```python +class StructuredDataDiagnosisRequest: + operation: str # "detect-type", "generate-descriptor", or "diagnose" + sample: str # Data sample to analyze (text content) + type: Optional[str] # Data type (csv, json, xml) - required for generate-descriptor + schema_name: Optional[str] # Target schema name for descriptor generation + options: Dict[str, Any] # Additional options (e.g., delimiter for CSV) +``` + +#### استجابة تشخيص البيانات المنظمة + +رسالة استجابة تحتوي على نتائج التشخيص: + +```python +class StructuredDataDiagnosisResponse: + operation: str # The operation that was performed + detected_type: Optional[str] # Detected data type (for detect-type/diagnose) + confidence: Optional[float] # Confidence score for type detection + descriptor: Optional[Dict] # Generated descriptor (for generate-descriptor/diagnose) + error: Optional[str] # Error message if operation failed + metadata: Dict[str, Any] # Additional metadata (e.g., field count, sample records) +``` + +#### هيكل الوصف + +يتبع الوصف الناتج تنسيق الوصف المنظم للبيانات الموجود: + +```json +{ + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true + } + }, + "mappings": [ + { + "source_field": "customer_id", + "target_field": "id", + "transforms": [ + {"type": "trim"} + ] + } + ], + "output": { + "schema_name": "customer", + "options": { + "batch_size": 1000, + "confidence": 0.9 + } + } +} +``` + +### واجهة الخدمة + +ستعرض الخدمة العمليات التالية من خلال نمط الطلب/الاستجابة: + +1. **عملية اكتشاف النوع** + المدخلات: عينة بيانات + المعالجة: تحليل هيكل البيانات باستخدام الكشف الخوارزمي + المخرجات: النوع المكتشف مع درجة الثقة + +2. **عملية توليد الوصف** + المدخلات: عينة بيانات، والنوع، واسم المخطط المستهدف + المعالجة: + استدعاء خدمة المطالبة بمعرف المطالبة الخاص بالتنسيق (diagnose-csv أو diagnose-json أو diagnose-xml) + تمرير عينة البيانات والمخططات المتاحة إلى المطالبة + استقبال الوصف الذي تم إنشاؤه من استجابة المطالبة + المخرجات: وصف البيانات المنظمة + +3. **عملية التشخيص المجمعة** + المدخلات: عينة بيانات، واسم المخطط (اختياري) + المعالجة: + استخدام الكشف الخوارزمي لتحديد التنسيق أولاً + تحديد معرف المطالبة الخاص بالتنسيق المناسب بناءً على النوع المكتشف + استدعاء خدمة المطالبة لإنشاء الوصف + المخرجات: كل من النوع المكتشف والوصف + +### تفاصيل التنفيذ + +ستتبع الخدمة اتفاقيات خدمة TrustGraph: + +1. **تسجيل الخدمة** + التسجيل كنوع خدمة `structured-diag` + استخدام مواضيع الطلب/الاستجابة القياسية + تنفيذ الفئة الأساسية FlowProcessor + تسجيل PromptClientSpec لتفاعل خدمة المطالبة + +2. **إدارة التكوين** + الوصول إلى تكوينات المخططات عبر خدمة التكوين + تخزين المخططات مؤقتًا لتحسين الأداء + التعامل مع تحديثات التكوين ديناميكيًا + +3. **تكامل المطالبة** + استخدام البنية التحتية الحالية لخدمة المطالبة + استدعاء خدمة المطالبة بمعرفات المطالبة الخاصة بالتنسيق: + `diagnose-csv`: لتحليل بيانات CSV + `diagnose-json`: لتحليل بيانات JSON + `diagnose-xml`: لتحليل بيانات XML + يتم تكوين المطالبات في تكوين المطالبة، وليس ترميزها بشكل ثابت في الخدمة + تمرير المخططات وعينات البيانات كمتغيرات للمطالبة + تحليل استجابات المطالبة لاستخراج الأوصاف + +4. **معالجة الأخطاء** + التحقق من صحة عينات البيانات المدخلة + توفير رسائل خطأ وصفية + التعامل مع البيانات التالفة بأمان + التعامل مع فشل خدمة المطالبة + +5. **أخذ العينات من البيانات** + معالجة أحجام العينات القابلة للتكوين + التعامل مع السجلات غير المكتملة بشكل مناسب + الحفاظ على اتساق أخذ العينات + +### تكامل واجهة برمجة التطبيقات (API) + +ستتكامل الخدمة مع واجهات برمجة تطبيقات TrustGraph الحالية: + +المكونات المعدلة: +`tg-load-structured-data` CLI - تم إعادة هيكلتها لاستخدام الخدمة الجديدة لعمليات التشخيص +Flow API - تم توسيعه لدعم طلبات تشخيص البيانات المنظمة + +نقاط نهاية الخدمة الجديدة: +`/api/v1/flow/{flow}/diagnose/structured-data` - نقطة نهاية WebSocket لطلبات التشخيص +`/api/v1/diagnose/structured-data` - نقطة نهاية REST للتشخيص المتزامن + +### تدفق الرسائل + +``` +Client → Gateway → Structured Diag Service → Config Service (for schemas) + ↓ + Type Detector (algorithmic) + ↓ + Prompt Service (diagnose-csv/json/xml) + ↓ + Descriptor Generator (parses prompt response) + ↓ +Client ← Gateway ← Structured Diag Service (response) +``` + +## اعتبارات الأمان + +التحقق من صحة الإدخال لمنع هجمات الحقن. +حدود الحجم على عينات البيانات لمنع هجمات الحرمان من الخدمة (DoS). +تنقية الواصفات التي تم إنشاؤها. +التحكم في الوصول من خلال مصادقة TrustGraph الحالية. + +## اعتبارات الأداء + +تخزين تعريفات المخططات مؤقتًا لتقليل عدد استدعاءات خدمة التكوين. +تحديد حدود لحجم العينات للحفاظ على أداء سريع الاستجابة. +استخدام المعالجة المتدفقة لعلاجات البيانات الكبيرة. +تطبيق آليات المهلة للتحليلات التي تستغرق وقتًا طويلاً. + +## استراتيجية الاختبار + +1. **اختبارات الوحدة** + اكتشاف النوع لـتنسيقات البيانات المختلفة. + دقة توليد الواصفات. + سيناريوهات معالجة الأخطاء. + +2. **اختبارات التكامل** + تدفق طلب/استجابة الخدمة. + استرجاع المخططات وتخزينها مؤقتًا. + تكامل واجهة سطر الأوامر (CLI). + +3. **اختبارات الأداء** + معالجة العينات الكبيرة. + معالجة الطلبات المتزامنة. + استخدام الذاكرة تحت الحمل. + +## خطة الترحيل + +1. **المرحلة الأولى**: تنفيذ الخدمة مع الوظائف الأساسية. +2. **المرحلة الثانية**: إعادة هيكلة واجهة سطر الأوامر (CLI) لاستخدام الخدمة (مع الحفاظ على التوافق مع الإصدارات السابقة). +3. **المرحلة الثالثة**: إضافة نقاط نهاية واجهة برمجة التطبيقات (REST API). +4. **المرحلة الرابعة**: إيقاف وظائف واجهة سطر الأوامر (CLI) المضمنة (مع إشعار مسبق). + +## الجدول الزمني + +الأسبوع 1-2: تنفيذ الخدمة الأساسية واكتشاف النوع. +الأسبوع 3-4: إضافة توليد الواصفات والتكامل. +الأسبوع 5: الاختبار والتوثيق. +الأسبوع 6: إعادة هيكلة واجهة سطر الأوامر (CLI) والترحيل. + +## أسئلة مفتوحة + +هل يجب أن تدعم الخدمة تنسيقات بيانات إضافية (مثل Parquet، Avro)؟ +ما هو الحد الأقصى لحجم العينة للتحليل؟ +هل يجب تخزين نتائج التشخيص مؤقتًا للطلبات المتكررة؟ +كيف يجب أن تتعامل الخدمة مع السيناريوهات متعددة المخططات؟ +هل يجب أن تكون معرفات المطالبات معلمات قابلة للتكوين للخدمة؟ + +## المراجع + +[مواصفات واصف البيانات المنظمة](structured-data-descriptor.md) +[توثيق تحميل البيانات المنظمة](structured-data.md) +`tg-load-structured-data` التنفيذ: `trustgraph-cli/trustgraph/cli/load_structured_data.py` \ No newline at end of file diff --git a/docs/tech-specs/structured-diag-service.es.md b/docs/tech-specs/structured-diag-service.es.md new file mode 100644 index 00000000..671ba15d --- /dev/null +++ b/docs/tech-specs/structured-diag-service.es.md @@ -0,0 +1,273 @@ +# Especificación Técnica del Servicio de Diagnóstico de Datos Estructurados + +## Descripción General + +Esta especificación describe un nuevo servicio invocable para diagnosticar y analizar datos estructurados dentro de TrustGraph. El servicio extrae la funcionalidad de la herramienta de línea de comandos `tg-load-structured-data` existente y la expone como un servicio de solicitud/respuesta, lo que permite el acceso programático a las capacidades de detección de tipos de datos y generación de descriptores. + +El servicio admite tres operaciones principales: + +1. **Detección de Tipo de Datos**: Analiza una muestra de datos para determinar su formato (CSV, JSON o XML). +2. **Generación de Descriptores**: Genera un descriptor de datos estructurados de TrustGraph para una muestra de datos y tipo dados. +3. **Diagnóstico Combinado**: Realiza la detección de tipo y la generación de descriptores en secuencia. + +## Objetivos + +**Modularización del Análisis de Datos**: Extrae la lógica de diagnóstico de datos de la CLI en componentes de servicio reutilizables. +**Habilitar el Acceso Programático**: Proporciona acceso basado en API a las capacidades de análisis de datos. +**Admitir Múltiples Formatos de Datos**: Maneja los formatos de datos CSV, JSON y XML de manera consistente. +**Generar Descriptores Precisos**: Produce descriptores de datos estructurados que mapean con precisión los datos de origen a los esquemas de TrustGraph. +**Mantener la Compatibilidad Inversa**: Garantiza que la funcionalidad existente de la CLI continúe funcionando. +**Habilitar la Composición de Servicios**: Permite que otros servicios aprovechen las capacidades de diagnóstico de datos. +**Mejorar la Capacidad de Pruebas**: Separa la lógica de negocio de la interfaz de la CLI para una mejor prueba. +**Admitir el Análisis por Flujo**: Permite el análisis de muestras de datos sin cargar archivos completos. + +## Antecedentes + +Actualmente, el comando `tg-load-structured-data` proporciona una funcionalidad completa para analizar datos estructurados y generar descriptores. Sin embargo, esta funcionalidad está estrechamente acoplada a la interfaz de la CLI, lo que limita su reutilización. + +Las limitaciones actuales incluyen: +Lógica de diagnóstico de datos incrustada en el código de la CLI. +Sin acceso programático a la detección de tipos y la generación de descriptores. +Difícil de integrar las capacidades de diagnóstico en otros servicios. +Capacidad limitada para componer flujos de trabajo de análisis de datos. + +Esta especificación aborda estas deficiencias mediante la creación de un servicio dedicado para el diagnóstico de datos estructurados. Al exponer estas capacidades como un servicio, TrustGraph puede: +Permitir que otros servicios analicen datos de forma programática. +Admitir canalizaciones de procesamiento de datos más complejas. +Facilitar la integración con sistemas externos. +Mejorar la mantenibilidad mediante la separación de responsabilidades. + +## Diseño Técnico + +### Arquitectura + +El servicio de diagnóstico de datos estructurados requiere los siguientes componentes técnicos: + +1. **Procesador del Servicio de Diagnóstico** + Maneja las solicitudes de diagnóstico entrantes. + Orquesta la detección de tipos y la generación de descriptores. + Devuelve respuestas estructuradas con los resultados del diagnóstico. + + Módulo: `trustgraph-flow/trustgraph/diagnosis/structured_data/service.py` + +2. **Detector de Tipo de Datos** + Utiliza la detección algorítmica para identificar el formato de datos (CSV, JSON, XML). + Analiza la estructura de datos, los delimitadores y los patrones de sintaxis. + Devuelve el formato detectado y las puntuaciones de confianza. + + Módulo: `trustgraph-flow/trustgraph/diagnosis/structured_data/type_detector.py` + +3. **Generador de Descriptores** + Utiliza el servicio de prompts para generar descriptores. + Invoca prompts específicos del formato (diagnose-csv, diagnose-json, diagnose-xml). + Mapea los campos de datos a los campos del esquema de TrustGraph a través de las respuestas del prompt. + + Módulo: `trustgraph-flow/trustgraph/diagnosis/structured_data/descriptor_generator.py` + +### Modelos de Datos + +#### StructuredDataDiagnosisRequest + +Mensaje de solicitud para operaciones de diagnóstico de datos estructurados: + +```python +class StructuredDataDiagnosisRequest: + operation: str # "detect-type", "generate-descriptor", or "diagnose" + sample: str # Data sample to analyze (text content) + type: Optional[str] # Data type (csv, json, xml) - required for generate-descriptor + schema_name: Optional[str] # Target schema name for descriptor generation + options: Dict[str, Any] # Additional options (e.g., delimiter for CSV) +``` + +#### RespuestaDiagnósticoDatosEstructurados + +Mensaje de respuesta que contiene los resultados del diagnóstico: + +```python +class StructuredDataDiagnosisResponse: + operation: str # The operation that was performed + detected_type: Optional[str] # Detected data type (for detect-type/diagnose) + confidence: Optional[float] # Confidence score for type detection + descriptor: Optional[Dict] # Generated descriptor (for generate-descriptor/diagnose) + error: Optional[str] # Error message if operation failed + metadata: Dict[str, Any] # Additional metadata (e.g., field count, sample records) +``` + +#### Estructura del descriptor + +El descriptor generado sigue el formato de descriptor de datos estructurados existente: + +```json +{ + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true + } + }, + "mappings": [ + { + "source_field": "customer_id", + "target_field": "id", + "transforms": [ + {"type": "trim"} + ] + } + ], + "output": { + "schema_name": "customer", + "options": { + "batch_size": 1000, + "confidence": 0.9 + } + } +} +``` + +### Interfaz de Servicio + +El servicio expondrá las siguientes operaciones a través del patrón de solicitud/respuesta: + +1. **Operación de Detección de Tipo** + Entrada: Muestra de datos + Procesamiento: Analizar la estructura de datos utilizando la detección algorítmica + Salida: Tipo detectado con una puntuación de confianza + +2. **Operación de Generación de Descriptores** + Entrada: Muestra de datos, tipo, nombre del esquema de destino + Procesamiento: + Llamar al servicio de solicitud con el ID de solicitud específico del formato (diagnóstico-csv, diagnóstico-json o diagnóstico-xml) + Pasar la muestra de datos y los esquemas disponibles a la solicitud + Recibir el descriptor generado de la respuesta de la solicitud + Salida: Descriptor de datos estructurados + +3. **Operación de Diagnóstico Combinado** + Entrada: Muestra de datos, nombre de esquema opcional + Procesamiento: + Utilizar la detección algorítmica para identificar el formato primero + Seleccionar la solicitud específica del formato basada en el tipo detectado + Llamar al servicio de solicitud para generar el descriptor + Salida: Tanto el tipo detectado como el descriptor + +### Detalles de Implementación + +El servicio seguirá las convenciones del servicio TrustGraph: + +1. **Registro de Servicio** + Registrarse como tipo de servicio `structured-diag` + Utilizar temas estándar de solicitud/respuesta + Implementar la clase base FlowProcessor + Registrar PromptClientSpec para la interacción con el servicio de solicitud + +2. **Gestión de la Configuración** + Acceder a las configuraciones del esquema a través del servicio de configuración + Almacenar en caché los esquemas para mejorar el rendimiento + Manejar las actualizaciones de configuración de forma dinámica + +3. **Integración de Solicitudes** + Utilizar la infraestructura existente del servicio de solicitud + Llamar al servicio de solicitud con los ID de solicitud específicos del formato: + `diagnose-csv`: Para el análisis de datos CSV + `diagnose-json`: Para el análisis de datos JSON + `diagnose-xml`: Para el análisis de datos XML + Las solicitudes están configuradas en la configuración de la solicitud, no codificadas de forma rígida en el servicio + Pasar los esquemas y las muestras de datos como variables de la solicitud + Analizar las respuestas de la solicitud para extraer los descriptores + +4. **Manejo de Errores** + Validar las muestras de datos de entrada + Proporcionar mensajes de error descriptivos + Manejar los datos incorrectos de forma elegante + Manejar las fallas del servicio de solicitud + +5. **Muestreo de Datos** + Procesar tamaños de muestra configurables + Manejar los registros incompletos de forma adecuada + Mantener la coherencia del muestreo + +### Integración de la API + +El servicio se integrará con las API existentes de TrustGraph: + +Componentes Modificados: +`tg-load-structured-data` CLI: Refactorizado para utilizar el nuevo servicio para las operaciones de diagnóstico +Flow API: Extendido para admitir solicitudes de diagnóstico de datos estructurados + +Nuevos Puntos Finales del Servicio: +`/api/v1/flow/{flow}/diagnose/structured-data`: Punto final de WebSocket para solicitudes de diagnóstico +`/api/v1/diagnose/structured-data`: Punto final REST para el diagnóstico sincrónico + +### Flujo de Mensajes + +``` +Client → Gateway → Structured Diag Service → Config Service (for schemas) + ↓ + Type Detector (algorithmic) + ↓ + Prompt Service (diagnose-csv/json/xml) + ↓ + Descriptor Generator (parses prompt response) + ↓ +Client ← Gateway ← Structured Diag Service (response) +``` + +## Consideraciones de seguridad + +Validación de entrada para prevenir ataques de inyección +Límites de tamaño en muestras de datos para prevenir DoS +Sanitización de descriptores generados +Control de acceso a través de la autenticación TrustGraph existente + +## Consideraciones de rendimiento + +Almacenar en caché las definiciones de esquema para reducir las llamadas al servicio de configuración +Limitar los tamaños de muestra para mantener un rendimiento receptivo +Utilizar procesamiento en streaming para grandes muestras de datos +Implementar mecanismos de tiempo de espera para análisis de larga duración + +## Estrategia de pruebas + +1. **Pruebas unitarias** + Detección de tipo para varios formatos de datos + Precisión de la generación de descriptores + Escenarios de manejo de errores + +2. **Pruebas de integración** + Flujo de solicitud/respuesta del servicio + Recuperación y almacenamiento en caché del esquema + Integración de la CLI + +3. **Pruebas de rendimiento** + Procesamiento de grandes muestras + Manejo de solicitudes concurrentes + Uso de memoria bajo carga + +## Plan de migración + +1. **Fase 1**: Implementar el servicio con la funcionalidad principal +2. **Fase 2**: Refactorizar la CLI para que utilice el servicio (mantener la compatibilidad con versiones anteriores) +3. **Fase 3**: Agregar puntos finales de la API REST +4. **Fase 4**: Descartar la lógica integrada de la CLI (con un período de aviso) + +## Cronograma + +Semana 1-2: Implementar el servicio principal y la detección de tipo +Semana 3-4: Agregar la generación de descriptores y la integración +Semana 5: Pruebas y documentación +Semana 6: Refactorización de la CLI y migración + +## Preguntas abiertas + +¿Debería el servicio admitir formatos de datos adicionales (por ejemplo, Parquet, Avro)? +¿Cuál debería ser el tamaño máximo de la muestra para el análisis? +¿Deben almacenarse en caché los resultados del diagnóstico para solicitudes repetidas? +¿Cómo debe manejar el servicio los escenarios de esquemas múltiples? +¿Deben los ID de las indicaciones ser parámetros configurables para el servicio? + +## Referencias + +[Especificación del descriptor de datos estructurados](structured-data-descriptor.md) +[Documentación de carga de datos estructurados](structured-data.md) +`tg-load-structured-data` implementación: `trustgraph-cli/trustgraph/cli/load_structured_data.py` \ No newline at end of file diff --git a/docs/tech-specs/structured-diag-service.he.md b/docs/tech-specs/structured-diag-service.he.md new file mode 100644 index 00000000..676bf799 --- /dev/null +++ b/docs/tech-specs/structured-diag-service.he.md @@ -0,0 +1,273 @@ +# מפרט טכני לשירות אבחון נתונים מובנים + +## סקירה כללית + +מפרט זה מתאר שירות חדש הניתן לביצוע לאבחון וניתוח נתונים מובנים בתוך TrustGraph. השירות שואב פונקציונליות מכלי שורת הפקודה הקיים `tg-load-structured-data` ומציג אותו כשירות בקשה/תגובה, ומאפשר גישה תכנותית ליכולות זיהוי סוג נתונים ויצירת תיאורים. + +השירות תומך בשלוש פעולות עיקריות: + +1. **זיהוי סוג נתונים**: ניתוח דוגמת נתונים כדי לקבוע את הפורמט שלה (CSV, JSON או XML) +2. **יצירת תיאור**: יצירת תיאור נתונים מובנים עבור דוגמת נתונים מסוימת וסוג +3. **אבחון משולב**: ביצוע גם זיהוי סוג וגם יצירת תיאור ברצף + +## מטרות + +**מודולריזציה של ניתוח נתונים**: העברת לוגיקת אבחון נתונים משורת הפקודה לרכיבי שירות הניתנים לשימוש חוזר +**אפשרות לגישה תכנותית**: מתן גישה מבוססת API ליכולות ניתוח נתונים +**תמיכה במספר פורמטים של נתונים**: טיפול בפורמטי נתונים של CSV, JSON ו-XML באופן עקבי +**יצירת תיאורים מדויקים**: יצירת תיאורי נתונים מובנים המתאימים בצורה מדויקת לנתוני המקור לתוך סכימות TrustGraph +**שמירה על תאימות לאחור**: הבטחה שפונקציונליות קיימת של שורת הפקודה תמשיך לעבוד +**אפשרות לחיבור שירותים**: לאפשר לשירותים אחרים לנצל יכולות אבחון נתונים +**שיפור יכולת בדיקה**: הפרדת לוגיקה עסקית מממשק שורת הפקודה לצורך בדיקות טובות יותר +**תמיכה בניתוח סטרימינג**: אפשרות לניתוח דוגמאות נתונים מבלי לטעון קבצים שלמים + +## רקע + +כיום, הפקודה `tg-load-structured-data` מספקת פונקציונליות מקיפה לניתוח נתונים מובנים ויצירת תיאורים. עם זאת, פונקציונליות זו קשורה הדוקות לממשק שורת הפקודה, מה שמגביל את יכולת השימוש החוזר בה. + +מגבלות נוכחיות כוללות: +לוגיקת אבחון נתונים מוטמעת בקוד שורת הפקודה +אין גישה תכנותית לזיהוי סוג ויצירת תיאורים +קשה לשלב יכולות אבחון בשירותים אחרים +יכולת מוגבלת ליצור זרימות עבודה לניתוח נתונים + +מפרט זה מתייחס לפערים אלה על ידי יצירת שירות ייעודי לאבחון נתונים מובנים. על ידי חשיפת יכולות אלה כשירות, TrustGraph יכולה: +לאפשר לשירותים אחרים לנתח נתונים באופן תכנותי +לתמוך בצינורות עיבוד נתונים מורכבים יותר +להקל על שילוב עם מערכות חיצוניות +לשפר את תחזוקת המערכת באמצעות הפרדת אחריות + +## עיצוב טכני + +### ארכיטקטורה + +שירות האבחון של נתונים מובנים דורש את הרכיבים הטכניים הבאים: + +1. **מעבד שירות אבחון** + מטפל בבקשות אבחון נכנסות + מתאם זיהוי סוג ויצירת תיאורים + מחזיר תגובות מובנות עם תוצאות אבחון + + מודול: `trustgraph-flow/trustgraph/diagnosis/structured_data/service.py` + +2. **מגַלֶּה סוג נתונים** + משתמש בגילוי אלגוריתמי כדי לזהות פורמט נתונים (CSV, JSON, XML) + מנתח מבנה נתונים, מפרידים ותבניות תחביר + מחזיר פורמט מזוהה וציוני אמון + + מודול: `trustgraph-flow/trustgraph/diagnosis/structured_data/type_detector.py` + +3. **יוצר תיאורים** + משתמש בשירות פרומפטים כדי ליצור תיאורים + מפעיל פרומפטים ספציפיים לפורמט (diagnose-csv, diagnose-json, diagnose-xml) + ממפה שדות נתונים לשדות סכימת TrustGraph באמצעות תגובות פרומפטים + + מודול: `trustgraph-flow/trustgraph/diagnosis/structured_data/descriptor_generator.py` + +### מודלים של נתונים + +#### StructuredDataDiagnosisRequest + +הודעת בקשה לפעולות אבחון נתונים מובנים: + +```python +class StructuredDataDiagnosisRequest: + operation: str # "detect-type", "generate-descriptor", or "diagnose" + sample: str # Data sample to analyze (text content) + type: Optional[str] # Data type (csv, json, xml) - required for generate-descriptor + schema_name: Optional[str] # Target schema name for descriptor generation + options: Dict[str, Any] # Additional options (e.g., delimiter for CSV) +``` + +#### תגובת אבחון נתונים מובנים + +הודעת תגובה המכילה תוצאות אבחון: + +```python +class StructuredDataDiagnosisResponse: + operation: str # The operation that was performed + detected_type: Optional[str] # Detected data type (for detect-type/diagnose) + confidence: Optional[float] # Confidence score for type detection + descriptor: Optional[Dict] # Generated descriptor (for generate-descriptor/diagnose) + error: Optional[str] # Error message if operation failed + metadata: Dict[str, Any] # Additional metadata (e.g., field count, sample records) +``` + +#### מבנה תיאור + +התיאור שנוצר עוקב אחר פורמט התיאור המובנה הקיים: + +```json +{ + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true + } + }, + "mappings": [ + { + "source_field": "customer_id", + "target_field": "id", + "transforms": [ + {"type": "trim"} + ] + } + ], + "output": { + "schema_name": "customer", + "options": { + "batch_size": 1000, + "confidence": 0.9 + } + } +} +``` + +### ממשק שירות + +השירות יחשוף את הפעולות הבאות באמצעות תבנית בקשה/תגובה: + +1. **פעולת זיהוי סוג** + קלט: דוגמת נתונים + עיבוד: ניתוח מבנה הנתונים באמצעות זיהוי אלגוריתמי + פלט: סוג מזוהה עם ציון אמון + +2. **פעולת יצירת תיאור** + קלט: דוגמת נתונים, סוג, שם סכימה יעד + עיבוד: + הפעלת שירות הפרומפט עם מזהה הפרומפט הספציפי לפורמט (diagnose-csv, diagnose-json או diagnose-xml) + העברת דוגמת הנתונים והסכימות הזמינות לפרומפט + קבלת התיאור שנוצר מתגובת הפרומפט + פלט: תיאור נתונים מובנים + +3. **פעולת אבחון משולבת** + קלט: דוגמת נתונים, שם סכימה אופציונלי + עיבוד: + שימוש בזיהוי אלגוריתמי לזיהוי הפורמט תחילה + בחירת פרומפט ספציפי לפורמט בהתאם לסוג המזוהה + הפעלת שירות הפרומפט ליצירת תיאור + פלט: גם הסוג המזוהה וגם התיאור + +### פרטי יישום + +השירות יפעל בהתאם לקונבנציות של שירות TrustGraph: + +1. **רישום שירות** + רישום כסוג שירות `structured-diag` + שימוש בנושאים סטנדרטיים של בקשה/תגובה + יישום מחלקת FlowProcessor בסיסית + רישום PromptClientSpec עבור אינטראקציה עם שירות הפרומפט + +2. **ניהול תצורה** + גישה לתצורות סכימה באמצעות שירות התצורה + שמירת סכימות במטמון לביצועים + טיפול בעדכוני תצורה באופן דינמי + +3. **שילוב פרומפט** + שימוש בתשתית קיימת של שירות הפרומפט + הפעלת שירות הפרומפט עם מזהי פרומפט ספציפיים לפורמט: + `diagnose-csv`: לניתוח נתוני CSV + `diagnose-json`: לניתוח נתוני JSON + `diagnose-xml`: לניתוח נתוני XML + הפרומפטים מוגדרים בתצורת הפרומפט, ולא מקודדים קשות בשירות + העברת סכימות ודוגמאות נתונים כמשתני פרומפט + ניתוח תגובות פרומפט לחילוץ תיאורים + +4. **טיפול בשגיאות** + אימות דוגמאות נתונים + מתן הודעות שגיאה תיאוריות + טיפול מסודר בנתונים פגומים + טיפול בכשלים בשירות הפרומפט + +5. **דגימת נתונים** + עיבוד גדלי דגימה הניתנים לתצורה + טיפול מתאים ברשומות חסרות + שמירה על עקביות דגימה + +### שילוב API + +השירות ישולב עם ממשקי TrustGraph קיימים: + +רכיבים שעברו שינוי: +`tg-load-structured-data` CLI - שופץ לשימוש בשירות החדש לפעולות אבחון +Flow API - הורחב לתמיכה בבקשות אבחון נתונים מובנים + +נקודות שירות חדשות: +`/api/v1/flow/{flow}/diagnose/structured-data` - נקודת קצה WebSocket לבקשות אבחון +`/api/v1/diagnose/structured-data` - נקודת קצה REST לאבחון סינכרוני + +### זרימת הודעות + +``` +Client → Gateway → Structured Diag Service → Config Service (for schemas) + ↓ + Type Detector (algorithmic) + ↓ + Prompt Service (diagnose-csv/json/xml) + ↓ + Descriptor Generator (parses prompt response) + ↓ +Client ← Gateway ← Structured Diag Service (response) +``` + +## שיקולי אבטחה + +אימות קלט למניעת התקפות הזרקה +מגבלות גודל על דוגמאות נתונים למניעת התקפות מניעת שירות (DoS) +ניקוי של מזהים שנוצרו +בקרת גישה באמצעות אימות TrustGraph הקיים + +## שיקולי ביצועים + +שמירת הגדרות סכימה במטמון להפחתת קריאות לשירות התצורה +הגבלת גודל הדוגמאות לשמירה על ביצועים מהירים +שימוש בעיבוד סטרימינג עבור דוגמאות נתונים גדולות +הטמעת מנגנוני זמן קצוב עבור ניתוחים ארוכים + +## אסטרטגיית בדיקות + +1. **בדיקות יחידה** + זיהוי סוג עבור פורמטי נתונים שונים + דיוק יצירת מזהים + תרחישי טיפול בשגיאות + +2. **בדיקות אינטגרציה** + זרימת בקשות/תגובות של שירות + שליפה ושמירה במטמון של סכימות + אינטגרציה עם שורת הפקודה (CLI) + +3. **בדיקות ביצועים** + עיבוד של דוגמאות גדולות + טיפול בבקשות מקבילות + שימוש בזיכרון בתנאי עומס + +## תוכנית מעבר + +1. **שלב 1**: הטמעת שירות עם פונקציונליות בסיסית +2. **שלב 2**: שינוי שורת הפקודה (CLI) לשימוש בשירות (שמירה על תאימות לאחור) +3. **שלב 3**: הוספת נקודות קצה של ממשק API REST +4. **שלב 4**: הפסקת השימוש בלוגיקה מוטמעת של שורת הפקודה (עם תקופת התראה) + +## ציר זמן + +שבוע 1-2: הטמעת שירות וזיהוי סוג בסיסי +שבוע 3-4: הוספת יצירת מזהים ואינטגרציה +שבוע 5: בדיקות ותיעוד +שבוע 6: שינוי שורת הפקודה (CLI) ומעבר + +## שאלות פתוחות + +האם השירות צריך לתמוך בפורמטי נתונים נוספים (לדוגמה, Parquet, Avro)? +מהו גודל הדוגמה המקסימלי לניתוח? +האם תוצאות האבחון צריכות להיות שמורות במטמון עבור בקשות חוזרות? +כיצד השירות צריך להתמודד עם תרחישים של סכימות מרובות? +האם מזהי הבקשות צריכים להיות פרמטרים הניתנים להגדרה עבור השירות? + +## הפניות + +[מפרט מזהה נתונים מובנים](structured-data-descriptor.md) +[תיעוד טעינת נתונים מובנים](structured-data.md) +`tg-load-structured-data` יישום: `trustgraph-cli/trustgraph/cli/load_structured_data.py` \ No newline at end of file diff --git a/docs/tech-specs/structured-diag-service.hi.md b/docs/tech-specs/structured-diag-service.hi.md new file mode 100644 index 00000000..be6fb004 --- /dev/null +++ b/docs/tech-specs/structured-diag-service.hi.md @@ -0,0 +1,273 @@ +# स्ट्रक्चर्ड डेटा डायग्नोस्टिक सर्विस टेक्निकल स्पेसिफिकेशन + +## अवलोकन + +यह स्पेसिफिकेशन ट्रस्टग्राफ के भीतर संरचित डेटा का निदान और विश्लेषण करने के लिए एक नए इनवोकेबल सर्विस का वर्णन करता है। यह सर्विस मौजूदा `tg-load-structured-data` कमांड-लाइन टूल से कार्यक्षमता निकालती है और इसे एक अनुरोध/प्रतिक्रिया सेवा के रूप में प्रस्तुत करती है, जिससे डेटा प्रकार का पता लगाने और विवरण पीढ़ी क्षमताओं तक प्रोग्रामेटिक पहुंच सक्षम होती है। + +यह सेवा तीन प्राथमिक कार्यों का समर्थन करती है: + +1. **डेटा टाइप डिटेक्शन**: यह निर्धारित करने के लिए कि इसका प्रारूप क्या है (CSV, JSON, या XML), एक डेटा नमूने का विश्लेषण करें। +2. **डिस्क्रिप्टर जेनरेशन**: दिए गए डेटा नमूने और प्रकार के लिए एक ट्रस्टग्राफ संरचित डेटा विवरण उत्पन्न करें। +3. **संयुक्त निदान**: अनुक्रम में डेटा प्रकार का पता लगाने और विवरण पीढ़ी दोनों करें। + +## लक्ष्य + +**डेटा विश्लेषण का मॉड्यूलरकरण**: CLI से डेटा निदान तर्क को पुन: प्रयोज्य सेवा घटकों में निकालें। +**प्रोग्रामेटिक एक्सेस सक्षम करें**: डेटा विश्लेषण क्षमताओं तक API-आधारित पहुंच प्रदान करें। +**एकाधिक डेटा प्रारूपों का समर्थन करें**: CSV, JSON और XML डेटा प्रारूपों को लगातार संभालें। +**सटीक विवरण उत्पन्न करें**: संरचित डेटा विवरण उत्पन्न करें जो स्रोत डेटा को ट्रस्टग्राफ स्कीमा से सटीक रूप से मैप करते हैं। +**पिछला संगतता बनाए रखें**: सुनिश्चित करें कि मौजूदा CLI कार्यक्षमता जारी रहती है। +**सेवा रचना को सक्षम करें**: अन्य सेवाओं को डेटा निदान क्षमताओं का लाभ उठाने दें। +**परीक्षण क्षमता में सुधार करें**: बेहतर परीक्षण के लिए CLI इंटरफ़ेस से व्यावसायिक तर्क को अलग करें। +**स्ट्रीमिंग विश्लेषण का समर्थन करें**: संपूर्ण फ़ाइलों को लोड किए बिना डेटा नमूनों का विश्लेषण सक्षम करें। + +## पृष्ठभूमि + +वर्तमान में, `tg-load-structured-data` कमांड संरचित डेटा का विश्लेषण करने और विवरण उत्पन्न करने के लिए व्यापक कार्यक्षमता प्रदान करता है। हालाँकि, यह कार्यक्षमता CLI इंटरफ़ेस से दृढ़ता से जुड़ी हुई है, जो इसकी पुन: प्रयोज्यता को सीमित करती है। + +वर्तमान सीमाएँ शामिल हैं: +CLI कोड में एम्बेडेड डेटा निदान तर्क। +डेटा प्रकार का पता लगाने और विवरण पीढ़ी तक कोई प्रोग्रामेटिक पहुंच नहीं। +अन्य सेवाओं में निदान क्षमताओं को एकीकृत करना मुश्किल है। +डेटा विश्लेषण वर्कफ़्लो को संयोजित करने की सीमित क्षमता। + +यह स्पेसिफिकेशन इन कमियों को एक समर्पित संरचित डेटा निदान सेवा बनाकर संबोधित करता है। इन क्षमताओं को एक सेवा के रूप में उजागर करके, ट्रस्टग्राफ: +अन्य सेवाओं को डेटा का प्रोग्रामेटिक रूप से विश्लेषण करने में सक्षम बनाता है। +अधिक जटिल डेटा प्रसंस्करण पाइपलाइन का समर्थन करता है। +बाहरी प्रणालियों के साथ एकीकरण को सुविधाजनक बनाता है। +चिंताओं के अलगाव के माध्यम से रखरखाव में सुधार करता है। + +## तकनीकी डिजाइन + +### आर्किटेक्चर + +संरचित डेटा निदान सेवा के लिए निम्नलिखित तकनीकी घटकों की आवश्यकता होती है: + +1. **डायग्नोस्टिक सर्विस प्रोसेसर** + आने वाले निदान अनुरोधों को संभालता है। + डेटा प्रकार का पता लगाने और विवरण पीढ़ी का समन्वय करता है। + निदान परिणामों के साथ संरचित प्रतिक्रियाएँ लौटाता है। + + मॉड्यूल: `trustgraph-flow/trustgraph/diagnosis/structured_data/service.py` + +2. **डेटा टाइप डिटेक्टर** + डेटा प्रारूप (CSV, JSON, XML) की पहचान करने के लिए एल्गोरिथम का उपयोग करता है। + पता लगाए गए प्रारूप और आत्मविश्वास स्कोर लौटाता है। + पता लगाए गए प्रारूप और आत्मविश्वास स्कोर वापस करता है। + + मॉड्यूल: `trustgraph-flow/trustgraph/diagnosis/structured_data/type_detector.py` + +3. **डिस्क्रिप्टर जेनरेटर** + विवरण उत्पन्न करने के लिए प्रॉम्प्ट सेवा का उपयोग करता है। + प्रारूप-विशिष्ट प्रॉम्प्ट (diagnose-csv, diagnose-json, diagnose-xml) को लागू करता है। + डेटा फ़ील्ड को प्रॉम्प्ट प्रतिक्रियाओं के माध्यम से ट्रस्टग्राफ स्कीमा फ़ील्ड में मैप करता है। + + मॉड्यूल: `trustgraph-flow/trustgraph/diagnosis/structured_data/descriptor_generator.py` + +### डेटा मॉडल + +#### StructuredDataDiagnosisRequest + +संरचित डेटा निदान कार्यों के लिए अनुरोध संदेश: + +```python +class StructuredDataDiagnosisRequest: + operation: str # "detect-type", "generate-descriptor", or "diagnose" + sample: str # Data sample to analyze (text content) + type: Optional[str] # Data type (csv, json, xml) - required for generate-descriptor + schema_name: Optional[str] # Target schema name for descriptor generation + options: Dict[str, Any] # Additional options (e.g., delimiter for CSV) +``` + +#### संरचित डेटा निदान प्रतिक्रिया + +निदान परिणामों को शामिल करने वाला प्रतिक्रिया संदेश: + +```python +class StructuredDataDiagnosisResponse: + operation: str # The operation that was performed + detected_type: Optional[str] # Detected data type (for detect-type/diagnose) + confidence: Optional[float] # Confidence score for type detection + descriptor: Optional[Dict] # Generated descriptor (for generate-descriptor/diagnose) + error: Optional[str] # Error message if operation failed + metadata: Dict[str, Any] # Additional metadata (e.g., field count, sample records) +``` + +#### विवरण संरचना + +उत्पन्न विवरण मौजूदा संरचित डेटा विवरण प्रारूप का पालन करता है: + +```json +{ + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true + } + }, + "mappings": [ + { + "source_field": "customer_id", + "target_field": "id", + "transforms": [ + {"type": "trim"} + ] + } + ], + "output": { + "schema_name": "customer", + "options": { + "batch_size": 1000, + "confidence": 0.9 + } + } +} +``` + +### सेवा इंटरफ़ेस + +यह सेवा अनुरोध/प्रतिक्रिया पैटर्न के माध्यम से निम्नलिखित कार्यों को प्रदान करेगी: + +1. **टाइप डिटेक्शन ऑपरेशन** + इनपुट: डेटा नमूना + प्रसंस्करण: एल्गोरिथम डिटेक्शन का उपयोग करके डेटा संरचना का विश्लेषण करें + आउटपुट: पता लगाए गए प्रकार के साथ आत्मविश्वास स्कोर + +2. **डिस्क्रिप्टर जनरेशन ऑपरेशन** + इनपुट: डेटा नमूना, प्रकार, लक्षित स्कीमा नाम + प्रसंस्करण: + प्रारूप-विशिष्ट प्रॉम्प्ट आईडी (diagnose-csv, diagnose-json, या diagnose-xml) के साथ प्रॉम्प्ट सेवा को कॉल करें + डेटा नमूना और उपलब्ध स्कीमा को प्रॉम्प्ट में पास करें + प्रॉम्प्ट प्रतिक्रिया से उत्पन्न डिस्क्रिप्टर प्राप्त करें + आउटपुट: संरचित डेटा डिस्क्रिप्टर + +3. **संयुक्त निदान ऑपरेशन** + इनपुट: डेटा नमूना, वैकल्पिक स्कीमा नाम + प्रसंस्करण: + पहले एल्गोरिथम डिटेक्शन का उपयोग करके प्रारूप की पहचान करें + पता लगाए गए प्रकार के आधार पर उपयुक्त प्रारूप-विशिष्ट प्रॉम्प्ट का चयन करें + डिस्क्रिप्टर उत्पन्न करने के लिए प्रॉम्प्ट सेवा को कॉल करें + आउटपुट: पता लगाए गए प्रकार और डिस्क्रिप्टर दोनों + +### कार्यान्वयन विवरण + +यह सेवा TrustGraph सेवा सम्मेलनों का पालन करेगी: + +1. **सेवा पंजीकरण** + `structured-diag` सेवा प्रकार के रूप में पंजीकृत करें + मानक अनुरोध/प्रतिक्रिया विषयों का उपयोग करें + FlowProcessor बेस क्लास को लागू करें + प्रॉम्प्ट सेवा के साथ इंटरैक्शन के लिए PromptClientSpec को पंजीकृत करें + +2. **कॉन्फ़िगरेशन प्रबंधन** + कॉन्फ़िग सेवा के माध्यम से स्कीमा कॉन्फ़िगरेशन तक पहुंचें + प्रदर्शन के लिए स्कीमा को कैश करें + गतिशील रूप से कॉन्फ़िगरेशन अपडेट को संभालें + +3. **प्रॉम्प्ट एकीकरण** + मौजूदा प्रॉम्प्ट सेवा बुनियादी ढांचे का उपयोग करें + प्रारूप-विशिष्ट प्रॉम्प्ट आईडी के साथ प्रॉम्प्ट सेवा को कॉल करें: + `diagnose-csv`: CSV डेटा विश्लेषण के लिए + `diagnose-json`: JSON डेटा विश्लेषण के लिए + `diagnose-xml`: XML डेटा विश्लेषण के लिए + प्रॉम्प्ट सेवा में कॉन्फ़िगर किए गए हैं, सेवा में हार्ड-कोडेड नहीं हैं + स्कीमा और डेटा नमूने को प्रॉम्प्ट चर के रूप में पास करें + डिस्क्रिप्टर निकालने के लिए प्रॉम्प्ट प्रतिक्रियाओं को पार्स करें + +4. **त्रुटि प्रबंधन** + इनपुट डेटा नमूनों को मान्य करें + वर्णनात्मक त्रुटि संदेश प्रदान करें + खराब डेटा को शालीनता से संभालें + प्रॉम्प्ट सेवा विफलताओं को संभालें + +5. **डेटा नमूनाकरण** + कॉन्फ़िगर करने योग्य नमूना आकारों को संसाधित करें + अधूरी रिकॉर्ड को उचित रूप से संभालें + नमूनाकरण स्थिरता बनाए रखें + +### एपीआई एकीकरण + +यह सेवा मौजूदा TrustGraph एपीआई के साथ एकीकृत होगी: + +संशोधित घटक: +`tg-load-structured-data` CLI - निदान कार्यों के लिए नई सेवा का उपयोग करने के लिए रिफैक्टर किया गया +फ्लो एपीआई - संरचित डेटा निदान अनुरोधों का समर्थन करने के लिए विस्तारित + +नए सेवा एंडपॉइंट: +`/api/v1/flow/{flow}/diagnose/structured-data` - निदान अनुरोधों के लिए वेबसॉकेट एंडपॉइंट +`/api/v1/diagnose/structured-data` - सिंक्रोनस निदान के लिए REST एंडपॉइंट + +### संदेश प्रवाह + +``` +Client → Gateway → Structured Diag Service → Config Service (for schemas) + ↓ + Type Detector (algorithmic) + ↓ + Prompt Service (diagnose-csv/json/xml) + ↓ + Descriptor Generator (parses prompt response) + ↓ +Client ← Gateway ← Structured Diag Service (response) +``` + +## सुरक्षा संबंधी विचार + +इंजेक्शन हमलों को रोकने के लिए इनपुट सत्यापन +DoS को रोकने के लिए डेटा नमूनों पर आकार सीमाएं +उत्पन्न विवरणों का सैनिटाइजेशन +मौजूदा ट्रस्टग्राफ प्रमाणीकरण के माध्यम से एक्सेस नियंत्रण + +## प्रदर्शन संबंधी विचार + +कॉन्फ़िगरेशन सेवा कॉल को कम करने के लिए स्कीमा परिभाषाओं को कैश करें +उत्तरदायी प्रदर्शन बनाए रखने के लिए नमूना आकारों को सीमित करें +बड़े डेटा नमूनों के लिए स्ट्रीमिंग प्रोसेसिंग का उपयोग करें +लंबे समय तक चलने वाले विश्लेषणों के लिए टाइमआउट तंत्र लागू करें + +## परीक्षण रणनीति + +1. **इकाई परीक्षण** + विभिन्न डेटा प्रारूपों के लिए प्रकार का पता लगाना + विवरण पीढ़ी की सटीकता + त्रुटि हैंडलिंग परिदृश्य + +2. **एकीकरण परीक्षण** + सेवा अनुरोध/प्रतिक्रिया प्रवाह + स्कीमा पुनर्प्राप्ति और कैशिंग + CLI एकीकरण + +3. **प्रदर्शन परीक्षण** + बड़े नमूने प्रसंस्करण + समवर्ती अनुरोध हैंडलिंग + लोड के तहत मेमोरी उपयोग + +## माइग्रेशन योजना + +1. **चरण 1**: मुख्य कार्यक्षमता के साथ सेवा लागू करें +2. **चरण 2**: CLI को सेवा का उपयोग करने के लिए रिफैक्टर करें (पिछड़ी संगतता बनाए रखें) +3. **चरण 3**: REST API एंडपॉइंट जोड़ें +4. **चरण 4**: एम्बेडेड CLI लॉजिक को अप्रचलित करें (सूचना अवधि के साथ) + +## समयरेखा + +सप्ताह 1-2: मुख्य सेवा और प्रकार का पता लगाना लागू करें +सप्ताह 3-4: विवरण पीढ़ी और एकीकरण जोड़ें +सप्ताह 5: परीक्षण और दस्तावेज़ीकरण +सप्ताह 6: CLI रिफैक्टरिंग और माइग्रेशन + +## खुले प्रश्न + +क्या सेवा को अतिरिक्त डेटा प्रारूपों (जैसे, Parquet, Avro) का समर्थन करना चाहिए? +विश्लेषण के लिए अधिकतम नमूना आकार क्या होना चाहिए? +क्या निदान परिणाम बार-बार अनुरोधों के लिए कैश किए जाने चाहिए? +सेवा को मल्टी-स्कीमा परिदृश्यों को कैसे संभालना चाहिए? +क्या प्रॉम्प्ट आईडी सेवा के लिए कॉन्फ़िगर करने योग्य पैरामीटर होने चाहिए? + +## संदर्भ + +[स्ट्रक्चर्ड डेटा डिस्क्रिप्टर विनिर्देश](structured-data-descriptor.md) +[स्ट्रक्चर्ड डेटा लोडिंग दस्तावेज़](structured-data.md) +`tg-load-structured-data` कार्यान्वयन: `trustgraph-cli/trustgraph/cli/load_structured_data.py` \ No newline at end of file diff --git a/docs/tech-specs/structured-diag-service.pt.md b/docs/tech-specs/structured-diag-service.pt.md new file mode 100644 index 00000000..a04028b3 --- /dev/null +++ b/docs/tech-specs/structured-diag-service.pt.md @@ -0,0 +1,273 @@ +# Especificação Técnica do Serviço de Diagnóstico de Dados Estruturados + +## Visão Geral + +Esta especificação descreve um novo serviço invocável para diagnosticar e analisar dados estruturados dentro do TrustGraph. O serviço extrai a funcionalidade da ferramenta de linha de comando existente `tg-load-structured-data` e a expõe como um serviço de solicitação/resposta, permitindo o acesso programático às capacidades de detecção de tipo de dados e geração de descritores. + +O serviço suporta três operações principais: + +1. **Detecção de Tipo de Dados**: Analisa uma amostra de dados para determinar seu formato (CSV, JSON ou XML) +2. **Geração de Descritor**: Gera um descritor de dados estruturados do TrustGraph para uma determinada amostra de dados e tipo +3. **Diagnóstico Combinado**: Realiza a detecção de tipo e a geração de descritor em sequência + +## Objetivos + +**Modularização da Análise de Dados**: Extrai a lógica de diagnóstico de dados da CLI para componentes de serviço reutilizáveis +**Habilitar Acesso Programático**: Fornecer acesso baseado em API às capacidades de análise de dados +**Suportar Múltiplos Formatos de Dados**: Lidar com formatos de dados CSV, JSON e XML de forma consistente +**Gerar Descritores Precisos**: Produzir descritores de dados estruturados que mapeiem com precisão os dados de origem para os esquemas do TrustGraph +**Manter a Compatibilidade com Versões Anteriores**: Garantir que a funcionalidade existente da CLI continue a funcionar +**Habilitar a Composição de Serviços**: Permitir que outros serviços aproveitem as capacidades de diagnóstico de dados +**Melhorar a Testabilidade**: Separar a lógica de negócios da interface da CLI para melhor teste +**Suportar a Análise em Streaming**: Permitir a análise de amostras de dados sem carregar arquivos inteiros + +## Contexto + +Atualmente, o comando `tg-load-structured-data` fornece funcionalidade abrangente para analisar dados estruturados e gerar descritores. No entanto, essa funcionalidade está fortemente acoplada à interface da CLI, limitando sua reutilização. + +As limitações atuais incluem: +Lógica de diagnóstico de dados incorporada no código da CLI +Sem acesso programático à detecção de tipo e à geração de descritores +Difícil integrar as capacidades de diagnóstico em outros serviços +Capacidade limitada de compor fluxos de trabalho de análise de dados + +Esta especificação aborda essas lacunas, criando um serviço dedicado para o diagnóstico de dados estruturados. Ao expor essas capacidades como um serviço, o TrustGraph pode: +Permitir que outros serviços analisem dados programaticamente +Suportar pipelines de processamento de dados mais complexos +Facilitar a integração com sistemas externos +Melhorar a manutenção por meio da separação de responsabilidades + +## Design Técnico + +### Arquitetura + +O serviço de diagnóstico de dados estruturados requer os seguintes componentes técnicos: + +1. **Processador do Serviço de Diagnóstico** + Lida com solicitações de diagnóstico recebidas + Orquestra a detecção de tipo e a geração de descritores + Retorna respostas estruturadas com os resultados do diagnóstico + + Módulo: `trustgraph-flow/trustgraph/diagnosis/structured_data/service.py` + +2. **Detector de Tipo de Dados** + Usa a detecção algorítmica para identificar o formato de dados (CSV, JSON, XML) + Analisa a estrutura de dados, delimitadores e padrões de sintaxe + Retorna o formato detectado e as pontuações de confiança + + Módulo: `trustgraph-flow/trustgraph/diagnosis/structured_data/type_detector.py` + +3. **Gerador de Descritores** + Usa o serviço de prompt para gerar descritores + Invoca prompts específicos do formato (diagnosticar-csv, diagnosticar-json, diagnosticar-xml) + Mapeia campos de dados para campos de esquema do TrustGraph por meio de respostas de prompt + + Módulo: `trustgraph-flow/trustgraph/diagnosis/structured_data/descriptor_generator.py` + +### Modelos de Dados + +#### StructuredDataDiagnosisRequest + +Mensagem de solicitação para operações de diagnóstico de dados estruturados: + +```python +class StructuredDataDiagnosisRequest: + operation: str # "detect-type", "generate-descriptor", or "diagnose" + sample: str # Data sample to analyze (text content) + type: Optional[str] # Data type (csv, json, xml) - required for generate-descriptor + schema_name: Optional[str] # Target schema name for descriptor generation + options: Dict[str, Any] # Additional options (e.g., delimiter for CSV) +``` + +#### StructuredDataDiagnosisResponse + +Mensagem de resposta contendo os resultados do diagnóstico: + +```python +class StructuredDataDiagnosisResponse: + operation: str # The operation that was performed + detected_type: Optional[str] # Detected data type (for detect-type/diagnose) + confidence: Optional[float] # Confidence score for type detection + descriptor: Optional[Dict] # Generated descriptor (for generate-descriptor/diagnose) + error: Optional[str] # Error message if operation failed + metadata: Dict[str, Any] # Additional metadata (e.g., field count, sample records) +``` + +#### Estrutura do Descritor + +O descritor gerado segue o formato existente de descritor de dados estruturados: + +```json +{ + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true + } + }, + "mappings": [ + { + "source_field": "customer_id", + "target_field": "id", + "transforms": [ + {"type": "trim"} + ] + } + ], + "output": { + "schema_name": "customer", + "options": { + "batch_size": 1000, + "confidence": 0.9 + } + } +} +``` + +### Interface de Serviço + +O serviço exporá as seguintes operações através do padrão de solicitação/resposta: + +1. **Operação de Detecção de Tipo** + Entrada: Amostra de dados + Processamento: Analisar a estrutura de dados usando detecção algorítmica + Saída: Tipo detectado com pontuação de confiança + +2. **Operação de Geração de Descritor** + Entrada: Amostra de dados, tipo, nome do esquema de destino + Processamento: + Chamar o serviço de prompt com o ID de prompt específico do formato (diagnosticar-csv, diagnosticar-json ou diagnosticar-xml) + Passar a amostra de dados e os esquemas disponíveis para o prompt + Receber o descritor gerado da resposta do prompt + Saída: Descritor de dados estruturados + +3. **Operação de Diagnóstico Combinado** + Entrada: Amostra de dados, nome de esquema opcional + Processamento: + Usar a detecção algorítmica para identificar o formato primeiro + Selecionar o prompt específico do formato apropriado com base no tipo detectado + Chamar o serviço de prompt para gerar o descritor + Saída: Tanto o tipo detectado quanto o descritor + +### Detalhes da Implementação + +O serviço seguirá as convenções do serviço TrustGraph: + +1. **Registro de Serviço** + Registrar como tipo de serviço `structured-diag` + Usar tópicos padrão de solicitação/resposta + Implementar a classe base FlowProcessor + Registrar PromptClientSpec para a interação com o serviço de prompt + +2. **Gerenciamento de Configuração** + Acessar as configurações do esquema através do serviço de configuração + Armazenar em cache os esquemas para desempenho + Lidar com atualizações de configuração dinamicamente + +3. **Integração de Prompt** + Usar a infraestrutura existente do serviço de prompt + Chamar o serviço de prompt com IDs de prompt específicos do formato: + `diagnose-csv`: Para análise de dados CSV + `diagnose-json`: Para análise de dados JSON + `diagnose-xml`: Para análise de dados XML + Os prompts são configurados na configuração do prompt, e não codificados no serviço + Passar esquemas e amostras de dados como variáveis de prompt + Analisar as respostas do prompt para extrair os descritores + +4. **Tratamento de Erros** + Validar as amostras de dados de entrada + Fornecer mensagens de erro descritivas + Lidar com dados malformados de forma elegante + Lidar com falhas no serviço de prompt + +5. **Amostragem de Dados** + Processar tamanhos de amostra configuráveis + Lidar com registros incompletos de forma apropriada + Manter a consistência da amostragem + +### Integração de API + +O serviço será integrado com as APIs TrustGraph existentes: + +Componentes Modificados: +`tg-load-structured-data` CLI - Refatorado para usar o novo serviço para operações de diagnóstico +Flow API - Estendido para suportar solicitações de diagnóstico de dados estruturados + +Novos Pontos de Extremidade do Serviço: +`/api/v1/flow/{flow}/diagnose/structured-data` - Endpoint WebSocket para solicitações de diagnóstico +`/api/v1/diagnose/structured-data` - Endpoint REST para diagnóstico síncrono + +### Fluxo de Mensagens + +``` +Client → Gateway → Structured Diag Service → Config Service (for schemas) + ↓ + Type Detector (algorithmic) + ↓ + Prompt Service (diagnose-csv/json/xml) + ↓ + Descriptor Generator (parses prompt response) + ↓ +Client ← Gateway ← Structured Diag Service (response) +``` + +## Considerações de Segurança + +Validação de entrada para prevenir ataques de injeção +Limites de tamanho em amostras de dados para prevenir ataques de negação de serviço (DoS) +Sanitização de descritores gerados +Controle de acesso através da autenticação TrustGraph existente + +## Considerações de Desempenho + +Cache de definições de esquema para reduzir o número de chamadas ao serviço de configuração +Limitar o tamanho das amostras para manter um desempenho responsivo +Usar processamento em fluxo para grandes amostras de dados +Implementar mecanismos de timeout para análises de longa duração + +## Estratégia de Testes + +1. **Testes Unitários** + Detecção de tipo para vários formatos de dados + Precisão da geração de descritores + Cenários de tratamento de erros + +2. **Testes de Integração** + Fluxo de solicitação/resposta do serviço + Recuperação e cache de esquema + Integração com a interface de linha de comando (CLI) + +3. **Testes de Desempenho** + Processamento de grandes amostras + Tratamento de solicitações concorrentes + Uso de memória sob carga + +## Plano de Migração + +1. **Fase 1**: Implementar o serviço com a funcionalidade principal +2. **Fase 2**: Refatorar a CLI para usar o serviço (manter a compatibilidade com versões anteriores) +3. **Fase 3**: Adicionar endpoints de API REST +4. **Fase 4**: Descontinuar a lógica da CLI incorporada (com aviso prévio) + +## Cronograma + +Semana 1-2: Implementar o serviço principal e a detecção de tipo +Semana 3-4: Adicionar geração de descritores e integração +Semana 5: Testes e documentação +Semana 6: Refatoração da CLI e migração + +## Perguntas Abertas + +O serviço deve suportar formatos de dados adicionais (por exemplo, Parquet, Avro)? +Qual deve ser o tamanho máximo da amostra para análise? +Os resultados do diagnóstico devem ser armazenados em cache para solicitações repetidas? +Como o serviço deve lidar com cenários de vários esquemas? +Os IDs de prompt devem ser parâmetros configuráveis para o serviço? + +## Referências + +[Especificação do Descritor de Dados Estruturados](structured-data-descriptor.md) +[Documentação de Carregamento de Dados Estruturados](structured-data.md) +`tg-load-structured-data` implementação: `trustgraph-cli/trustgraph/cli/load_structured_data.py` \ No newline at end of file diff --git a/docs/tech-specs/structured-diag-service.ru.md b/docs/tech-specs/structured-diag-service.ru.md new file mode 100644 index 00000000..0e9947b7 --- /dev/null +++ b/docs/tech-specs/structured-diag-service.ru.md @@ -0,0 +1,273 @@ +# Техническая спецификация сервиса диагностики структурированных данных + +## Обзор + +Эта спецификация описывает новый сервис, который можно вызывать для диагностики и анализа структурированных данных в TrustGraph. Сервис извлекает функциональность из существующего инструмента командной строки `tg-load-structured-data` и предоставляет ее в виде сервиса запросов/ответов, обеспечивая программный доступ к возможностям определения типа данных и генерации описаний. + +Сервис поддерживает три основные операции: + +1. **Определение типа данных**: Анализ образца данных для определения его формата (CSV, JSON или XML). +2. **Генерация описания**: Генерация структурированного описания данных TrustGraph для заданного образца данных и типа. +3. **Комплексная диагностика**: Выполнение как определения типа данных, так и генерации описания последовательно. + +## Цели + +**Модулизация анализа данных**: Извлечение логики диагностики данных из интерфейса командной строки в многократно используемые компоненты сервиса. +**Обеспечение программного доступа**: Предоставление API для доступа к возможностям анализа данных. +**Поддержка нескольких форматов данных**: Обработка форматов данных CSV, JSON и XML согласованным образом. +**Генерация точных описаний**: Создание структурированных описаний данных, которые точно сопоставляют исходные данные со схемами TrustGraph. +**Сохранение обратной совместимости**: Обеспечение продолжения работы существующей функциональности интерфейса командной строки. +**Обеспечение возможности объединения сервисов**: Предоставление другим сервисам возможности использования возможностей диагностики данных. +**Улучшение тестируемости**: Разделение бизнес-логики от интерфейса командной строки для улучшения тестирования. +**Поддержка потоковой обработки**: Обеспечение возможности анализа образцов данных без загрузки целых файлов. + +## Обзор + +В настоящее время команда `tg-load-structured-data` предоставляет комплексную функциональность для анализа структурированных данных и генерации описаний. Однако эта функциональность тесно связана с интерфейсом командной строки, что ограничивает ее повторное использование. + +Существующие ограничения включают: +Логика диагностики данных, встроенная в код интерфейса командной строки. +Отсутствие программного доступа к определению типа данных и генерации описаний. +Сложность интеграции возможностей диагностики в другие сервисы. +Ограниченная возможность создания рабочих процессов анализа данных. + +Эта спецификация решает эти проблемы, создавая специальный сервис для диагностики структурированных данных. Предоставляя эти возможности в виде сервиса, TrustGraph может: +Обеспечить возможность другим сервисам программного анализа данных. +Поддерживать более сложные конвейеры обработки данных. +Облегчить интеграцию с внешними системами. +Улучшить поддерживаемость за счет разделения ответственности. + +## Технический дизайн + +### Архитектура + +Сервису диагностики структурированных данных требуются следующие технические компоненты: + +1. **Процессор сервиса диагностики** + Обрабатывает входящие запросы на диагностику. + Координирует определение типа данных и генерацию описаний. + Возвращает структурированные ответы с результатами диагностики. + + Модуль: `trustgraph-flow/trustgraph/diagnosis/structured_data/service.py` + +2. **Детектор типа данных** + Использует алгоритмическое определение для идентификации формата данных (CSV, JSON, XML). + Анализирует структуру данных, разделители и шаблоны синтаксиса. + Возвращает определенный формат и коэффициенты достоверности. + + Модуль: `trustgraph-flow/trustgraph/diagnosis/structured_data/type_detector.py` + +3. **Генератор описаний** + Использует сервис запросов для генерации описаний. + Вызывает специфичные для формата запросы (diagnose-csv, diagnose-json, diagnose-xml). + Отображает поля данных на поля схемы TrustGraph с помощью ответов запросов. + + Модуль: `trustgraph-flow/trustgraph/diagnosis/structured_data/descriptor_generator.py` + +### Модели данных + +#### StructuredDataDiagnosisRequest + +Сообщение запроса для операций диагностики структурированных данных: + +```python +class StructuredDataDiagnosisRequest: + operation: str # "detect-type", "generate-descriptor", or "diagnose" + sample: str # Data sample to analyze (text content) + type: Optional[str] # Data type (csv, json, xml) - required for generate-descriptor + schema_name: Optional[str] # Target schema name for descriptor generation + options: Dict[str, Any] # Additional options (e.g., delimiter for CSV) +``` + +#### StructuredDataDiagnosisResponse + +Сообщение ответа, содержащее результаты диагностики: + +```python +class StructuredDataDiagnosisResponse: + operation: str # The operation that was performed + detected_type: Optional[str] # Detected data type (for detect-type/diagnose) + confidence: Optional[float] # Confidence score for type detection + descriptor: Optional[Dict] # Generated descriptor (for generate-descriptor/diagnose) + error: Optional[str] # Error message if operation failed + metadata: Dict[str, Any] # Additional metadata (e.g., field count, sample records) +``` + +#### Структура дескриптора + +Сгенерированный дескриптор соответствует существующему формату структурированного дескриптора данных: + +```json +{ + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true + } + }, + "mappings": [ + { + "source_field": "customer_id", + "target_field": "id", + "transforms": [ + {"type": "trim"} + ] + } + ], + "output": { + "schema_name": "customer", + "options": { + "batch_size": 1000, + "confidence": 0.9 + } + } +} +``` + +### Интерфейс сервиса + +Сервис будет предоставлять следующие операции с использованием шаблона запрос/ответ: + +1. **Операция определения типа** + Входные данные: Образец данных + Обработка: Анализ структуры данных с использованием алгоритмического определения + Выходные данные: Определенный тип с уровнем достоверности + +2. **Операция генерации дескриптора** + Входные данные: Образец данных, тип, имя целевой схемы + Обработка: + Вызов сервиса запросов с идентификатором запроса, специфичным для формата (diagnose-csv, diagnose-json или diagnose-xml) + Передача образца данных и доступных схем в запрос + Получение сгенерированного дескриптора из ответа запроса + Выходные данные: Структурированный дескриптор данных + +3. **Комплексная операция диагностики** + Входные данные: Образец данных, необязательное имя схемы + Обработка: + Использование алгоритмического определения для определения формата + Выбор соответствующего запроса, специфичного для формата, на основе определенного типа + Вызов сервиса запросов для генерации дескриптора + Выходные данные: Определенный тип и дескриптор + +### Детали реализации + +Сервис будет соответствовать соглашениям сервиса TrustGraph: + +1. **Регистрация сервиса** + Регистрация как сервис типа `structured-diag` + Использование стандартных тем запросов/ответов + Реализация базового класса FlowProcessor + Регистрация PromptClientSpec для взаимодействия с сервисом запросов + +2. **Управление конфигурацией** + Доступ к конфигурациям схем через сервис конфигурации + Кэширование схем для повышения производительности + Динамическая обработка обновлений конфигурации + +3. **Интеграция с сервисом запросов** + Использование существующей инфраструктуры сервиса запросов + Вызов сервиса запросов с идентификаторами запросов, специфичными для формата: + `diagnose-csv`: Для анализа данных CSV + `diagnose-json`: Для анализа данных JSON + `diagnose-xml`: Для анализа данных XML + Запросы настроены в конфигурации запросов, а не жестко закодированы в сервисе + Передача схем и образцов данных в качестве переменных запроса + Разбор ответов запросов для извлечения дескрипторов + +4. **Обработка ошибок** + Проверка входных образцов данных + Предоставление описательных сообщений об ошибках + Обработка некорректных данных + Обработка сбоев сервиса запросов + +5. **Выборка данных** + Обработка настраиваемых размеров выборки + Правильная обработка неполных записей + Поддержание согласованности выборки + +### Интеграция с API + +Сервис будет интегрирован с существующими API TrustGraph: + +Измененные компоненты: +`tg-load-structured-data` CLI - Переработан для использования нового сервиса для операций диагностики +Flow API - Расширен для поддержки запросов структурированной диагностики + +Новые конечные точки сервиса: +`/api/v1/flow/{flow}/diagnose/structured-data` - WebSocket конечная точка для запросов диагностики +`/api/v1/diagnose/structured-data` - REST конечная точка для синхронной диагностики + +### Поток сообщений + +``` +Client → Gateway → Structured Diag Service → Config Service (for schemas) + ↓ + Type Detector (algorithmic) + ↓ + Prompt Service (diagnose-csv/json/xml) + ↓ + Descriptor Generator (parses prompt response) + ↓ +Client ← Gateway ← Structured Diag Service (response) +``` + +## Соображения безопасности + +Проверка входных данных для предотвращения атак внедрения +Ограничения на размер образцов данных для предотвращения DoS-атак +Очистка сгенерированных описаний +Контроль доступа через существующую аутентификацию TrustGraph + +## Соображения производительности + +Кэширование определений схемы для уменьшения количества обращений к сервису конфигурации +Ограничение размеров образцов для поддержания отзывчивой производительности +Использование потоковой обработки для больших образцов данных +Реализация механизмов тайм-аута для длительных анализов + +## Стратегия тестирования + +1. **Модульные тесты** + Обнаружение типа для различных форматов данных + Точность генерации описаний + Сценарии обработки ошибок + +2. **Интеграционные тесты** + Поток запросов/ответов сервиса + Получение и кэширование схемы + Интеграция с CLI + +3. **Тесты производительности** + Обработка больших образцов + Обработка одновременных запросов + Использование памяти при высокой нагрузке + +## План миграции + +1. **Этап 1**: Реализация сервиса с основной функциональностью +2. **Этап 2**: Рефакторинг CLI для использования сервиса (с сохранением обратной совместимости) +3. **Этап 3**: Добавление REST API +4. **Этап 4**: Отказ от встроенной логики CLI (с предварительным уведомлением) + +## График + +Неделя 1-2: Реализация основного сервиса и обнаружения типа +Неделя 3-4: Добавление генерации описаний и интеграции +Неделя 5: Тестирование и документация +Неделя 6: Рефакторинг CLI и миграция + +## Открытые вопросы + +Должен ли сервис поддерживать дополнительные форматы данных (например, Parquet, Avro)? +Каков должен быть максимальный размер образца для анализа? +Следует ли кэшировать результаты диагностики для повторяющихся запросов? +Как сервис должен обрабатывать сценарии с несколькими схемами? +Должны ли идентификаторы запросов быть настраиваемыми параметрами для сервиса? + +## Ссылки + +[Спецификация структурированного описания данных](structured-data-descriptor.md) +[Документация по загрузке структурированных данных](structured-data.md) +`tg-load-structured-data` реализация: `trustgraph-cli/trustgraph/cli/load_structured_data.py` \ No newline at end of file diff --git a/docs/tech-specs/structured-diag-service.sw.md b/docs/tech-specs/structured-diag-service.sw.md new file mode 100644 index 00000000..7c0da7a9 --- /dev/null +++ b/docs/tech-specs/structured-diag-service.sw.md @@ -0,0 +1,273 @@ +# Vigezo vya Kisaikolojia kwa Huduma ya Utambuzi wa Data Imebuniwa + +## Muhtasari + +Vigezo hivi vinaelezea huduma mpya inayoweza kutumika kwa utambuzi na uchambuzi wa data iliyobuniwa ndani ya TrustGraph. Huduma hii hutoa utendakazi kutoka kwa zana ya `tg-load-structured-data` iliyopo ya mstari wa amri na kuifanya kuwa huduma ya ombi/jibu, na hivyo kuwezesha ufikiaji wa programu kwa uwezo wa utambuzi wa aina ya data na uundaji wa maelezo. + +Huduma hii inasaidia operesheni tatu kuu: + +1. **Utambuzi wa Aina ya Data**: Changanua sampuli ya data ili kubaini muundo wake (CSV, JSON, au XML) +2. **Uundaji wa Maelezo**: Unda maelezo ya TrustGraph ya data iliyobuniwa kwa sampuli fulani ya data na aina +3. **Utambuzi Mchanganyiko**: Fanya utambuzi wa aina na uundaji wa maelezo kwa pamoja + +## Lengo + +**Kugawa Uchunguzi wa Data**: Toa mantiki ya utambuzi wa data kutoka kwa CLI hadi vipengele vya huduma vinavyoweza kutumika tena +**Kuwezesha Ufikiaji wa Programu**: Toa ufikiaji wa API kwa uwezo wa uchambuzi wa data +**Kusaidia Muundo Mbalimbali wa Data**: Shirikisha muundo wa data wa CSV, JSON, na XML kwa uthabiti +**Kuzalisha Maelezo Sahihi**: Toa maelezo ya data iliyobuniwa ambayo yanaelea data ya chanzo kwa schemas za TrustGraph +**Kuhifadhi Utangamano wa Zamani**: Hakikisha utendakazi wa sasa wa CLI unaendelea kufanya kazi +**Kuwezesha Uundaji wa Huduma**: Ruhusu huduma zingine kutumia uwezo wa utambuzi wa data +**Kuboresha Uwezekano wa Kujaribu**: Tenganisha mantiki ya biashara kutoka kwa kiolesura cha CLI kwa ajili ya majaribio bora +**Kusaidia Uchanganuzi wa Msururu**: Wezesha uchanganuzi wa sampuli za data bila kulaini faili nzima + +## Asili + +Kwa sasa, amri ya `tg-load-structured-data` hutoa utendakazi kamili kwa uchambuzi wa data iliyobuniwa na uundaji wa maelezo. Hata hivyo, utendakazi huu umeunganishwa sana na kiolesura cha CLI, na hivyo kupunguza uwezekano wake wa kutumika tena. + +Mapungufu ya sasa ni pamoja na: +Mantiki ya utambuzi wa data iliyo ndani ya nambari ya CLI +Hakuna ufikiaji wa programu kwa utambuzi wa aina na uundaji wa maelezo +Ni vigumu kuunganisha uwezo wa utambuzi katika huduma zingine +Uwezo mdogo wa kuunda mchakato wa uchambuzi wa data + +Vigezo hivi vinashughulikia pengo hizi kwa kuunda huduma maalum ya utambuzi wa data iliyobuniwa. Kwa kuonyesha uwezo huu kama huduma, TrustGraph inaweza: +Kuwezesha huduma zingine kuchambua data kwa programu +Kusaidia mnyororo wa uchakataji wa data unaozidi +Kurahisisha ushirikiano na mifumo ya nje +Kuboresha uendelevu kupitia kutenganisha masuala + +## Muundo wa Kiufundi + +### Usanifu + +Huduma ya utambuzi wa data iliyobuniwa inahitaji vipengele vifuatavyo vya kiufundi: + +1. **Mchakato wa Huduma ya Utambuzi** + Hushughulikia ombi la utambuzi linalokuja + Huendesha utambuzi wa aina na uundaji wa maelezo + Hurudisha majibu yaliyobuniwa na matokeo ya utambuzi + + Moduli: `trustgraph-flow/trustgraph/diagnosis/structured_data/service.py` + +2. **Kigunduzi cha Aina ya Data** + Hutumia utambuzi wa algorithm ili kutambua muundo wa data (CSV, JSON, XML) + Inachanganua muundo wa data, vichakavu, na mifumo ya sintaksia + Hurudisha muundo uliogunduliwa na alama za uaminifu + + Moduli: `trustgraph-flow/trustgraph/diagnosis/structured_data/type_detector.py` + +3. **Mundua wa Maelezo** + Hutumia huduma ya ombi ili kuzalisha maelezo + Huita ombi maalum ya muundo (diagnose-csv, diagnose-json, diagnose-xml) + Inoelekeza nafasi za data kwa nafasi za schema za TrustGraph kupitia majibu ya ombi + + Moduli: `trustgraph-flow/trustgraph/diagnosis/structured_data/descriptor_generator.py` + +### Mifano ya Data + +#### StructuredDataDiagnosisRequest + +Ujumbe wa ombi kwa operesheni za utambuzi wa data iliyobuniwa: + +```python +class StructuredDataDiagnosisRequest: + operation: str # "detect-type", "generate-descriptor", or "diagnose" + sample: str # Data sample to analyze (text content) + type: Optional[str] # Data type (csv, json, xml) - required for generate-descriptor + schema_name: Optional[str] # Target schema name for descriptor generation + options: Dict[str, Any] # Additional options (e.g., delimiter for CSV) +``` + +#### Jibu la Uchambuzi wa Data Iliyopangwa + +Ujumbe wa jibu unaoonyesha matokeo ya uchambuzi: + +```python +class StructuredDataDiagnosisResponse: + operation: str # The operation that was performed + detected_type: Optional[str] # Detected data type (for detect-type/diagnose) + confidence: Optional[float] # Confidence score for type detection + descriptor: Optional[Dict] # Generated descriptor (for generate-descriptor/diagnose) + error: Optional[str] # Error message if operation failed + metadata: Dict[str, Any] # Additional metadata (e.g., field count, sample records) +``` + +#### Muundo wa Kisajili + +Kisajili kinachozalishwa kinafuata muundo wa sasa wa kisajili cha data iliyopangwa: + +```json +{ + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true + } + }, + "mappings": [ + { + "source_field": "customer_id", + "target_field": "id", + "transforms": [ + {"type": "trim"} + ] + } + ], + "output": { + "schema_name": "customer", + "options": { + "batch_size": 1000, + "confidence": 0.9 + } + } +} +``` + +### Kiolesho cha Muunganisho + +Huduma itatoa huduma zifuatazo kupitia mfumo wa ombi/jibu: + +1. **Operesheni ya Udagilizaji wa Aina** + Ingizo: Sampuli ya data + Uchakataji: Angalia muundo wa data kwa kutumia ugani wa uchunguzi + Patoto: Aina iliyogunduliwa pamoja na alama ya uaminifu + +2. **Operesheni ya Uundaji wa Kisajili** + Ingizo: Sampuli ya data, aina, jina la mpango (schema) unaolengwa + Uchakataji: + Piga huduma ya ombi kwa kitambulisho cha ombi maalum kwa aina (diagnose-csv, diagnose-json, au diagnose-xml) + Pasa sampuli ya data na mipango inayopatikana kwa ombi + Pokea kisajili kilichoundwa kutoka kwa jibu la ombi + Patoto: Kisajili cha data iliyopangwa + +3. **Operesheni ya Uchambuzi Mchanganyiko** + Ingizo: Sampuli ya data, jina la mpango (schema) la hiari + Uchakataji: + Tumia ugani wa uchunguzi ili kubaini aina kwanza + Chagua ombi maalum kwa aina kulingana na aina iliyogunduliwa + Piga huduma ya ombi ili kuunda kisajili + Patoto: Aina iliyogunduliwa na kisajili + +### Maelezo ya Utendaji + +Huduma itafuata miongozo ya huduma ya TrustGraph: + +1. **Usajili wa Huduma** + Sajili kama aina ya `structured-diag` + Tumia mada za kipekee za ombi/jibu + Lenga darasa la msingi la FlowProcessor + Sajili PromptClientSpec kwa mwingiliano wa huduma ya ombi + +2. **Usimamizi wa Usanidi** + Pata usanidi wa mpango kupitia huduma ya usanidi + Hifadhi mipango kwa utendaji + Shirikisha mabadiliko ya usanidi kwa utaratibu + +3. **Uunganisho wa Ombi** + Tumia miundombinu iliyopo ya huduma ya ombi + Piga huduma ya ombi kwa kitambulisho cha ombi maalum kwa aina: + `diagnose-csv`: Kwa uchambuzi wa data ya CSV + `diagnose-json`: Kwa uchambuzi wa data ya JSON + `diagnose-xml`: Kwa uchambuzi wa data ya XML + Ombi zimepangwa katika usanidi wa ombi, sio zilizopangwa katika huduma + Pasa mipango na sampuli za data kama vigezo vya ombi + Changanua majibu ya ombi ili kuchimbua visajili + +4. **Usimamizi wa Hitilafu** + Thibitisha sampuli za ingizo + Toa ujumbe wa kosa unaoeleweka + Shirikisha data iliyo na kasoro kwa utaratibu + Shirikisha hitilafu za huduma ya ombi + +5. **Uchukuzi wa Sampuli** + Chakata saizi za sampuli zinazoweza kusanidiwa + Shirikisha rekodi zisizo kamili kwa utaratibu + Dumishe utaratibu wa uchukuzi + +### Uunganisho wa API + +Huduma itounganisha na API za TrustGraph zilizopo: + +Vipengele Vilivyobadilishwa: +`tg-load-structured-data` CLI - Imepangwa upya ili kutumia huduma mpya kwa operesheni za uchambuzi +Flow API - Imepanuliwa ili kusaidia ombi za uchambuzi wa data iliyopangwa + +Ncha Mpya za Huduma: +`/api/v1/flow/{flow}/diagnose/structured-data` - Ncha ya WebSocket kwa ombi za uchambuzi +`/api/v1/diagnose/structured-data` - Ncha ya REST kwa uchambuzi wa synchronous + +### Mtiririko wa Ujumbe + +``` +Client → Gateway → Structured Diag Service → Config Service (for schemas) + ↓ + Type Detector (algorithmic) + ↓ + Prompt Service (diagnose-csv/json/xml) + ↓ + Descriptor Generator (parses prompt response) + ↓ +Client ← Gateway ← Structured Diag Service (response) +``` + +## Masuala ya Usalama + +Uthibitishaji wa pembejeo ili kuzuia mashambulizi ya kuingiza data +Mipaka ya ukubwa ya sampuli za data ili kuzuia mashambulizi ya aina ya "Denial of Service" (DoS) +Usafishaji wa maelezo yaliyoundwa +Udhibiti wa ufikiaji kupitia uthibitishaji wa TrustGraph uliopo + +## Masuala ya Utendaji + +Hifadhi maelezo ya muundo ili kupunguza idadi ya ombi kwa huduma ya usanidi +Punguza ukubwa wa sampuli ili kudumisha utendaji wa haraka +Tumia usindikaji wa mtiririko kwa sampuli kubwa za data +Lenga mitambo ya muda kwa uchambuzi unaochukua muda mrefu + +## Mkakati wa Majaribio + +1. **Majaribio ya Kitengo** + Utambuzi wa aina kwa muundo tofauti wa data + Usahihi wa uundaji wa maelezo + Hali za kushughulikia makosa + +2. **Majaribio ya Uunganisho** + Mtiririko wa ombi/jibu wa huduma + Kupata na kuhifadhi muundo + Uunganisho wa CLI + +3. **Majaribio ya Utendaji** + Usindikaji wa sampuli kubwa + Kushughulikia ombi kwa wakati mmoja + Matumizi ya kumbukumbu chini ya mzigo + +## Mpango wa Uhamisho + +1. **Awamu ya 1**: Tekeleza huduma na utendaji wa msingi +2. **Awamu ya 2**: Badilisha CLI ili itumie huduma (dumishe utangamano wa zamani) +3. **Awamu ya 3**: Ongeza vidokezo vya API ya REST +4. **Awamu ya 4**: Ondoa mantiki iliyojumuishwa ya CLI (na kipindi cha taarifa) + +## Ratiba + +Wiki ya 1-2: Tekeleza huduma ya msingi na utambuzi wa aina +Wiki ya 3-4: Ongeza uundaji wa maelezo na uunganisho +Wiki ya 5: Majaribio na maandishi +Wiki ya 6: Ubadilishaji wa CLI na uhamishaji + +## Maswali ya Wazi + +Je, huduma inapaswa kusaidia muundo wa ziada wa data (e.g., Parquet, Avro)? +Je, ukubwa wa juu wa sampuli kwa uchambuzi unapaswa kuwa gani? +Je, matokeo ya uchunguzi yanapaswa kuhifadhiwa kwa ombi zinazorudia? +Huduma inapaswa kushughulikia hali ya muundo mwingi vipi? +Je, kitambulisho cha ombi (prompt IDs) vinaweza kupangwa kama vigezo vya huduma? + +## Marejeleo + +[Maelezo ya Muundo wa Data](structured-data-descriptor.md) +[Maandishi ya Kupakua Data Imeundwa](structured-data.md) +`tg-load-structured-data` utekelezaji: `trustgraph-cli/trustgraph/cli/load_structured_data.py` \ No newline at end of file diff --git a/docs/tech-specs/structured-diag-service.tr.md b/docs/tech-specs/structured-diag-service.tr.md new file mode 100644 index 00000000..9c7dfbcb --- /dev/null +++ b/docs/tech-specs/structured-diag-service.tr.md @@ -0,0 +1,273 @@ +# Yapılandırılmış Veri Tanı Hizmeti Teknik Özellikleri + +## Genel Bakış + +Bu özellik, TrustGraph içinde yapılandırılmış verileri teşhis etmek ve analiz etmek için yeni bir kullanılabilir hizmeti tanımlar. Bu hizmet, mevcut `tg-load-structured-data` komut satırı aracından işlevleri ayırır ve bunları istek/yanıt hizmeti olarak sunar, böylece veri türü algılama ve tanımlayıcı oluşturma yeteneklerine programlı erişim sağlar. + +Bu hizmet, üç birincil işlemi destekler: + +1. **Veri Türü Algılama**: Bir veri örneğinin biçimini (CSV, JSON veya XML) belirlemek için analiz gerçekleştirin. +2. **Tanımlayıcı Oluşturma**: Verilen bir veri örneği ve tür için bir TrustGraph yapılandırılmış veri tanımlayıcısı oluşturun. +3. **Birleşik Tanı**: Hem tür algılama hem de tanımlayıcı oluşturmayı sırayla gerçekleştirin. + +## Hedefler + +**Veri Analizini Modülerleştirme**: Veri teşhis mantığını CLI'dan yeniden kullanılabilir hizmet bileşenlerine ayırma. +**Programlı Erişimi Sağlama**: Veri analiz yeteneklerine API tabanlı erişim sağlama. +**Çoklu Veri Biçimlerini Destekleme**: CSV, JSON ve XML veri biçimlerini tutarlı bir şekilde işleme. +**Doğru Tanımlayıcılar Oluşturma**: Kaynak verileri TrustGraph şemalarına doğru bir şekilde eşleyen yapılandırılmış veri tanımlayıcıları oluşturma. +**Geriye Dönük Uyumluluğu Koruma**: Mevcut CLI işlevselliğinin çalışmaya devam etmesini sağlama. +**Hizmet Birleştirme İmkanı Sağlama**: Diğer hizmetlerin veri teşhis yeteneklerinden yararlanmasına olanak sağlama. +**Test Edilebilirliği Artırma**: İş mantığını CLI arayüzünden ayırarak daha iyi test imkanı sağlama. +**Akış Analizini Destekleme**: Tüm dosyaları yüklemeden veri örneklerinin analizini yapma imkanı sağlama. + +## Arka Plan + +Şu anda, `tg-load-structured-data` komutu, yapılandırılmış verileri analiz etmek ve tanımlayıcılar oluşturmak için kapsamlı işlevsellik sağlar. Ancak, bu işlevsellik CLI arayüzüne sıkı bir şekilde bağlıdır ve yeniden kullanılabilirliğini sınırlar. + +Mevcut sınırlamalar şunlardır: +Veri teşhis mantığının CLI kodunda yer alması. +Tür algılama ve tanımlayıcı oluşturma için programlı erişimin olmaması. +Teşhis yeteneklerinin diğer hizmetlere entegre edilmesinin zor olması. +Veri analiz iş akışlarının birleştirme yeteneğinin sınırlı olması. + +Bu özellik, yapılandırılmış veri teşhisi için özel bir hizmet oluşturarak bu boşlukları giderir. Bu yetenekleri bir hizmet olarak sunarak, TrustGraph şunları yapabilir: +Diğer hizmetlerin verileri programlı olarak analiz etmesine olanak sağlama. +Daha karmaşık veri işleme süreçlerini destekleme. +Harici sistemlerle entegrasyonu kolaylaştırma. +Endişelerin ayrılması yoluyla bakım kolaylığını artırma. + +## Teknik Tasarım + +### Mimari + +Yapılandırılmış veri teşhis hizmeti, aşağıdaki teknik bileşenleri gerektirir: + +1. **Teşhis Hizmeti İşlemcisi** + Gelen teşhis isteklerini işler. + Tür algılama ve tanımlayıcı oluşturmayı koordine eder. + Teşhis sonuçlarıyla yapılandırılmış yanıtlar döndürür. + + Modül: `trustgraph-flow/trustgraph/diagnosis/structured_data/service.py` + +2. **Veri Türü Algılayıcı** + Algoritmik algılama kullanarak veri biçimini (CSV, JSON, XML) belirler. + Veri yapısını, ayırıcıları ve sözdizimi kalıplarını analiz eder. + Algılanan biçimi ve güvenilirlik puanlarını döndürür. + + Modül: `trustgraph-flow/trustgraph/diagnosis/structured_data/type_detector.py` + +3. **Tanımlayıcı Oluşturucu** + Tanımlayıcılar oluşturmak için bir istem hizmetini kullanır. + Biçime özgü istemleri (diagnose-csv, diagnose-json, diagnose-xml) çağırır. + Veri alanlarını, istem yanıtları aracılığıyla TrustGraph şema alanlarına eşler. + + Modül: `trustgraph-flow/trustgraph/diagnosis/structured_data/descriptor_generator.py` + +### Veri Modelleri + +#### StructuredDataDiagnosisRequest + +Yapılandırılmış veri teşhis işlemleri için istek mesajı: + +```python +class StructuredDataDiagnosisRequest: + operation: str # "detect-type", "generate-descriptor", or "diagnose" + sample: str # Data sample to analyze (text content) + type: Optional[str] # Data type (csv, json, xml) - required for generate-descriptor + schema_name: Optional[str] # Target schema name for descriptor generation + options: Dict[str, Any] # Additional options (e.g., delimiter for CSV) +``` + +#### YapılandırılmışVeriTeşhisYanıtı + +Teşhis sonuçlarını içeren yanıt mesajı: + +```python +class StructuredDataDiagnosisResponse: + operation: str # The operation that was performed + detected_type: Optional[str] # Detected data type (for detect-type/diagnose) + confidence: Optional[float] # Confidence score for type detection + descriptor: Optional[Dict] # Generated descriptor (for generate-descriptor/diagnose) + error: Optional[str] # Error message if operation failed + metadata: Dict[str, Any] # Additional metadata (e.g., field count, sample records) +``` + +#### Açıklayıcı Yapı + +Oluşturulan açıklayıcı, mevcut yapılandırılmış veri açıklayıcı biçimini izler: + +```json +{ + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true + } + }, + "mappings": [ + { + "source_field": "customer_id", + "target_field": "id", + "transforms": [ + {"type": "trim"} + ] + } + ], + "output": { + "schema_name": "customer", + "options": { + "batch_size": 1000, + "confidence": 0.9 + } + } +} +``` + +### Hizmet Arayüzü + +Hizmet, istek/yanıt kalıbı aracılığıyla aşağıdaki işlemleri sunacaktır: + +1. **Tip Algılama İşlemi** + Giriş: Veri örneği + İşlem: Algoritmik algılama kullanarak veri yapısını analiz etme + Çıkış: Belirlenen tip ve güvenilirlik skoru + +2. **Açıklayıcı Oluşturma İşlemi** + Giriş: Veri örneği, tip, hedef şema adı + İşlem: + Biçime özgü bir istem kimliği (diagnose-csv, diagnose-json veya diagnose-xml) ile istem hizmetini çağırın. + Veri örneğini ve mevcut şemaları isteme iletin. + İstem yanıtından oluşturulan açıklayıcıyı alın. + Çıkış: Yapılandırılmış veri açıklayıcısı + +3. **Birleşik Tanılama İşlemi** + Giriş: Veri örneği, isteğe bağlı şema adı + İşlem: + Önce algoritmik algılama kullanarak biçimi belirleyin. + Belirlenen tipe göre uygun biçime özgü istemi seçin. + Açıklayıcı oluşturmak için istem hizmetini çağırın. + Çıkış: Hem belirlenen tip hem de açıklayıcı + +### Uygulama Detayları + +Hizmet, TrustGraph hizmeti geleneklerini takip edecektir: + +1. **Hizmet Kaydı** + `structured-diag` hizmet türü olarak kaydedin + Standart istek/yanıt konularını kullanın + FlowProcessor temel sınıfını uygulayın + İstem hizmeti etkileşimi için PromptClientSpec'i kaydedin + +2. **Yapılandırma Yönetimi** + Şema yapılandırmalarına yapılandırma hizmeti aracılığıyla erişin + Performans için şemaları önbelleğe alın + Yapılandırma güncellemelerini dinamik olarak işleyin + +3. **İstem Entegrasyonu** + Mevcut istem hizmeti altyapısını kullanın + Biçime özgü istem kimlikleriyle istem hizmetini çağırın: + `diagnose-csv`: CSV verisi analizi için + `diagnose-json`: JSON verisi analizi için + `diagnose-xml`: XML verisi analizi için + İstemler, hizmette sabit kodlanmış olan istem yapılandırmasında yapılandırılmıştır. + Şemaları ve veri örneklerini istem değişkenleri olarak iletin + Açıklayıcıları çıkarmak için istem yanıtlarını ayrıştırın + +4. **Hata Yönetimi** + Giriş veri örneklerini doğrulayın + Açıklayıcı hata mesajları sağlayın + Hatalı verileri zarif bir şekilde işleyin + İstem hizmeti hatalarını işleyin + +5. **Veri Örneklemesi** + Yapılandırılabilir örnek boyutlarını işleyin + Eksik kayıtları uygun şekilde işleyin + Örnekleme tutarlılığını koruyun + +### API Entegrasyonu + +Hizmet, mevcut TrustGraph API'leriyle entegre olacaktır: + +Değiştirilen Bileşenler: +`tg-load-structured-data` CLI - Tanılama işlemleri için yeni hizmeti kullanmak üzere yeniden düzenlendi +Flow API - Yapılandırılmış veri tanılama isteklerini desteklemek üzere genişletildi + +Yeni Hizmet Uç Noktaları: +`/api/v1/flow/{flow}/diagnose/structured-data` - Tanılama istekleri için WebSocket uç noktası +`/api/v1/diagnose/structured-data` - Senkron tanılama için REST uç noktası + +### Mesaj Akışı + +``` +Client → Gateway → Structured Diag Service → Config Service (for schemas) + ↓ + Type Detector (algorithmic) + ↓ + Prompt Service (diagnose-csv/json/xml) + ↓ + Descriptor Generator (parses prompt response) + ↓ +Client ← Gateway ← Structured Diag Service (response) +``` + +## Güvenlik Hususları + +Enjeksiyon saldırılarını önlemek için girdi doğrulama +DoS saldırılarını önlemek için veri örnekleri üzerindeki boyut sınırlamaları +Oluşturulan tanımlayıcıların temizlenmesi +Mevcut TrustGraph kimlik doğrulama aracılığıyla erişim kontrolü + +## Performans Hususları + +Yapılandırma hizmeti çağrılarını azaltmak için şema tanımlarını önbelleğe alın +Duyarlı performansı korumak için örnek boyutlarını sınırlayın +Büyük veri örnekleri için akış işleme kullanın +Uzun süren analizler için zaman aşımı mekanizmaları uygulayın + +## Test Stratejisi + +1. **Birim Testleri** + Çeşitli veri formatları için tür tespiti + Tanımlayıcı oluşturma doğruluğu + Hata işleme senaryoları + +2. **Entegrasyon Testleri** + Hizmet istek/yanıt akışı + Şema alma ve önbelleğe alma + CLI entegrasyonu + +3. **Performans Testleri** + Büyük örnek işleme + Eşzamanlı istek işleme + Yük altında bellek kullanımı + +## Geçiş Planı + +1. **1. Aşama**: Temel işlevselliğe sahip hizmeti uygulayın +2. **2. Aşama**: CLI'ı hizmeti kullanacak şekilde yeniden düzenleyin (geriye dönük uyumluluğu koruyun) +3. **3. Aşama**: REST API uç noktaları ekleyin +4. **4. Aşama**: Gömülü CLI mantığını kullanımdan kaldırın (bildirim süresiyle) + +## Zaman Çizelgesi + +1-2. Hafta: Temel hizmeti ve tür tespitini uygulayın +3-4. Hafta: Tanımlayıcı oluşturmayı ve entegrasyonu ekleyin +5. Hafta: Test ve dokümantasyon +6. Hafta: CLI yeniden düzenlemesi ve geçiş + +## Açık Sorular + +Hizmet, ek veri formatlarını (örneğin, Parquet, Avro) desteklemeli mi? +Analiz için maksimum örnek boyutu ne olmalıdır? +Teşhis sonuçları, tekrarlanan istekler için önbelleğe alınmalı mı? +Hizmet, çoklu şema senaryolarını nasıl işlemelidir? +İstek kimlikleri, hizmet için yapılandırılabilir parametreler olmalı mı? + +## Referanslar + +[Yapılandırılmış Veri Tanımlayıcı Özellikleri](structured-data-descriptor.md) +[Yapılandırılmış Veri Yükleme Dokümantasyonu](structured-data.md) +`tg-load-structured-data` uygulaması: `trustgraph-cli/trustgraph/cli/load_structured_data.py` \ No newline at end of file diff --git a/docs/tech-specs/structured-diag-service.zh-cn.md b/docs/tech-specs/structured-diag-service.zh-cn.md new file mode 100644 index 00000000..8bb26fd6 --- /dev/null +++ b/docs/tech-specs/structured-diag-service.zh-cn.md @@ -0,0 +1,273 @@ +# 结构化数据诊断服务技术规范 + +## 概述 + +本规范描述了一种新的可调用服务,用于诊断和分析 TrustGraph 中的结构化数据。该服务从现有的 `tg-load-structured-data` 命令行工具中提取功能,并将其暴露为请求/响应服务,从而实现对数据类型检测和描述符生成功能的编程访问。 + +该服务支持三种主要操作: + +1. **数据类型检测**: 分析数据样本以确定其格式(CSV、JSON 或 XML) +2. **描述符生成**: 为给定的数据样本和类型生成 TrustGraph 结构化数据描述符 +3. **综合诊断**: 依次执行数据类型检测和描述符生成 + +## 目标 + +**模块化数据分析**: 将数据诊断逻辑从 CLI 提取到可重用的服务组件中 +**启用编程访问**: 提供基于 API 的访问数据分析能力 +**支持多种数据格式**: 始终如一地处理 CSV、JSON 和 XML 数据格式 +**生成准确的描述符**: 生成准确映射源数据到 TrustGraph 模式的结构化数据描述符 +**保持向后兼容性**: 确保现有的 CLI 功能继续正常工作 +**启用服务组合**: 允许其他服务利用数据诊断能力 +**提高可测试性**: 将业务逻辑与 CLI 接口分离,以获得更好的测试效果 +**支持流式分析**: 允许分析数据样本,而无需加载整个文件 + +## 背景 + +目前,`tg-load-structured-data` 命令提供了用于分析结构化数据和生成描述符的全面功能。但是,此功能与 CLI 接口紧密耦合,限制了其可重用性。 + +当前的限制包括: +数据诊断逻辑嵌入在 CLI 代码中 +没有对数据类型检测和描述符生成的编程访问 +难以将诊断能力集成到其他服务中 +难以组合数据分析工作流程 + +本规范通过创建一个专用的结构化数据诊断服务来解决这些差距。通过将这些功能暴露为服务,TrustGraph 可以: +允许其他服务以编程方式分析数据 +支持更复杂的数据处理管道 +促进与外部系统的集成 +通过分离关注点来提高可维护性 + +## 技术设计 + +### 架构 + +结构化数据诊断服务需要以下技术组件: + +1. **诊断服务处理器** + 处理传入的诊断请求 + 协调数据类型检测和描述符生成 + 返回包含诊断结果的结构化响应 + + 模块:`trustgraph-flow/trustgraph/diagnosis/structured_data/service.py` + +2. **数据类型检测器** + 使用算法检测来识别数据格式(CSV、JSON、XML) + 分析数据结构、分隔符和语法模式 + 返回检测到的格式和置信度分数 + + 模块:`trustgraph-flow/trustgraph/diagnosis/structured_data/type_detector.py` + +3. **描述符生成器** + 使用提示服务生成描述符 + 调用特定于格式的提示(diagnose-csv、diagnose-json、diagnose-xml) + 通过提示响应将数据字段映射到 TrustGraph 模式字段 + + 模块:`trustgraph-flow/trustgraph/diagnosis/structured_data/descriptor_generator.py` + +### 数据模型 + +#### StructuredDataDiagnosisRequest + +结构化数据诊断操作的请求消息: + +```python +class StructuredDataDiagnosisRequest: + operation: str # "detect-type", "generate-descriptor", or "diagnose" + sample: str # Data sample to analyze (text content) + type: Optional[str] # Data type (csv, json, xml) - required for generate-descriptor + schema_name: Optional[str] # Target schema name for descriptor generation + options: Dict[str, Any] # Additional options (e.g., delimiter for CSV) +``` + +#### 结构化数据诊断响应 + +包含诊断结果的响应消息: + +```python +class StructuredDataDiagnosisResponse: + operation: str # The operation that was performed + detected_type: Optional[str] # Detected data type (for detect-type/diagnose) + confidence: Optional[float] # Confidence score for type detection + descriptor: Optional[Dict] # Generated descriptor (for generate-descriptor/diagnose) + error: Optional[str] # Error message if operation failed + metadata: Dict[str, Any] # Additional metadata (e.g., field count, sample records) +``` + +#### 描述符结构 + +生成的描述符遵循现有的结构化数据描述符格式: + +```json +{ + "format": { + "type": "csv", + "encoding": "utf-8", + "options": { + "delimiter": ",", + "has_header": true + } + }, + "mappings": [ + { + "source_field": "customer_id", + "target_field": "id", + "transforms": [ + {"type": "trim"} + ] + } + ], + "output": { + "schema_name": "customer", + "options": { + "batch_size": 1000, + "confidence": 0.9 + } + } +} +``` + +### 服务接口 + +该服务将通过请求/响应模式提供以下操作: + +1. **类型检测操作** + 输入:数据样本 + 处理:使用算法检测分析数据结构 + 输出:检测到的类型及其置信度分数 + +2. **描述符生成操作** + 输入:数据样本、类型、目标模式名称 + 处理: + 使用特定格式的提示 ID(diagnose-csv、diagnose-json 或 diagnose-xml)调用提示服务 + 将数据样本和可用模式传递给提示 + 从提示响应接收生成的描述符 + 输出:结构化数据描述符 + +3. **综合诊断操作** + 输入:数据样本、可选模式名称 + 处理: + 首先使用算法检测识别格式 + 根据检测到的类型选择适当的特定格式的提示 + 调用提示服务以生成描述符 + 输出:检测到的类型和描述符 + +### 实现细节 + +该服务将遵循 TrustGraph 服务约定: + +1. **服务注册** + 注册为 `structured-diag` 服务类型 + 使用标准的请求/响应主题 + 实现 FlowProcessor 基础类 + 注册 PromptClientSpec 以进行提示服务交互 + +2. **配置管理** + 通过配置服务访问模式配置 + 缓存模式以提高性能 + 动态处理配置更新 + +3. **提示集成** + 使用现有的提示服务基础设施 + 使用特定格式的提示 ID调用提示服务: + `diagnose-csv`:用于 CSV 数据分析 + `diagnose-json`:用于 JSON 数据分析 + `diagnose-xml`:用于 XML 数据分析 + 提示配置在提示配置中,而不是硬编码在服务中 + 将模式和数据样本作为提示变量传递 + 解析提示响应以提取描述符 + +4. **错误处理** + 验证输入数据样本 + 提供描述性的错误消息 + 优雅地处理格式错误的数据 + 处理提示服务故障 + +5. **数据采样** + 处理可配置的样本大小 + 适当处理不完整的记录 + 保持采样的一致性 + +### API 集成 + +该服务将与现有的 TrustGraph API 集成: + +修改的组件: +`tg-load-structured-data` CLI - 重新设计为使用新的服务进行诊断操作 +Flow API - 扩展以支持结构化数据诊断请求 + +新的服务端点: +`/api/v1/flow/{flow}/diagnose/structured-data` - 用于诊断请求的 WebSocket 端点 +`/api/v1/diagnose/structured-data` - 用于同步诊断的 REST 端点 + +### 消息流 + +``` +Client → Gateway → Structured Diag Service → Config Service (for schemas) + ↓ + Type Detector (algorithmic) + ↓ + Prompt Service (diagnose-csv/json/xml) + ↓ + Descriptor Generator (parses prompt response) + ↓ +Client ← Gateway ← Structured Diag Service (response) +``` + +## 安全注意事项 + +输入验证,以防止注入攻击 +对数据样本的大小设置限制,以防止拒绝服务 (DoS) 攻击 +清理生成的描述符 +通过现有的 TrustGraph 身份验证进行访问控制 + +## 性能注意事项 + +缓存模式定义,以减少对配置服务的调用 +限制样本大小,以保持响应性能 +对大型数据样本使用流式处理 +实施超时机制,用于长时间运行的分析 + +## 测试策略 + +1. **单元测试** + 对各种数据格式进行类型检测 + 描述符生成准确性 + 错误处理场景 + +2. **集成测试** + 服务请求/响应流程 + 模式检索和缓存 + CLI 集成 + +3. **性能测试** + 处理大型样本 + 并发请求处理 + 在负载下的内存使用情况 + +## 迁移计划 + +1. **第一阶段**: 实施具有核心功能的服务 +2. **第二阶段**: 重构 CLI 以使用服务(保持向后兼容性) +3. **第三阶段**: 添加 REST API 端点 +4. **第四阶段**: 弃用嵌入式 CLI 逻辑(提前通知) + +## 时间表 + +第 1-2 周:实施核心服务和类型检测 +第 3-4 周:添加描述符生成和集成 +第 5 周:测试和文档 +第 6 周:CLI 重构和迁移 + +## 开放问题 + +该服务是否应支持其他数据格式(例如,Parquet、Avro)? +分析的最大样本大小应为多少? +诊断结果是否应针对重复请求进行缓存? +该服务应如何处理多模式场景? +提示 ID 是否应为服务的可配置参数? + +## 参考文献 + +[结构化数据描述符规范](structured-data-descriptor.md) +[结构化数据加载文档](structured-data.md) +`tg-load-structured-data` 实现:`trustgraph-cli/trustgraph/cli/load_structured_data.py` \ No newline at end of file diff --git a/docs/tech-specs/tool-group.ar.md b/docs/tech-specs/tool-group.ar.md new file mode 100644 index 00000000..e03d6c86 --- /dev/null +++ b/docs/tech-specs/tool-group.ar.md @@ -0,0 +1,491 @@ +# مجموعة أدوات TrustGraph +## المواصفات الفنية v1.0 + +### ملخص تنفيذي + +تحدد هذه المواصفات نظام تجميع الأدوات لوكلاء TrustGraph، مما يسمح بالتحكم الدقيق في الأدوات المتاحة لطلبات معينة. يقدم النظام تصفية الأدوات المستندة إلى المجموعات من خلال التكوين وتحديد مستوى الطلب، مما يتيح حدودًا أمنية أفضل وإدارة الموارد وتقسيمًا وظيفيًا لقدرات الوكيل. + +### 1. نظرة عامة + +#### 1.1 بيان المشكلة + +حاليًا، يتمتع وكلاء TrustGraph بإمكانية الوصول إلى جميع الأدوات المكونة بغض النظر عن سياق الطلب أو متطلبات الأمان. وهذا يخلق عدة تحديات: + +**مخاطر أمنية**: الأدوات الحساسة (مثل تعديل البيانات) متاحة حتى للاستعلامات للقراءة فقط. +**إهدار الموارد**: يتم تحميل الأدوات المعقدة حتى عندما لا تتطلب الاستعلامات البسيطة ذلك. +**ارتباك وظيفي**: قد تختار الوكلاء أدوات غير مناسبة عندما تكون هناك بدائل أبسط. +**العزل متعدد المستأجرين**: تحتاج مجموعات المستخدمين المختلفة إلى الوصول إلى مجموعات أدوات مختلفة. + +#### 1.2 نظرة عامة على الحل + +يقدم نظام تجميع الأدوات ما يلي: + +1. **تصنيف المجموعات**: يتم وضع علامة على الأدوات باستخدام عضوية المجموعة أثناء التكوين. +2. **التصفية على مستوى الطلب**: يحدد AgentRequest مجموعات الأدوات المسموح بها. +3. **التنفيذ في وقت التشغيل**: لا تملك الوكلاء سوى الأدوات التي تتطابق مع المجموعات المطلوبة. +4. **تجميع مرن**: يمكن أن تنتمي الأدوات إلى مجموعات متعددة للسيناريوهات المعقدة. + +### 2. تغييرات المخطط + +#### 2.1 تحسين مخطط تكوين الأداة + +يتم تحسين تكوين الأداة الحالي بإضافة حقل `group`: + +**قبل:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph" +} +``` + +**بعد:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"] +} +``` + +**تحديد حقل المجموعة:** +`group`: Array(String) - قائمة المجموعات التي تنتمي إليها هذه الأداة. +**اختياري**: الأدوات التي لا تحتوي على حقل المجموعة تنتمي إلى المجموعة الافتراضية. +**العضوية المتعددة**: يمكن للأدوات أن تنتمي إلى مجموعات متعددة. +**حساسية حالة الأحرف**: أسماء المجموعات هي مطابقات دقيقة للسلاسل النصية. + +#### 2.1.2 تحسين انتقال حالة الأداة + +يمكن للأدوات تحديد انتقالات الحالة وحالة التوفر بناءً على الحالة بشكل اختياري: + +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"], + "state": "analysis", + "available_in_states": ["undefined", "research"] +} +``` + +**تحديد حقل الحالة:** +`state`: String - **اختياري** - الحالة التي يتم الانتقال إليها بعد تنفيذ الأداة بنجاح +`available_in_states`: Array(String) - **اختياري** - الحالات التي تتوفر فيها هذه الأداة +**السلوك الافتراضي**: الأدوات التي لا تحتوي على `available_in_states` متاحة في جميع الحالات +**انتقال الحالة**: يحدث فقط بعد تنفيذ الأداة بنجاح + +#### 2.2 تحسين مخطط AgentRequest + +مخطط `AgentRequest` في `trustgraph-base/trustgraph/schema/services/agent.py` تم تحسينه: + +**AgentRequest الحالي:** +`question`: String - استعلام المستخدم +`plan`: String - خطة التنفيذ (يمكن إزالتها) +`state`: String - حالة الوكيل +`history`: Array(AgentStep) - سجل التنفيذ + +**AgentRequest المحسن:** +`question`: String - استعلام المستخدم +`state`: String - حالة تنفيذ الوكيل (تستخدم الآن بنشاط لتصفية الأدوات) +`history`: Array(AgentStep) - سجل التنفيذ +`group`: Array(String) - **جديد** - مجموعات الأدوات المسموح بها لهذا الطلب + +**تغييرات المخطط:** +**تمت إزالة**: حقل `plan` لم يعد مطلوبًا ويمكن إزالته (كان مخصصًا في الأصل لتحديد الأدوات) +**تمت إضافة**: حقل `group` لتحديد مجموعة الأدوات +**تم التحسين**: يتحكم حقل `state` الآن في توفر الأدوات أثناء التنفيذ + +**سلوكيات الحقول:** + +**حقل المجموعة:** +**اختياري**: إذا لم يتم تحديده، فسيتم تعيينه افتراضيًا إلى ["default"] +**التقاطع**: تتوفر فقط الأدوات التي تتطابق مع مجموعة واحدة على الأقل من المجموعات المحددة +**مصفوفة فارغة**: لا تتوفر أي أدوات (يمكن للوكيل استخدام الاستدلال الداخلي فقط) +**رمز بدل (Wildcard)**: تمنح المجموعة الخاصة "*" إمكانية الوصول إلى جميع الأدوات + +**حقل الحالة:** +**اختياري**: إذا لم يتم تحديده، فسيتم تعيينه افتراضيًا إلى "undefined" +**التصفية بناءً على الحالة**: الأدوات المتاحة فقط في الحالة الحالية هي المؤهلة +**الحالة الافتراضية**: تسمح حالة "undefined" بجميع الأدوات (مع مراعاة تصفية المجموعة) +**انتقالات الحالة**: يمكن للأدوات تغيير الحالة بعد التنفيذ الناجح + +### 3. أمثلة على المجموعات المخصصة + +يمكن للمؤسسات تحديد مجموعات خاصة بالمجال: + +```json +{ + "financial-tools": ["stock-query", "portfolio-analysis"], + "medical-tools": ["diagnosis-assist", "drug-interaction"], + "legal-tools": ["contract-analysis", "case-search"] +} +``` + +### 4. تفاصيل التنفيذ + +#### 4.1 تحميل الأدوات وتصفيتها + +**مرحلة التهيئة:** +1. يتم تحميل جميع الأدوات من ملف التهيئة مع تحديد مجموعاتها. +2. يتم تعيين الأدوات التي لا تحتوي على مجموعات محددة إلى المجموعة "الافتراضية". +3. يتم التحقق من عضوية المجموعة وتخزينها في سجل الأدوات. + +**مرحلة معالجة الطلبات:** +1. يصل طلب الوكيل (AgentRequest) مع تحديد المجموعة الاختياري. +2. يقوم الوكيل بتصفية الأدوات المتاحة بناءً على تقاطع المجموعات. +3. يتم تمرير الأدوات المتطابقة فقط إلى سياق تنفيذ الوكيل. +4. يعمل الوكيل مع مجموعة الأدوات المفلترة طوال دورة حياة الطلب. + +#### 4.2 منطق تصفية الأدوات + +**التصفية المجمعة للمجموعة والحالة:** + +``` +For each configured tool: + tool_groups = tool.group || ["default"] + tool_states = tool.available_in_states || ["*"] // Available in all states + +For each request: + requested_groups = request.group || ["default"] + current_state = request.state || "undefined" + +Tool is available if: + // Group filtering + (intersection(tool_groups, requested_groups) is not empty OR "*" in requested_groups) + AND + // State filtering + (current_state in tool_states OR "*" in tool_states) +``` + +**منطق الانتقال بين الحالات:** + +``` +After successful tool execution: + if tool.state is defined: + next_request.state = tool.state + else: + next_request.state = current_request.state // No change +``` + +#### 4.3 نقاط تكامل الوكيل + +**الوكيل ReAct:** +يتم تصفية الأدوات في agent_manager.py أثناء إنشاء سجل الأدوات. +يتم تصفية قائمة الأدوات المتاحة بناءً على المجموعة والحالة قبل إنشاء الخطة. +تحديثات انتقالات الحالة تحدّث حقل AgentRequest.state بعد تنفيذ الأداة بنجاح. +تستخدم التكرار التالي الحالة المحدثة لتصفية الأدوات. + +**الوكيل القائم على الثقة:** +يتم تصفية الأدوات في planner.py أثناء إنشاء الخطة. +التحقق من صحة ExecutionStep يضمن استخدام الأدوات المؤهلة فقط بناءً على المجموعة والحالة. +وحدة التحكم في التدفق تفرض توفر الأدوات في وقت التشغيل. +تتم إدارة انتقالات الحالة بواسطة وحدة التحكم في التدفق بين الخطوات. + +### 5. أمثلة التكوين + +#### 5.1 تكوين الأداة مع المجموعات والحالات + +```yaml +tool: + knowledge-query: + type: knowledge-query + name: "Knowledge Graph Query" + description: "Query the knowledge graph for entities and relationships" + group: ["read-only", "knowledge", "basic"] + state: "analysis" + available_in_states: ["undefined", "research"] + + graph-update: + type: graph-update + name: "Graph Update" + description: "Add or modify entities in the knowledge graph" + group: ["write", "knowledge", "admin"] + available_in_states: ["analysis", "modification"] + + text-completion: + type: text-completion + name: "Text Completion" + description: "Generate text using language models" + group: ["read-only", "text", "basic"] + state: "undefined" + # No available_in_states = available in all states + + complex-analysis: + type: mcp-tool + name: "Complex Analysis Tool" + description: "Perform complex data analysis" + group: ["advanced", "compute", "expensive"] + state: "results" + available_in_states: ["analysis"] + mcp_tool_id: "analysis-server" + + reset-workflow: + type: mcp-tool + name: "Reset Workflow" + description: "Reset to initial state" + group: ["admin"] + state: "undefined" + available_in_states: ["analysis", "results"] +``` + +#### 5.2 أمثلة للطلبات مع سير العمل الخاص بالحالة. + +**طلب البحث الأولي:** +```json +{ + "question": "What entities are connected to Company X?", + "group": ["read-only", "knowledge"], + "state": "undefined" +} +``` +*الأدوات المتاحة: knowledge-query، text-completion* +*بعد استخدام knowledge-query: الحالة → "analysis"* + +**مرحلة التحليل:** +```json +{ + "question": "Continue analysis based on previous results", + "group": ["advanced", "compute", "write"], + "state": "analysis" +} +``` +*الأدوات المتاحة: تحليل معقد، تحديث الرسم البياني، إعادة تعيين سير العمل* +*بعد التحليل المعقد: الحالة → "النتائج"* + +**مرحلة النتائج:** +```json +{ + "question": "What should I do with these results?", + "group": ["admin"], + "state": "results" +} +``` +*الأدوات المتاحة: reset-workflow فقط* +*بعد reset-workflow: الحالة → "غير محددة"* + +**مثال سير العمل - التدفق الكامل:** +1. **البداية (غير محددة):** استخدم knowledge-query للانتقال إلى الحالة "تحليل". +2. **حالة التحليل:** استخدم complex-analysis للانتقال إلى الحالة "النتائج". +3. **حالة النتائج:** استخدم reset-workflow للعودة إلى الحالة "غير محددة". +4. **العودة إلى البداية:** تتوفر جميع الأدوات الأولية مرة أخرى. + +### 6. اعتبارات الأمان + +#### 6.1 تكامل التحكم في الوصول + +**التصفية على مستوى البوابة:** +يمكن للبوابة فرض قيود على المجموعات بناءً على أذونات المستخدم. +منع رفع الامتيازات من خلال التلاعب بالطلبات. +يتضمن سجل التدقيق المجموعات المطلوبة والمجموعات الممنوحة. + +**مثال لمنطق البوابة:** +``` +user_permissions = get_user_permissions(request.user_id) +allowed_groups = user_permissions.tool_groups +requested_groups = request.group + +# Validate request doesn't exceed permissions +if not is_subset(requested_groups, allowed_groups): + reject_request("Insufficient permissions for requested tool groups") +``` + +#### 6.2 التدقيق والمراقبة + +**مسار تدقيق مُحسّن:** +تسجيل مجموعات الأدوات المطلوبة والحالة الأولية لكل طلب. +تتبع عمليات انتقال الحالة واستخدام الأدوات حسب عضوية المجموعة. +مراقبة محاولات الوصول غير المصرح بها إلى المجموعة والانتقالات غير الصالحة للحالة. +إرسال تنبيهات عند وجود أنماط استخدام غير عادية للمجموعة أو سير عمل حالة مشبوه. + +### 7. استراتيجية الترحيل + +#### 7.1 التوافق مع الإصدارات السابقة + +**المرحلة الأولى: تغييرات إضافية** +إضافة حقل `group` اختياري إلى تكوينات الأدوات. +إضافة حقل `group` اختياري إلى مخطط AgentRequest. +السلوك الافتراضي: تنتمي جميع الأدوات الحالية إلى المجموعة "الافتراضية". +تستخدم الطلبات الحالية التي لا تحتوي على حقل المجموعة المجموعة "الافتراضية". + +**الحفاظ على السلوك الحالي:** +تستمر الأدوات التي لا تحتوي على تكوين مجموعة في العمل (المجموعة الافتراضية). +الأدوات التي لا تحتوي على تكوين حالة متاحة في جميع الحالات. +يمكن للطلبات التي لا تحدد المجموعة الوصول إلى جميع الأدوات (المجموعة الافتراضية). +تستخدم الطلبات التي لا تحدد الحالة حالة "غير محددة" (جميع الأدوات متاحة). +لا توجد تغييرات تؤثر على عمليات النشر الحالية. + +### 8. المراقبة وقابلية الملاحظة + +#### 8.1 مقاييس جديدة + +**استخدام مجموعة الأدوات:** +`agent_tool_group_requests_total` - عد الطلبات حسب المجموعة. +`agent_tool_group_availability` - مقياس للأدوات المتاحة لكل مجموعة. +`agent_filtered_tools_count` - رسم بياني لعدد الأدوات بعد تصفية المجموعة والحالة. + +**مقاييس سير عمل الحالة:** +`agent_state_transitions_total` - عد عمليات انتقال الحالة لكل أداة. +`agent_workflow_duration_seconds` - رسم بياني للوقت المستغرق في كل حالة. +`agent_state_availability` - مقياس للأدوات المتاحة لكل حالة. + +**مقاييس الأمان:** +`agent_group_access_denied_total` - عد الوصول غير المصرح به إلى المجموعة. +`agent_invalid_state_transition_total` - عد عمليات انتقال الحالة غير الصالحة. +`agent_privilege_escalation_attempts_total` - عد الطلبات المشبوهة. + +#### 8.2 تحسينات التسجيل + +**تسجيل الطلبات:** +```json +{ + "request_id": "req-123", + "requested_groups": ["read-only", "knowledge"], + "initial_state": "undefined", + "state_transitions": [ + {"tool": "knowledge-query", "from": "undefined", "to": "analysis", "timestamp": "2024-01-01T10:00:01Z"} + ], + "available_tools": ["knowledge-query", "text-completion"], + "filtered_by_group": ["graph-update", "admin-tool"], + "filtered_by_state": [], + "execution_time": "1.2s" +} +``` + +### 9. استراتيجية الاختبار + +#### 9.1 اختبارات الوحدة + +**منطق تصفية الأدوات:** +حسابات تقاطع مجموعات الاختبار. +منطق التصفية المستند إلى الحالة. +التحقق من التعيين الافتراضي للمجموعة والحالة. +اختبار سلوك المجموعة باستخدام أحرف البدل. +التحقق من معالجة المجموعات الفارغة. +اختبار سيناريوهات التصفية المجمعة للمجموعة والحالة. + +**التحقق من التكوين:** +اختبار تحميل الأدوات مع تكوينات مختلفة للمجموعة والحالة. +التحقق من صحة المخطط للمواصفات غير الصالحة للمجموعة والحالة. +اختبار التوافق مع الإصدارات السابقة مع التكوينات الحالية. +التحقق من تعريفات دورات الانتقال بين الحالات. + +#### 9.2 اختبارات التكامل + +**سلوك الوكيل:** +التحقق من أن الوكلاء يرون فقط الأدوات التي تم تصفيتها حسب المجموعة والحالة. +اختبار تنفيذ الطلبات مع مجموعات مختلفة. +اختبار الانتقالات بين الحالات أثناء تنفيذ الوكيل. +التحقق من معالجة الأخطاء عندما لا تتوفر أي أدوات. +اختبار تقدم سير العمل عبر حالات متعددة. + +**اختبار الأمان:** +اختبار منع تصعيد الامتيازات. +التحقق من دقة سجل التدقيق. +اختبار تكامل البوابة مع أذونات المستخدم. + +#### 9.3 سيناريوهات شاملة + +**الاستخدام متعدد المستأجر مع سير عمل الحالة:** +``` +Scenario: Different users with different tool access and workflow states +Given: User A has "read-only" permissions, state "undefined" + And: User B has "write" permissions, state "analysis" +When: Both request knowledge operations +Then: User A gets read-only tools available in "undefined" state + And: User B gets write tools available in "analysis" state + And: State transitions are tracked per user session + And: All usage and transitions are properly audited +``` + +**تطور حالة سير العمل:** +``` +Scenario: Complete workflow execution +Given: Request with groups ["knowledge", "compute"] and state "undefined" +When: Agent executes knowledge-query tool (transitions to "analysis") + And: Agent executes complex-analysis tool (transitions to "results") + And: Agent executes reset-workflow tool (transitions to "undefined") +Then: Each step has correctly filtered available tools + And: State transitions are logged with timestamps + And: Final state allows initial workflow to repeat +``` + +### 10. الاعتبارات المتعلقة بالأداء + +#### 10.1 تأثير تحميل الأدوات + +**تحميل التكوين:** +يتم تحميل بيانات التعريف الخاصة بالمجموعة والحالة مرة واحدة عند بدء التشغيل. +الحد الأدنى من الحمل على الذاكرة لكل أداة (حقول إضافية). +لا يوجد تأثير على وقت تهيئة الأداة. + +**معالجة الطلبات:** +يتم تطبيق تصفية المجموعة + الحالة المجمعة مرة واحدة لكل طلب. +تعقيد O(n) حيث n = عدد الأدوات المكونة. +تضيف عمليات انتقال الحالة حملًا ضئيلًا (تعيين سلسلة). +تأثير ضئيل لعدد الأدوات النموذجي (< 100). + +#### 10.2 استراتيجيات التحسين + +**مجموعات الأدوات المحسوبة مسبقًا:** +تخزين مجموعات الأدوات حسب مجموعة + مجموعة حالة. +تجنب التصفية المتكررة لأنماط المجموعة / الحالة الشائعة. +مقايضة بين الذاكرة والحساب للتوليفات المستخدمة بشكل متكرر. + +**التحميل الكسول:** +قم بتحميل تطبيقات الأدوات فقط عند الحاجة. +تقليل وقت بدء التشغيل لنشر الأدوات العديدة. +تسجيل الأدوات الديناميكي بناءً على متطلبات المجموعة. + +### 11. التحسينات المستقبلية + +#### 11.1 التعيين الديناميكي للمجموعة + +**التجميع الواعي بالسياق:** +تعيين الأدوات إلى المجموعات بناءً على سياق الطلب. +توفر المجموعة بناءً على الوقت (ساعات العمل فقط). +قيود المجموعة بناءً على الحمل (الأدوات باهظة الثمن أثناء الاستخدام المنخفض). + +#### 11.2 التسلسلات الهرمية للمجموعات + +**هيكل المجموعة المتداخل:** +```json +{ + "knowledge": { + "read": ["knowledge-query", "entity-search"], + "write": ["graph-update", "entity-create"] + } +} +``` + +#### 11.3 توصيات بالأدوات + +**اقتراحات قائمة على المجموعات:** +اقتراح مجموعات الأدوات المثلى لأنواع الطلبات. +التعلم من أنماط الاستخدام لتحسين التوصيات. +توفير مجموعات احتياطية عندما تكون الأدوات المفضلة غير متاحة. + +### 12. أسئلة مفتوحة + +1. **التحقق من صحة المجموعة**: هل يجب أن تتسبب أسماء المجموعات غير الصالحة في الطلبات في حدوث أخطاء فادحة أم تحذيرات؟ + +2. **اكتشاف المجموعة**: هل يجب أن يوفر النظام واجهة برمجة تطبيقات (API) لسرد المجموعات المتاحة وأدواتها؟ + +3. **المجموعات الديناميكية**: هل يجب أن تكون المجموعات قابلة للتكوين في وقت التشغيل أم فقط عند بدء التشغيل؟ + +4. **وراثة المجموعة**: هل يجب أن ترث الأدوات مجموعات من فئاتها الأصلية أو تطبيقاتها؟ + +5. **مراقبة الأداء**: ما هي المقاييس الإضافية المطلوبة لتتبع استخدام الأدوات القائمة على المجموعات بشكل فعال؟ + +### 13. الخلاصة + +يوفر نظام مجموعات الأدوات ما يلي: + +**الأمان**: تحكم دقيق في الوصول إلى قدرات الوكيل. +**الأداء**: تقليل الحمل الزائد لاختيار الأدوات وتحميلها. +**المرونة**: تصنيف متعدد الأبعاد للأدوات. +**التوافق**: تكامل سلس مع بنيات الوكيل الحالية. + +يمكّن هذا النظام عمليات نشر TrustGraph من إدارة الوصول إلى الأدوات بشكل أفضل، وتحسين الحدود الأمنية، وتحسين استخدام الموارد مع الحفاظ على التوافق الكامل مع التكوينات والطلبات الحالية. diff --git a/docs/tech-specs/tool-group.es.md b/docs/tech-specs/tool-group.es.md new file mode 100644 index 00000000..bd02389c --- /dev/null +++ b/docs/tech-specs/tool-group.es.md @@ -0,0 +1,491 @@ +# Grupo de Herramientas TrustGraph +## Especificación Técnica v1.0 + +### Resumen Ejecutivo + +Esta especificación define un sistema de agrupación de herramientas para agentes de TrustGraph que permite un control preciso sobre qué herramientas están disponibles para solicitudes específicas. El sistema introduce un filtrado de herramientas basado en grupos a través de la configuración y la especificación a nivel de solicitud, lo que permite mejores límites de seguridad, gestión de recursos y partición funcional de las capacidades de los agentes. + +### 1. Descripción General + +#### 1.1 Declaración del Problema + +Actualmente, los agentes de TrustGraph tienen acceso a todas las herramientas configuradas, independientemente del contexto de la solicitud o los requisitos de seguridad. Esto crea varios desafíos: + +**Riesgo de Seguridad**: Herramientas sensibles (por ejemplo, modificación de datos) están disponibles incluso para consultas de solo lectura. +**Desperdicio de Recursos**: Se cargan herramientas complejas incluso cuando las consultas simples no las requieren. +**Confusión Funcional**: Los agentes pueden seleccionar herramientas inapropiadas cuando existen alternativas más simples. +**Aislamiento Multi-inquilino**: Diferentes grupos de usuarios necesitan acceso a diferentes conjuntos de herramientas. + +#### 1.2 Descripción General de la Solución + +El sistema de agrupación de herramientas introduce: + +1. **Clasificación por Grupos**: Las herramientas se etiquetan con membresías de grupos durante la configuración. +2. **Filtrado a Nivel de Solicitud**: AgentRequest especifica qué grupos de herramientas están permitidos. +3. **Aplicación en Tiempo de Ejecución**: Los agentes solo tienen acceso a las herramientas que coinciden con los grupos solicitados. +4. **Agrupación Flexible**: Las herramientas pueden pertenecer a múltiples grupos para escenarios complejos. + +### 2. Cambios en el Esquema + +#### 2.1 Mejora del Esquema de Configuración de Herramientas + +La configuración de herramientas existente se mejora con un campo `group`: + +**Antes:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph" +} +``` + +**Después:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"] +} +``` + +**Especificación del campo de grupo:** +`group`: Array(String) - Lista de grupos a los que pertenece esta herramienta. +**Opcional**: Las herramientas sin campo de grupo pertenecen al grupo "predeterminado". +**Múltiple pertenencia**: Las herramientas pueden pertenecer a múltiples grupos. +**Sensible a mayúsculas y minúsculas**: Los nombres de los grupos deben coincidir exactamente con la cadena. + +#### 2.1.2 Mejora de la transición de estado de la herramienta + +Las herramientas pueden especificar opcionalmente transiciones de estado y disponibilidad basada en el estado: + +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"], + "state": "analysis", + "available_in_states": ["undefined", "research"] +} +``` + +**Especificación del campo de estado:** +`state`: String - **Opcional** - Estado al que se debe pasar después de la ejecución exitosa de la herramienta. +`available_in_states`: Array(String) - **Opcional** - Estados en los que esta herramienta está disponible. +**Comportamiento predeterminado**: Las herramientas sin `available_in_states` están disponibles en todos los estados. +**Transición de estado**: Solo ocurre después de la ejecución exitosa de la herramienta. + +#### 2.2 Mejora del esquema AgentRequest + +El esquema `AgentRequest` en `trustgraph-base/trustgraph/schema/services/agent.py` se ha mejorado: + +**AgentRequest actual:** +`question`: String - Consulta del usuario. +`plan`: String - Plan de ejecución (se puede eliminar). +`state`: String - Estado del agente. +`history`: Array(AgentStep) - Historial de ejecución. + +**AgentRequest mejorado:** +`question`: String - Consulta del usuario. +`state`: String - Estado de ejecución del agente (ahora se utiliza activamente para el filtrado de herramientas). +`history`: Array(AgentStep) - Historial de ejecución. +`group`: Array(String) - **NUEVO** - Grupos de herramientas permitidos para esta solicitud. + +**Cambios en el esquema:** +**Eliminado**: El campo `plan` ya no es necesario y se puede eliminar (originalmente estaba destinado a la especificación de herramientas). +**Añadido**: El campo `group` para la especificación de grupos de herramientas. +**Mejorado**: El campo `state` ahora controla la disponibilidad de herramientas durante la ejecución. + +**Comportamientos de los campos:** + +**Grupo de campos:** +**Opcional**: Si no se especifica, el valor predeterminado es ["default"]. +**Intersección**: Solo las herramientas que coinciden con al menos un grupo especificado están disponibles. +**Arreglo vacío**: No hay herramientas disponibles (el agente solo puede usar el razonamiento interno). +**Comodín**: El grupo especial "*" otorga acceso a todas las herramientas. + +**Campo de estado:** +**Opcional**: Si no se especifica, el valor predeterminado es "undefined". +**Filtrado basado en el estado**: Solo las herramientas disponibles en el estado actual son elegibles. +**Estado predeterminado**: El estado "undefined" permite todas las herramientas (sujeto al filtrado de grupos). +**Transiciones de estado**: Las herramientas pueden cambiar de estado después de una ejecución exitosa. + +### 3. Ejemplos de grupos personalizados + +Las organizaciones pueden definir grupos específicos del dominio: + +```json +{ + "financial-tools": ["stock-query", "portfolio-analysis"], + "medical-tools": ["diagnosis-assist", "drug-interaction"], + "legal-tools": ["contract-analysis", "case-search"] +} +``` + +### 4. Detalles de implementación + +#### 4.1 Carga y filtrado de herramientas + +**Fase de configuración:** +1. Todas las herramientas se cargan desde la configuración con sus asignaciones de grupo. +2. Las herramientas sin grupos explícitos se asignan al grupo "predeterminado". +3. La pertenencia al grupo se valida y se almacena en el registro de herramientas. + +**Fase de procesamiento de solicitudes:** +1. La solicitud del agente llega con una especificación de grupo opcional. +2. El agente filtra las herramientas disponibles según la intersección de grupos. +3. Solo las herramientas que coinciden se pasan al contexto de ejecución del agente. +4. El agente opera con el conjunto de herramientas filtrado durante todo el ciclo de vida de la solicitud. + +#### 4.2 Lógica de filtrado de herramientas + +**Filtrado combinado de grupos y estado:** + +``` +For each configured tool: + tool_groups = tool.group || ["default"] + tool_states = tool.available_in_states || ["*"] // Available in all states + +For each request: + requested_groups = request.group || ["default"] + current_state = request.state || "undefined" + +Tool is available if: + // Group filtering + (intersection(tool_groups, requested_groups) is not empty OR "*" in requested_groups) + AND + // State filtering + (current_state in tool_states OR "*" in tool_states) +``` + +**Lógica de transición de estado:** + +``` +After successful tool execution: + if tool.state is defined: + next_request.state = tool.state + else: + next_request.state = current_request.state // No change +``` + +#### 4.3 Puntos de Integración del Agente + +**Agente ReAct:** +El filtrado de herramientas se produce en agent_manager.py durante la creación del registro de herramientas. +La lista de herramientas disponibles se filtra tanto por grupo como por estado antes de la generación del plan. +Las transiciones de estado actualizan el campo AgentRequest.state después de la ejecución exitosa de la herramienta. +La siguiente iteración utiliza el estado actualizado para el filtrado de herramientas. + +**Agente Basado en la Confianza:** +El filtrado de herramientas se produce en planner.py durante la generación del plan. +La validación de ExecutionStep asegura que solo se utilicen las herramientas elegibles por grupo y estado. +El controlador de flujo hace cumplir la disponibilidad de las herramientas en tiempo de ejecución. +Las transiciones de estado son gestionadas por el Controlador de Flujo entre los pasos. + +### 5. Ejemplos de Configuración + +#### 5.1 Configuración de Herramientas con Grupos y Estados + +```yaml +tool: + knowledge-query: + type: knowledge-query + name: "Knowledge Graph Query" + description: "Query the knowledge graph for entities and relationships" + group: ["read-only", "knowledge", "basic"] + state: "analysis" + available_in_states: ["undefined", "research"] + + graph-update: + type: graph-update + name: "Graph Update" + description: "Add or modify entities in the knowledge graph" + group: ["write", "knowledge", "admin"] + available_in_states: ["analysis", "modification"] + + text-completion: + type: text-completion + name: "Text Completion" + description: "Generate text using language models" + group: ["read-only", "text", "basic"] + state: "undefined" + # No available_in_states = available in all states + + complex-analysis: + type: mcp-tool + name: "Complex Analysis Tool" + description: "Perform complex data analysis" + group: ["advanced", "compute", "expensive"] + state: "results" + available_in_states: ["analysis"] + mcp_tool_id: "analysis-server" + + reset-workflow: + type: mcp-tool + name: "Reset Workflow" + description: "Reset to initial state" + group: ["admin"] + state: "undefined" + available_in_states: ["analysis", "results"] +``` + +#### 5.2 Ejemplos de solicitudes con flujos de trabajo de estado + +**Solicitud de investigación inicial:** +```json +{ + "question": "What entities are connected to Company X?", + "group": ["read-only", "knowledge"], + "state": "undefined" +} +``` +*Herramientas disponibles: knowledge-query, text-completion* +*Después de knowledge-query: estado → "análisis"* + +**Fase de análisis:** +```json +{ + "question": "Continue analysis based on previous results", + "group": ["advanced", "compute", "write"], + "state": "analysis" +} +``` +*Herramientas disponibles: análisis complejo, actualización de gráficos, restablecimiento del flujo de trabajo* +*Después del análisis complejo: estado → "resultados"* + +**Fase de resultados:** +```json +{ + "question": "What should I do with these results?", + "group": ["admin"], + "state": "results" +} +``` +*Herramientas disponibles: reset-workflow solamente* +*Después de reset-workflow: estado → "indefinido"* + +**Ejemplo de flujo de trabajo: flujo completo:** +1. **Inicio (indefinido):** Use knowledge-query → transiciones a "análisis" +2. **Estado de análisis:** Use complex-analysis → transiciones a "resultados" +3. **Estado de resultados:** Use reset-workflow → transiciones de vuelta a "indefinido" +4. **De vuelta al inicio:** Todas las herramientas iniciales están disponibles nuevamente + +### 6. Consideraciones de seguridad + +#### 6.1 Integración de control de acceso + +**Filtrado a nivel de puerta de enlace:** +La puerta de enlace puede hacer cumplir las restricciones de grupo basadas en los permisos del usuario +Prevenir la elevación de privilegios a través de la manipulación de solicitudes +El registro de auditoría incluye los grupos de herramientas solicitados y concedidos + +**Ejemplo de lógica de la puerta de enlace:** +``` +user_permissions = get_user_permissions(request.user_id) +allowed_groups = user_permissions.tool_groups +requested_groups = request.group + +# Validate request doesn't exceed permissions +if not is_subset(requested_groups, allowed_groups): + reject_request("Insufficient permissions for requested tool groups") +``` + +#### 6.2 Auditoría y Monitoreo + +**Registro de Auditoría Mejorado:** +Registrar los grupos de herramientas solicitados y el estado inicial por solicitud. +Registrar las transiciones de estado y el uso de herramientas por pertenencia a un grupo. +Monitorear los intentos de acceso no autorizados a grupos y las transiciones de estado inválidas. +Generar alertas sobre patrones de uso de grupos inusuales o flujos de trabajo de estado sospechosos. + +### 7. Estrategia de Migración + +#### 7.1 Compatibilidad con Versiones Anteriores + +**Fase 1: Cambios Aditivos** +Agregar un campo opcional `group` a las configuraciones de las herramientas. +Agregar un campo opcional `group` al esquema de AgentRequest. +Comportamiento predeterminado: Todas las herramientas existentes pertenecen al grupo "predeterminado". +Las solicitudes existentes sin el campo de grupo utilizan el grupo "predeterminado". + +**Comportamiento Existente Preservado:** +Las herramientas sin configuración de grupo siguen funcionando (grupo predeterminado). +Las herramientas sin configuración de estado están disponibles en todos los estados. +Las solicitudes sin especificación de grupo acceden a todas las herramientas (grupo predeterminado). +Las solicitudes sin especificación de estado utilizan el estado "indefinido" (todas las herramientas disponibles). +No hay cambios que rompan la compatibilidad con las implementaciones existentes. + +### 8. Monitoreo y Observabilidad + +#### 8.1 Nuevas Métricas + +**Uso de Grupos de Herramientas:** +`agent_tool_group_requests_total` - Contador de solicitudes por grupo. +`agent_tool_group_availability` - Indicador de herramientas disponibles por grupo. +`agent_filtered_tools_count` - Histograma del número de herramientas después del filtrado por grupo + estado. + +**Métricas de Flujo de Trabajo de Estado:** +`agent_state_transitions_total` - Contador de transiciones de estado por herramienta. +`agent_workflow_duration_seconds` - Histograma del tiempo empleado en cada estado. +`agent_state_availability` - Indicador de herramientas disponibles por estado. + +**Métricas de Seguridad:** +`agent_group_access_denied_total` - Contador de accesos no autorizados a grupos. +`agent_invalid_state_transition_total` - Contador de transiciones de estado inválidas. +`agent_privilege_escalation_attempts_total` - Contador de solicitudes sospechosas. + +#### 8.2 Mejoras en el Registro + +**Registro de Solicitudes:** +```json +{ + "request_id": "req-123", + "requested_groups": ["read-only", "knowledge"], + "initial_state": "undefined", + "state_transitions": [ + {"tool": "knowledge-query", "from": "undefined", "to": "analysis", "timestamp": "2024-01-01T10:00:01Z"} + ], + "available_tools": ["knowledge-query", "text-completion"], + "filtered_by_group": ["graph-update", "admin-tool"], + "filtered_by_state": [], + "execution_time": "1.2s" +} +``` + +### 9. Estrategia de Pruebas + +#### 9.1 Pruebas Unitarias + +**Lógica de Filtrado de Herramientas:** +Cálculos de intersección de grupos de pruebas +Lógica de filtrado basada en el estado de la prueba +Verificar la asignación predeterminada de grupos y estados +Probar el comportamiento de los comodines en los grupos +Validar el manejo de grupos vacíos +Probar escenarios de filtrado combinados de grupos y estados + +**Validación de la Configuración:** +Probar la carga de herramientas con varias configuraciones de grupos y estados +Verificar la validación del esquema para especificaciones inválidas de grupos y estados +Probar la compatibilidad con versiones anteriores con las configuraciones existentes +Validar las definiciones y ciclos de transición de estados + +#### 9.2 Pruebas de Integración + +**Comportamiento del Agente:** +Verificar que los agentes solo vean las herramientas filtradas por grupo y estado +Probar la ejecución de solicitudes con varias combinaciones de grupos +Probar las transiciones de estado durante la ejecución del agente +Validar el manejo de errores cuando no hay herramientas disponibles +Probar el progreso del flujo de trabajo a través de múltiples estados + +**Pruebas de Seguridad:** +Probar la prevención de la escalada de privilegios +Verificar la precisión del registro de auditoría +Probar la integración de la puerta de enlace con los permisos de usuario + +#### 9.3 Escenarios de Extremo a Extremo + +**Uso Multi-inquilino con Flujos de Trabajo de Estado:** +``` +Scenario: Different users with different tool access and workflow states +Given: User A has "read-only" permissions, state "undefined" + And: User B has "write" permissions, state "analysis" +When: Both request knowledge operations +Then: User A gets read-only tools available in "undefined" state + And: User B gets write tools available in "analysis" state + And: State transitions are tracked per user session + And: All usage and transitions are properly audited +``` + +**Progresión del estado del flujo de trabajo:** +``` +Scenario: Complete workflow execution +Given: Request with groups ["knowledge", "compute"] and state "undefined" +When: Agent executes knowledge-query tool (transitions to "analysis") + And: Agent executes complex-analysis tool (transitions to "results") + And: Agent executes reset-workflow tool (transitions to "undefined") +Then: Each step has correctly filtered available tools + And: State transitions are logged with timestamps + And: Final state allows initial workflow to repeat +``` + +### 10. Consideraciones de rendimiento + +#### 10.1 Impacto de la carga de herramientas + +**Carga de configuración:** +Los metadatos del grupo y el estado se cargan una vez al inicio. +Sobrecarga de memoria mínima por herramienta (campos adicionales). +No hay impacto en el tiempo de inicialización de la herramienta. + +**Procesamiento de solicitudes:** +El filtrado combinado de grupo+estado se realiza una vez por solicitud. +Complejidad O(n), donde n = número de herramientas configuradas. +Las transiciones de estado agregan una sobrecarga mínima (asignación de cadenas). +Impacto insignificante para un número típico de herramientas (< 100). + +#### 10.2 Estrategias de optimización + +**Conjuntos de herramientas precalculados:** +Almacenar en caché los conjuntos de herramientas por combinación de grupo+estado. +Evitar el filtrado repetido para patrones comunes de grupo/estado. +Intercambio entre memoria y computación para combinaciones de uso frecuente. + +**Carga diferida:** +Cargar las implementaciones de las herramientas solo cuando sea necesario. +Reducir el tiempo de inicio para implementaciones con muchas herramientas. +Registro dinámico de herramientas basado en los requisitos del grupo. + +### 11. Mejoras futuras + +#### 11.1 Asignación dinámica de grupos + +**Agrupación con conocimiento del contexto:** +Asignar herramientas a grupos según el contexto de la solicitud. +Disponibilidad del grupo basada en el tiempo (solo durante el horario de atención). +Restricciones de grupo basadas en la carga (herramientas costosas durante el bajo uso). + +#### 11.2 Jerarquías de grupos + +**Estructura de grupo anidada:** +```json +{ + "knowledge": { + "read": ["knowledge-query", "entity-search"], + "write": ["graph-update", "entity-create"] + } +} +``` + +#### 11.3 Recomendaciones de herramientas + +**Sugerencias basadas en grupos:** +Sugerir grupos de herramientas óptimos para tipos de solicitud. +Aprender de los patrones de uso para mejorar las recomendaciones. +Proporcionar grupos de respaldo cuando las herramientas preferidas no están disponibles. + +### 12. Preguntas abiertas + +1. **Validación de grupos**: ¿Deben los nombres de grupo no válidos en las solicitudes causar errores graves o advertencias? + +2. **Descubrimiento de grupos**: ¿Debería el sistema proporcionar una API para listar los grupos disponibles y sus herramientas? + +3. **Grupos dinámicos**: ¿Deben los grupos ser configurables en tiempo de ejecución o solo al inicio? + +4. **Herencia de grupos**: ¿Deben las herramientas heredar grupos de sus categorías o implementaciones principales? + +5. **Monitoreo del rendimiento**: ¿Qué métricas adicionales son necesarias para realizar un seguimiento eficaz del uso de herramientas basado en grupos? + +### 13. Conclusión + +El sistema de grupos de herramientas proporciona: + +**Seguridad**: Control de acceso granular sobre las capacidades del agente. +**Rendimiento**: Reducción de la sobrecarga de carga y selección de herramientas. +**Flexibilidad**: Clasificación de herramientas multidimensional. +**Compatibilidad**: Integración perfecta con arquitecturas de agentes existentes. + +Este sistema permite que las implementaciones de TrustGraph gestionen mejor el acceso a las herramientas, mejoren los límites de seguridad y optimicen el uso de recursos, al tiempo que mantiene la compatibilidad con versiones anteriores con las configuraciones y solicitudes existentes. diff --git a/docs/tech-specs/tool-group.he.md b/docs/tech-specs/tool-group.he.md new file mode 100644 index 00000000..b01ade78 --- /dev/null +++ b/docs/tech-specs/tool-group.he.md @@ -0,0 +1,491 @@ +# קבוצת כלים עבור TrustGraph +## מפרט טכני גרסה 1.0 + +### תקציר מנהלים + +מפרט זה מגדיר מערכת לקבוצות כלים עבור סוכני TrustGraph, המאפשרת שליטה מדויקת על אילו כלים זמינים עבור בקשות ספציפיות. המערכת מציגה סינון כלים מבוסס קבוצות באמצעות תצורה ומפרט ברמת הבקשה, ומאפשרת גבולות אבטחה טובים יותר, ניהול משאבים וחלוקת פונקציונליות של יכולות הסוכנים. + +### 1. סקירה כללית + +#### 1.1 הצגת הבעיה + +כיום, לסוכני TrustGraph יש גישה לכל הכלים המוגדרים, ללא קשר להקשר הבקשה או לדרישות האבטחה. זה יוצר מספר אתגרים: + +**סיכון אבטחה**: כלים רגישים (לדוגמה, שינוי נתונים) זמינים גם עבור שאילתות לקריאה בלבד. +**בזבוז משאבים**: כלים מורכבים נטענים גם כאשר שאילתות פשוטות אינן דורשים אותם. +**בלבול פונקציונלי**: סוכנים עשויים לבחור כלים לא מתאימים כאשר קיימות חלופות פשוטות יותר. +**בידוד מרובה דיירים**: קבוצות משתמשים שונות צריכות גישה לקבוצות כלים שונות. + +#### 1.2 סקירה כללית של הפתרון + +מערכת קבוצות הכלים מציגה: + +1. **סיווג קבוצות**: כלים מסומנים עם שייכות לקבוצות במהלך התצורה. +2. **סינון ברמת הבקשה**: בקשת סוכן מציינת אילו קבוצות כלים מותרות. +3. **אכיפה בזמן ריצה**: לסוכנים יש גישה רק לכלים התואמים לקבוצות המבוקשות. +4. **קיבוץ גמיש**: כלים יכולים להיות שייכים למספר קבוצות עבור תרחישים מורכבים. + +### 2. שינויים בסכימה + +#### 2.1 שיפור סכימת תצורת הכלים + +תצורת הכלים הקיימת משופרת עם שדה `group`: + +**לפני:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph" +} +``` + +**אחרי:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"] +} +``` + +**מפרט שדה קבוצה:** +`group`: Array(String) - רשימה של קבוצות שאליהן הכלי הזה שייך +**אופציונלי**: כלים ללא שדה קבוצה שייכים לקבוצה "ברירת מחדל" +**חברות מרובות**: כלים יכולים להיות שייכים למספר קבוצות +**רגישות לאותיות**: שמות הקבוצות חייבים להיות התאמה מדויקת של מחרוזות + +#### 2.1.2 שיפור מעבר מצבים של כלי + +כלים יכולים לציין אופציונלית מעברי מצבים וזמינות מבוססת מצב: + +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"], + "state": "analysis", + "available_in_states": ["undefined", "research"] +} +``` + +**מפרט שדה מצב:** +`state`: מחרוזת - **אופציונלי** - המצב שאליו יש לעבור לאחר ביצוע מוצלח של הכלי +`available_in_states`: מערך(מחרוזת) - **אופציונלי** - מצבים שבהם הכלי זמין +**התנהגות ברירת מחדל**: כלים ללא `available_in_states` זמינים בכל המצבים +**מעבר מצב**: מתרחש רק לאחר ביצוע מוצלח של הכלי + +#### 2.2 שיפור סכימת AgentRequest + +הסכימה `AgentRequest` ב-`trustgraph-base/trustgraph/schema/services/agent.py` משופרת: + +**AgentRequest נוכחי:** +`question`: מחרוזת - שאילתת משתמש +`plan`: מחרוזת - תוכנית ביצוע (ניתן להסיר) +`state`: מחרוזת - מצב סוכן +`history`: מערך(AgentStep) - היסטוריית ביצוע + +**AgentRequest משופר:** +`question`: מחרוזת - שאילתת משתמש +`state`: מחרוזת - מצב ביצוע סוכן (כעת בשימוש פעיל לסינון כלים) +`history`: מערך(AgentStep) - היסטוריית ביצוע +`group`: מערך(מחרוזת) - **חדש** - קבוצות כלים מותרות עבור בקשה זו + +**שינויים בסכימה:** +**הוסר**: השדה `plan` אינו נחוץ יותר וניתן להסירו (היה מיועד במקור למפרט כלים) +**נוסף**: השדה `group` למפרט קבוצות כלים +**שופר**: השדה `state` שולט כעת בזמינות הכלים במהלך הביצוע + +**התנהגויות של שדות:** + +**קבוצת שדות:** +**אופציונלי**: אם לא צוין, ברירת המחדל היא ["default"] +**חיתוך**: זמינים רק כלים התואמים לפחות לקבוצה אחת שצוינה +**מערך ריק**: אין כלים זמינים (הסוכן יכול להשתמש רק בנימוקים פנימיים) +**תו גלובלי**: קבוצה מיוחדת "*" מעניקה גישה לכל הכלים + +**שדה מצב:** +**אופציונלי**: אם לא צוין, ברירת המחדל היא "לא מוגדר" +**סינון מבוסס מצב**: זכאים רק כלים הזמינים במצב הנוכחי +**מצב ברירת מחדל**: מצב "לא מוגדר" מאפשר לכל הכלים (בהתאם לסינון קבוצות) +**מעברי מצב**: כלים יכולים לשנות מצב לאחר ביצוע מוצלח + +### 3. דוגמאות לקבוצות מותאמות אישית + +ארגונים יכולים להגדיר קבוצות ספציפיות לתחום: + +```json +{ + "financial-tools": ["stock-query", "portfolio-analysis"], + "medical-tools": ["diagnosis-assist", "drug-interaction"], + "legal-tools": ["contract-analysis", "case-search"] +} +``` + +### 4. פרטי יישום + +#### 4.1 טעינת כלים וסינון + +**שלב התצורה:** +1. כל הכלים נטענים מקובץ התצורה עם ההקצאות שלהם לקבוצות. +2. כלים שאין להם קבוצות מוגדרות מוקצים לקבוצה "ברירת מחדל". +3. חברות בקבוצות מאומתות ונשמרות במאגר הכלים. + +**שלב עיבוד בקשות:** +1. בקשת סוכן מגיעה עם ציון קבוצה אופציונלי. +2. הסוכן מסנן את הכלים הזמינים בהתבסס על חיתוך קבוצות. +3. רק כלים תואמים מועברים להקשר הביצוע של הסוכן. +4. הסוכן פועל עם סט הכלים המסונן לאורך כל מחזור החיים של הבקשה. + +#### 4.2 לוגיקת סינון כלים + +**סינון משולב של קבוצות ומצבים:** + +``` +For each configured tool: + tool_groups = tool.group || ["default"] + tool_states = tool.available_in_states || ["*"] // Available in all states + +For each request: + requested_groups = request.group || ["default"] + current_state = request.state || "undefined" + +Tool is available if: + // Group filtering + (intersection(tool_groups, requested_groups) is not empty OR "*" in requested_groups) + AND + // State filtering + (current_state in tool_states OR "*" in tool_states) +``` + +**לוגיקת מעבר מצבים:** + +``` +After successful tool execution: + if tool.state is defined: + next_request.state = tool.state + else: + next_request.state = current_request.state // No change +``` + +#### 4.3 נקודות אינטגרציה של סוכן + +**סוכן ReAct:** +סינון כלים מתבצע ב-agent_manager.py במהלך יצירת רישום הכלים +רשימת הכלים הזמינים מסוננת לפי קבוצה ומצב לפני יצירת תוכנית +מעברי מצבים מעדכנים את השדה AgentRequest.state לאחר ביצוע מוצלח של כלי +האיטרציה הבאה משתמשת במצב המעודכן לסינון כלים + +**סוכן מבוסס ביטחון:** +סינון כלים מתבצע ב-planner.py במהלך יצירת תוכנית +אימות ExecutionStep מבטיח שרק כלים מתאימים לקבוצה ולמצב משמשים +בקר הזרימה (Flow controller) מאכף את זמינות הכלים בזמן ריצה +מעברי מצבים מנוהלים על ידי בקר הזרימה בין שלבים + +### 5. דוגמאות תצורה + +#### 5.1 תצורת כלים עם קבוצות ומצבים + +```yaml +tool: + knowledge-query: + type: knowledge-query + name: "Knowledge Graph Query" + description: "Query the knowledge graph for entities and relationships" + group: ["read-only", "knowledge", "basic"] + state: "analysis" + available_in_states: ["undefined", "research"] + + graph-update: + type: graph-update + name: "Graph Update" + description: "Add or modify entities in the knowledge graph" + group: ["write", "knowledge", "admin"] + available_in_states: ["analysis", "modification"] + + text-completion: + type: text-completion + name: "Text Completion" + description: "Generate text using language models" + group: ["read-only", "text", "basic"] + state: "undefined" + # No available_in_states = available in all states + + complex-analysis: + type: mcp-tool + name: "Complex Analysis Tool" + description: "Perform complex data analysis" + group: ["advanced", "compute", "expensive"] + state: "results" + available_in_states: ["analysis"] + mcp_tool_id: "analysis-server" + + reset-workflow: + type: mcp-tool + name: "Reset Workflow" + description: "Reset to initial state" + group: ["admin"] + state: "undefined" + available_in_states: ["analysis", "results"] +``` + +#### 5.2 דוגמאות לבקשות עם תהליכי עבודה מוגדרים מראש + +**בקשה ראשונית למחקר:** +```json +{ + "question": "What entities are connected to Company X?", + "group": ["read-only", "knowledge"], + "state": "undefined" +} +``` +*כלים זמינים: שאילתת ידע, השלמת טקסט* +*לאחר שאילתת ידע: מצב → "ניתוח"* + +**שלב הניתוח:** +```json +{ + "question": "Continue analysis based on previous results", + "group": ["advanced", "compute", "write"], + "state": "analysis" +} +``` +*כלים זמינים: complex-analysis, graph-update, reset-workflow* +*לאחר complex-analysis: מצב → "תוצאות"* + +**שלב התוצאות:** +```json +{ + "question": "What should I do with these results?", + "group": ["admin"], + "state": "results" +} +``` +*כלים זמינים: reset-workflow בלבד* +*לאחר הפעלת reset-workflow: מצב → "לא מוגדר"* + +**דוגמה לזרימת עבודה - זרימה מלאה:** +1. **התחלה (לא מוגדר):** השתמש ב-knowledge-query → מעבר למצב "ניתוח" +2. **מצב ניתוח:** השתמש ב-complex-analysis → מעבר למצב "תוצאות" +3. **מצב תוצאות:** השתמש ב-reset-workflow → חזרה למצב "לא מוגדר" +4. **חזרה להתחלה:** כל הכלים הזמינים זמינים שוב + +### 6. שיקולי אבטחה + +#### 6.1 שילוב בקרת גישה + +**סינון ברמת השער (Gateway):** +השער יכול לאכוף הגבלות קבוצתיות בהתבסס על הרשאות משתמש +מניעת העלאת הרשאות באמצעות מניפולציה של בקשות +רישום ביקורת כולל קבוצות כלים מבוקשות ומוענקות + +**לוגיקה לדוגמה של השער:** +``` +user_permissions = get_user_permissions(request.user_id) +allowed_groups = user_permissions.tool_groups +requested_groups = request.group + +# Validate request doesn't exceed permissions +if not is_subset(requested_groups, allowed_groups): + reject_request("Insufficient permissions for requested tool groups") +``` + +#### 6.2 ביקורת וניטור + +**רשומות ביקורת משופרות:** +רישום קבוצות כלים מבוקשות ומצב התחלתי עבור כל בקשה +מעקב אחר מעברי מצבים ושימוש בכלים לפי חברות בקבוצה +ניטור ניסיונות גישה לא מורשים לקבוצות ושינויי מצב לא חוקיים +התראה על דפוסי שימוש חריגים בקבוצות או זרימות עבודה חשודות במצב + +### 7. אסטרטגיית מעבר + +#### 7.1 תאימות לאחור + +**שלב 1: שינויים מצטברים** +הוספת שדה אופציונלי `group` לתצורות כלים +הוספת שדה אופציונלי `group` לתבנית AgentRequest +התנהגות ברירת מחדל: כל הכלים הקיימים שייכים לקבוצה "ברירת מחדל" +בקשות קיימות ללא שדה קבוצה משתמשות בקבוצה "ברירת מחדל" + +**התנהגות קיימת נשמרת:** +כלים ללא תצורת קבוצה ממשיכים לעבוד (קבוצת ברירת מחדל) +כלים ללא תצורת מצב זמינים בכל המצבים +בקשות ללא ציון קבוצה ניגשות לכל הכלים (קבוצת ברירת מחדל) +בקשות ללא ציון מצב משתמשות במצב "לא מוגדר" (כל הכלים זמינים) +אין שינויים משמעותיים לפריסות קיימות + +### 8. ניטור וניתוח + +#### 8.1 מדדים חדשים + +**שימוש בקבוצות כלים:** +`agent_tool_group_requests_total` - מונה של בקשות לפי קבוצה +`agent_tool_group_availability` - מדד של כלים זמינים לכל קבוצה +`agent_filtered_tools_count` - היסטוגרמה של מספר כלים לאחר סינון לפי קבוצה + מצב + +**מדדי זרימת עבודה של מצבים:** +`agent_state_transitions_total` - מונה של מעברי מצבים לפי כלי +`agent_workflow_duration_seconds` - היסטוגרמה של זמן שהייה בכל מצב +`agent_state_availability` - מדד של כלים זמינים לכל מצב + +**מדדי אבטחה:** +`agent_group_access_denied_total` - מונה של גישה לא מורשית לקבוצה +`agent_invalid_state_transition_total` - מונה של מעברי מצב לא חוקיים +`agent_privilege_escalation_attempts_total` - מונה של בקשות חשודות + +#### 8.2 שיפורים ברישום + +**רישום בקשות:** +```json +{ + "request_id": "req-123", + "requested_groups": ["read-only", "knowledge"], + "initial_state": "undefined", + "state_transitions": [ + {"tool": "knowledge-query", "from": "undefined", "to": "analysis", "timestamp": "2024-01-01T10:00:01Z"} + ], + "available_tools": ["knowledge-query", "text-completion"], + "filtered_by_group": ["graph-update", "admin-tool"], + "filtered_by_state": [], + "execution_time": "1.2s" +} +``` + +### 9. אסטרטגיית בדיקות + +#### 9.1 בדיקות יחידה + +**לוגיקת סינון כלים:** +חישובים של חיתוך קבוצות בדיקה +לוגיקת סינון מבוססת מצבים +אימות הקצאה ברירת מחדל של קבוצות ומצבים +בדיקת התנהגות של קבוצות עם תווים מיוחדים (wildcard) +אימות טיפול בקבוצות ריקות +בדיקת תרחישים משולבים של סינון קבוצות + מצבים + +**אימות תצורה:** +בדיקת טעינת כלים עם תצורות שונות של קבוצות ומצבים +אימות של תקינות הסכימה עבור מפרטי קבוצות ומצבים לא חוקיים +בדיקת תאימות לאחור עם תצורות קיימות +אימות של הגדרות מעברים בין מצבים ומחזורים + +#### 9.2 בדיקות אינטגרציה + +**התנהגות של סוכן (Agent):** +אימות שהסוכן רואה רק כלים שעברו סינון לפי קבוצה + מצב +בדיקת ביצוע בקשות עם שילובים שונים של קבוצות +בדיקת מעברים בין מצבים במהלך ביצוע הסוכן +אימות של טיפול בשגיאות כאשר אין כלים זמינים +בדיקת התקדמות של זרימת עבודה דרך מצבים שונים + +**בדיקות אבטחה:** +בדיקת מניעת העלאת הרשאות +אימות של דיוק רישום ביקורת (audit trail) +בדיקת שילוב של שער (gateway) עם הרשאות משתמש + +#### 9.3 תרחישים מקצה לקצה + +**שימוש מרובה דיירים (Multi-tenant) עם זרימות עבודה מבוססות מצבים:** +``` +Scenario: Different users with different tool access and workflow states +Given: User A has "read-only" permissions, state "undefined" + And: User B has "write" permissions, state "analysis" +When: Both request knowledge operations +Then: User A gets read-only tools available in "undefined" state + And: User B gets write tools available in "analysis" state + And: State transitions are tracked per user session + And: All usage and transitions are properly audited +``` + +**התקדמות מצב העבודה:** +``` +Scenario: Complete workflow execution +Given: Request with groups ["knowledge", "compute"] and state "undefined" +When: Agent executes knowledge-query tool (transitions to "analysis") + And: Agent executes complex-analysis tool (transitions to "results") + And: Agent executes reset-workflow tool (transitions to "undefined") +Then: Each step has correctly filtered available tools + And: State transitions are logged with timestamps + And: Final state allows initial workflow to repeat +``` + +### 10. שיקולי ביצועים + +#### 10.1 השפעת טעינת כלים + +**טעינת תצורה:** +מטא-נתונים של קבוצה ומצב נטענים פעם אחת בעת ההפעלה +תקורה מינימלית של זיכרון לכל כלי (שדות נוספים) +אין השפעה על זמן אתחול הכלי + +**עיבוד בקשות:** +סינון משולב של קבוצה+מצב מתבצע פעם אחת לכל בקשה +מורכבות O(n) כאשר n = מספר הכלים המוגדרים +מעברים של מצבים מוסיפים תקורה מינימלית (הקצאת מחרוזות) +השפעה זניחה עבור מספר טיפוסי של כלים (< 100) + +#### 10.2 אסטרטגיות אופטימיזציה + +**סטים של כלים מחושבים מראש:** +שמירת סטים של כלים לפי שילוב של קבוצה+מצב +הימנעות מסינון חוזר עבור דפוסי קבוצה/מצב נפוצים +פשרה בין זיכרון לחישוב עבור שילובים בשימוש תכוף + +**טעינה עצלה:** +טעינת יישומי כלים רק כאשר נדרש +הפחתת זמן אתחול עבור פריסות עם מספר רב של כלים +רישום דינמי של כלים בהתאם לדרישות הקבוצה + +### 11. שיפורים עתידיים + +#### 11.1 הקצאת קבוצות דינמית + +**קיבוץ מודע להקשר:** +הקצאת כלים לקבוצות בהתבסס על הקשר הבקשה +זמינות קבוצה מבוססת זמן (שעות עסקים בלבד) +הגבלות קבוצה מבוססות עומס (כלים יקרים בזמן שימוש נמוך) + +#### 11.2 היררכיות קבוצות + +**מבנה קבוצות מקונן:** +```json +{ + "knowledge": { + "read": ["knowledge-query", "entity-search"], + "write": ["graph-update", "entity-create"] + } +} +``` + +#### 11.3 המלצות כלים + +**הצעות מבוססות קבוצות:** +הצעת קבוצות כלים אופטימליות עבור סוגי בקשות +למידה מדפוסי שימוש לשיפור ההמלצות +מתן קבוצות חלופיות כאשר הכלים המועדפים אינם זמינים + +### 12. שאלות פתוחות + +1. **אימות קבוצות**: האם שמות קבוצות לא חוקיים בבקשות צריכים לגרום לכישלונות קשים או אזהרות? + +2. **גילוי קבוצות**: האם המערכת צריכה לספק API לרשימת קבוצות זמינות והכלים שלהן? + +3. **קבוצות דינמיות**: האם הקבוצות צריכות להיות ניתנות להגדרה בזמן ריצה או רק בזמן ההתחלה? + +4. **ירושה של קבוצות**: האם כלים צריכים לרשת קבוצות מהקטגוריות או המימושים הראשיים שלהם? + +5. **ניטור ביצועים**: אילו מדדים נוספים נחוצים למעקב יעיל אחר שימוש בכלים מבוססי קבוצות? + +### 13. סיכום + +מערכת קבוצות הכלים מספקת: + +**אבטחה**: בקרת גישה מפורטת על יכולות הסוכן +**ביצועים**: הפחתת עומס טעינה ובחירת כלים +**גמישות**: סיווג רב-ממדי של כלים +**תאימות**: שילוב חלק עם ארכיטקטורות סוכן קיימות + +מערכת זו מאפשרת לפריסות TrustGraph לנהל טוב יותר את גישת הכלים, לשפר את גבולות האבטחה ולייעל את השימוש במשאבים תוך שמירה על תאימות מלאה לאחור עם תצורות ובקשות קיימות. diff --git a/docs/tech-specs/tool-group.hi.md b/docs/tech-specs/tool-group.hi.md new file mode 100644 index 00000000..688fc267 --- /dev/null +++ b/docs/tech-specs/tool-group.hi.md @@ -0,0 +1,491 @@ +# ट्रस्टग्राफ टूल ग्रुप सिस्टम +## तकनीकी विनिर्देश v1.0 + +### कार्यकारी सारांश + +यह विनिर्देश ट्रस्टग्राफ एजेंटों के लिए एक टूल ग्रुपिंग सिस्टम को परिभाषित करता है जो विशिष्ट अनुरोधों के लिए कौन से टूल उपलब्ध हैं, इस पर बारीक नियंत्रण की अनुमति देता है। यह सिस्टम कॉन्फ़िगरेशन और अनुरोध-स्तरीय विनिर्देश के माध्यम से समूह-आधारित टूल फ़िल्टरिंग पेश करता है, जो एजेंट क्षमताओं के बेहतर सुरक्षा सीमाओं, संसाधन प्रबंधन और कार्यात्मक विभाजन को सक्षम करता है। + +### 1. अवलोकन + +#### 1.1 समस्या विवरण + +वर्तमान में, ट्रस्टग्राफ एजेंटों के पास अनुरोध संदर्भ या सुरक्षा आवश्यकताओं की परवाह किए बिना, सभी कॉन्फ़िगर किए गए टूल तक पहुंच होती है। इससे कई चुनौतियाँ उत्पन्न होती हैं: + +**सुरक्षा जोखिम**: संवेदनशील टूल (जैसे, डेटा संशोधन) रीड-ओनली प्रश्नों के लिए भी उपलब्ध हैं +**संसाधन बर्बादी**: जटिल टूल लोड किए जाते हैं, भले ही सरल प्रश्नों के लिए उनकी आवश्यकता न हो +**कार्यात्मक भ्रम**: एजेंट उपयुक्त टूल का चयन कर सकते हैं जब सरल विकल्प मौजूद हों +**मल्टी-टेनेन्ट अलगाव**: विभिन्न उपयोगकर्ता समूहों को अलग-अलग टूल सेट तक पहुंचने की आवश्यकता होती है + +#### 1.2 समाधान अवलोकन + +टूल ग्रुप सिस्टम निम्नलिखित पेश करता है: + +1. **समूह वर्गीकरण**: टूल को कॉन्फ़िगरेशन के दौरान समूह सदस्यता के साथ टैग किया जाता है +2. **अनुरोध-स्तरीय फ़िल्टरिंग**: AgentRequest निर्दिष्ट करता है कि कौन से टूल समूह अनुमत हैं +3. **रनटाइम प्रवर्तन**: एजेंटों के पास केवल अनुरोधित समूहों से मेल खाने वाले टूल तक पहुंच होती है +4. **लचीला समूहीकरण**: जटिल परिदृश्यों के लिए टूल कई समूहों से संबंधित हो सकते हैं + +### 2. स्कीमा परिवर्तन + +#### 2.1 टूल कॉन्फ़िगरेशन स्कीमा संवर्धन + +मौजूदा टूल कॉन्फ़िगरेशन को एक `group` फ़ील्ड के साथ बढ़ाया गया है: + +**पहले:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph" +} +``` + +**इसके बाद:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"] +} +``` + +**समूह क्षेत्र विनिर्देश:** +`group`: Array(String) - यह सूची उन समूहों की है जिनसे यह उपकरण संबंधित है। +**वैकल्पिक**: जिन उपकरणों में समूह क्षेत्र नहीं है, वे "डिफ़ॉल्ट" समूह से संबंधित होते हैं। +**बहु-सदस्यता**: उपकरण कई समूहों से संबंधित हो सकते हैं। +**केस-संवेदी**: समूह नाम सटीक स्ट्रिंग मिलान होते हैं। + +#### 2.1.2 उपकरण स्थिति परिवर्तन संवर्धन + +उपकरण वैकल्पिक रूप से स्थिति परिवर्तनों और स्थिति-आधारित उपलब्धता को निर्दिष्ट कर सकते हैं: + +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"], + "state": "analysis", + "available_in_states": ["undefined", "research"] +} +``` + +**राज्य क्षेत्र विनिर्देश:** +`state`: स्ट्रिंग - **वैकल्पिक** - सफल टूल निष्पादन के बाद जाने वाला राज्य +`available_in_states`: Array(String) - **वैकल्पिक** - उन राज्यों में जहां यह टूल उपलब्ध है +**डिफ़ॉल्ट व्यवहार:** `available_in_states` के बिना टूल सभी राज्यों में उपलब्ध होते हैं +**राज्य परिवर्तन:** केवल सफल टूल निष्पादन के बाद होता है + +#### 2.2 AgentRequest स्कीमा में सुधार + +`trustgraph-base/trustgraph/schema/services/agent.py` में `AgentRequest` स्कीमा में सुधार किया गया है: + +**वर्तमान AgentRequest:** +`question`: स्ट्रिंग - उपयोगकर्ता प्रश्न +`plan`: स्ट्रिंग - निष्पादन योजना (हटाया जा सकता है) +`state`: स्ट्रिंग - एजेंट राज्य +`history`: Array(AgentStep) - निष्पादन इतिहास + +**सुधारे गए AgentRequest:** +`question`: स्ट्रिंग - उपयोगकर्ता प्रश्न +`state`: स्ट्रिंग - एजेंट निष्पादन स्थिति (अब सक्रिय रूप से टूल फ़िल्टरिंग के लिए उपयोग किया जाता है) +`history`: Array(AgentStep) - निष्पादन इतिहास +`group`: Array(String) - **नया** - इस अनुरोध के लिए अनुमत टूल समूह + +**स्कीमा परिवर्तन:** +**हटाया गया:** `plan` फ़ील्ड अब आवश्यक नहीं है और इसे हटाया जा सकता है (मूल रूप से टूल विनिर्देश के लिए अभिप्रेत था) +**जोड़ा गया:** टूल समूह विनिर्देश के लिए `group` फ़ील्ड +**सुधारा गया:** `state` फ़ील्ड अब निष्पादन के दौरान टूल उपलब्धता को नियंत्रित करता है + +**फ़ील्ड व्यवहार:** + +**समूह फ़ील्ड:** +**वैकल्पिक:** यदि निर्दिष्ट नहीं है, तो डिफ़ॉल्ट रूप से ["default"] होता है +**प्रतिच्छेदन:** केवल वे टूल जो कम से कम एक निर्दिष्ट समूह से मेल खाते हैं, वे उपलब्ध हैं +**खाली सरणी:** कोई टूल उपलब्ध नहीं है (एजेंट केवल आंतरिक तर्क का उपयोग कर सकता है) +**वाइल्डकार्ड:** विशेष समूह "*" सभी टूल तक पहुंच प्रदान करता है + +**राज्य फ़ील्ड:** +**वैकल्पिक:** यदि निर्दिष्ट नहीं है, तो डिफ़ॉल्ट रूप से "अपरिभाषित" होता है +**राज्य-आधारित फ़िल्टरिंग:** केवल वर्तमान राज्य में उपलब्ध टूल ही पात्र हैं +**डिफ़ॉल्ट राज्य:** "अपरिभाषित" राज्य सभी टूल की अनुमति देता है (समूह फ़िल्टरिंग के अधीन) +**राज्य परिवर्तन:** सफल निष्पादन के बाद टूल अपनी स्थिति बदल सकते हैं + +### 3. कस्टम समूह उदाहरण + +संगठन डोमेन-विशिष्ट समूह परिभाषित कर सकते हैं: + +```json +{ + "financial-tools": ["stock-query", "portfolio-analysis"], + "medical-tools": ["diagnosis-assist", "drug-interaction"], + "legal-tools": ["contract-analysis", "case-search"] +} +``` + +### 4. कार्यान्वयन विवरण + +#### 4.1 टूल लोडिंग और फ़िल्टरिंग + +**कॉन्फ़िगरेशन चरण:** +1. सभी टूल अपने समूह असाइनमेंट के साथ कॉन्फ़िगरेशन से लोड किए जाते हैं। +2. स्पष्ट समूहों के बिना टूल को "डिफ़ॉल्ट" समूह में असाइन किया जाता है। +3. समूह सदस्यता को मान्य किया जाता है और टूल रजिस्ट्री में संग्रहीत किया जाता है। + +**अनुरोध प्रसंस्करण चरण:** +1. एजेंट अनुरोध वैकल्पिक समूह विनिर्देश के साथ आता है। +2. एजेंट उपलब्ध टूल को समूह प्रतिच्छेदन के आधार पर फ़िल्टर करता है। +3. केवल मिलान करने वाले टूल को एजेंट निष्पादन संदर्भ में पास किया जाता है। +4. एजेंट अनुरोध जीवनचक्र के दौरान फ़िल्टर किए गए टूल सेट के साथ काम करता है। + +#### 4.2 टूल फ़िल्टरिंग लॉजिक + +**संयुक्त समूह और स्थिति फ़िल्टरिंग:** + +``` +For each configured tool: + tool_groups = tool.group || ["default"] + tool_states = tool.available_in_states || ["*"] // Available in all states + +For each request: + requested_groups = request.group || ["default"] + current_state = request.state || "undefined" + +Tool is available if: + // Group filtering + (intersection(tool_groups, requested_groups) is not empty OR "*" in requested_groups) + AND + // State filtering + (current_state in tool_states OR "*" in tool_states) +``` + +**राज्य परिवर्तन तर्क:** + +``` +After successful tool execution: + if tool.state is defined: + next_request.state = tool.state + else: + next_request.state = current_request.state // No change +``` + +#### 4.3 एजेंट एकीकरण बिंदु + +**ReAct एजेंट:** +टूल फ़िल्टरिंग एजेंट_मैनेजर.py में टूल रजिस्ट्री निर्माण के दौरान होती है। +उपलब्ध टूल की सूची को योजना निर्माण से पहले समूह और स्थिति दोनों द्वारा फ़िल्टर किया जाता है। +स्थिति परिवर्तन सफल टूल निष्पादन के बाद AgentRequest.state फ़ील्ड को अपडेट करते हैं। +अगले पुनरावृत्ति में टूल फ़िल्टरिंग के लिए अपडेट की गई स्थिति का उपयोग किया जाता है। + +**विश्वास-आधारित एजेंट:** +टूल फ़िल्टरिंग योजना निर्माण के दौरान प्लानर.py में होती है। +ExecutionStep सत्यापन यह सुनिश्चित करता है कि केवल समूह+स्थिति के लिए योग्य टूल का उपयोग किया जाए। +फ्लो कंट्रोलर रनटाइम पर टूल की उपलब्धता को लागू करता है। +चरणों के बीच फ्लो कंट्रोलर द्वारा स्थिति परिवर्तन प्रबंधित किए जाते हैं। + +### 5. कॉन्फ़िगरेशन उदाहरण + +#### 5.1 समूहों और स्थितियों के साथ टूल कॉन्फ़िगरेशन + +```yaml +tool: + knowledge-query: + type: knowledge-query + name: "Knowledge Graph Query" + description: "Query the knowledge graph for entities and relationships" + group: ["read-only", "knowledge", "basic"] + state: "analysis" + available_in_states: ["undefined", "research"] + + graph-update: + type: graph-update + name: "Graph Update" + description: "Add or modify entities in the knowledge graph" + group: ["write", "knowledge", "admin"] + available_in_states: ["analysis", "modification"] + + text-completion: + type: text-completion + name: "Text Completion" + description: "Generate text using language models" + group: ["read-only", "text", "basic"] + state: "undefined" + # No available_in_states = available in all states + + complex-analysis: + type: mcp-tool + name: "Complex Analysis Tool" + description: "Perform complex data analysis" + group: ["advanced", "compute", "expensive"] + state: "results" + available_in_states: ["analysis"] + mcp_tool_id: "analysis-server" + + reset-workflow: + type: mcp-tool + name: "Reset Workflow" + description: "Reset to initial state" + group: ["admin"] + state: "undefined" + available_in_states: ["analysis", "results"] +``` + +#### 5.2 अनुरोध के उदाहरण राज्य वर्कफ़्लो के साथ + +**प्रारंभिक अनुसंधान अनुरोध:** +```json +{ + "question": "What entities are connected to Company X?", + "group": ["read-only", "knowledge"], + "state": "undefined" +} +``` +*उपलब्ध उपकरण: ज्ञान-पूछताछ, पाठ-पूर्णता* +*ज्ञान-पूछताछ के बाद: अवस्था → "विश्लेषण"* + +**विश्लेषण चरण:** +```json +{ + "question": "Continue analysis based on previous results", + "group": ["advanced", "compute", "write"], + "state": "analysis" +} +``` +*उपलब्ध उपकरण: जटिल-विश्लेषण, ग्राफ-अपडेट, रीसेट-वर्कफ़्लो* +*जटिल-विश्लेषण के बाद: अवस्था → "परिणाम"* + +**परिणाम चरण:** +```json +{ + "question": "What should I do with these results?", + "group": ["admin"], + "state": "results" +} +``` +*उपलब्ध उपकरण: केवल reset-workflow* +*reset-workflow के बाद: स्थिति → "अपरिभाषित"* + +**वर्कफ़्लो उदाहरण - पूर्ण प्रवाह:** +1. **शुरुआत (अपरिभाषित):** ज्ञान-पूछताछ का उपयोग करें → "विश्लेषण" में संक्रमण +2. **विश्लेषण अवस्था:** जटिल-विश्लेषण का उपयोग करें → "परिणाम" में संक्रमण +3. **परिणाम अवस्था:** reset-workflow का उपयोग करें → "अपरिभाषित" में वापस संक्रमण +4. **शुरुआत में वापस:** सभी प्रारंभिक उपकरण फिर से उपलब्ध + +### 6. सुरक्षा संबंधी विचार + +#### 6.1 एक्सेस नियंत्रण एकीकरण + +**गेटवे-स्तरीय फ़िल्टरिंग:** +गेटवे उपयोगकर्ता अनुमतियों के आधार पर समूह प्रतिबंधों को लागू कर सकता है +अनुरोध हेरफेर के माध्यम से विशेषाधिकारों को बढ़ाने से रोकें +ऑडिट ट्रेल में अनुरोधित और अनुमत टूल समूह शामिल हैं + +**उदाहरण गेटवे तर्क:** +``` +user_permissions = get_user_permissions(request.user_id) +allowed_groups = user_permissions.tool_groups +requested_groups = request.group + +# Validate request doesn't exceed permissions +if not is_subset(requested_groups, allowed_groups): + reject_request("Insufficient permissions for requested tool groups") +``` + +#### 6.2 ऑडिट और निगरानी + +**बेहतर ऑडिट ट्रेल:** +प्रत्येक अनुरोध के लिए अनुरोधित टूल समूहों और प्रारंभिक स्थिति को लॉग करें। +समूह सदस्यता द्वारा स्थिति परिवर्तन और टूल उपयोग को ट्रैक करें। +अनधिकृत समूह एक्सेस प्रयासों और अमान्य स्थिति परिवर्तनों की निगरानी करें। +असामान्य समूह उपयोग पैटर्न या संदिग्ध स्थिति वर्कफ़्लो पर अलर्ट जारी करें। + +### 7. माइग्रेशन रणनीति + +#### 7.1 पिछड़ा संगतता + +**चरण 1: अतिरिक्त परिवर्तन** +टूल कॉन्फ़िगरेशन में वैकल्पिक `group` फ़ील्ड जोड़ें। +AgentRequest स्कीमा में वैकल्पिक `group` फ़ील्ड जोड़ें। +डिफ़ॉल्ट व्यवहार: सभी मौजूदा टूल "डिफ़ॉल्ट" समूह से संबंधित हैं। +समूह फ़ील्ड के बिना मौजूदा अनुरोध "डिफ़ॉल्ट" समूह का उपयोग करते हैं। + +**मौजूदा व्यवहार संरक्षित:** +समूह कॉन्फ़िगरेशन के बिना टूल काम करना जारी रखते हैं (डिफ़ॉल्ट समूह)। +स्थिति कॉन्फ़िगरेशन के बिना टूल सभी स्थितियों में उपलब्ध हैं। +समूह विनिर्देश के बिना अनुरोध सभी टूल तक पहुंचते हैं (डिफ़ॉल्ट समूह)। +स्थिति विनिर्देश के बिना अनुरोध "अपरिभाषित" स्थिति का उपयोग करते हैं (सभी टूल उपलब्ध हैं)। +मौजूदा परिनियोजन में कोई ब्रेकिंग परिवर्तन नहीं। + +### 8. निगरानी और अवलोकन + +#### 8.1 नए मेट्रिक्स + +**टूल समूह उपयोग:** +`agent_tool_group_requests_total` - समूह द्वारा अनुरोधों की संख्या। +`agent_tool_group_availability` - प्रति समूह उपलब्ध टूल का गेज। +`agent_filtered_tools_count` - समूह+स्थिति फ़िल्टरिंग के बाद टूल गणना का हिस्टोग्राम। + +**स्थिति वर्कफ़्लो मेट्रिक्स:** +`agent_state_transitions_total` - टूल द्वारा स्थिति परिवर्तनों की संख्या। +`agent_workflow_duration_seconds` - प्रत्येक स्थिति में बिताए गए समय का हिस्टोग्राम। +`agent_state_availability` - प्रति स्थिति उपलब्ध टूल का गेज। + +**सुरक्षा मेट्रिक्स:** +`agent_group_access_denied_total` - अनधिकृत समूह एक्सेस की संख्या। +`agent_invalid_state_transition_total` - अमान्य स्थिति परिवर्तनों की संख्या। +`agent_privilege_escalation_attempts_total` - संदिग्ध अनुरोधों की संख्या। + +#### 8.2 लॉगिंग सुधार + +**अनुरोध लॉगिंग:** +```json +{ + "request_id": "req-123", + "requested_groups": ["read-only", "knowledge"], + "initial_state": "undefined", + "state_transitions": [ + {"tool": "knowledge-query", "from": "undefined", "to": "analysis", "timestamp": "2024-01-01T10:00:01Z"} + ], + "available_tools": ["knowledge-query", "text-completion"], + "filtered_by_group": ["graph-update", "admin-tool"], + "filtered_by_state": [], + "execution_time": "1.2s" +} +``` + +### 9. परीक्षण रणनीति + +#### 9.1 यूनिट परीक्षण + +**उपकरण फ़िल्टरिंग लॉजिक:** +परीक्षण समूह इंटरसेक्शन गणनाएँ +परीक्षण राज्य-आधारित फ़िल्टरिंग लॉजिक +डिफ़ॉल्ट समूह और राज्य असाइनमेंट की जाँच करें +वाइल्डकार्ड समूह व्यवहार का परीक्षण करें +खाली समूह हैंडलिंग को मान्य करें +संयुक्त समूह+राज्य फ़िल्टरिंग परिदृश्यों का परीक्षण करें + +**कॉन्फ़िगरेशन सत्यापन:** +विभिन्न समूह और राज्य कॉन्फ़िगरेशन के साथ उपकरण लोडिंग का परीक्षण करें +अमान्य समूह और राज्य विनिर्देशों के लिए स्कीमा सत्यापन की जाँच करें +मौजूदा कॉन्फ़िगरेशन के साथ पिछड़े अनुकूलता का परीक्षण करें +राज्य संक्रमण परिभाषाओं और चक्रों को मान्य करें + +#### 9.2 एकीकरण परीक्षण + +**एजेंट व्यवहार:** +सत्यापित करें कि एजेंट केवल समूह+राज्य फ़िल्टर किए गए उपकरणों को ही देखते हैं +विभिन्न समूह संयोजनों के साथ अनुरोध निष्पादन का परीक्षण करें +एजेंट निष्पादन के दौरान राज्य संक्रमणों का परीक्षण करें +जब कोई उपकरण उपलब्ध न हो तो त्रुटि हैंडलिंग को मान्य करें +कई राज्यों के माध्यम से वर्कफ़्लो प्रगति का परीक्षण करें + +**सुरक्षा परीक्षण:** +विशेषाधिकार वृद्धि रोकथाम का परीक्षण करें +ऑडिट ट्रेल की सटीकता को सत्यापित करें +उपयोगकर्ता अनुमतियों के साथ गेटवे एकीकरण का परीक्षण करें + +#### 9.3 एंड-टू-एंड परिदृश्य + +**राज्य वर्कफ़्लो के साथ मल्टी-टेनांट उपयोग:** +``` +Scenario: Different users with different tool access and workflow states +Given: User A has "read-only" permissions, state "undefined" + And: User B has "write" permissions, state "analysis" +When: Both request knowledge operations +Then: User A gets read-only tools available in "undefined" state + And: User B gets write tools available in "analysis" state + And: State transitions are tracked per user session + And: All usage and transitions are properly audited +``` + +**कार्यप्रवाह स्थिति प्रगति:** +``` +Scenario: Complete workflow execution +Given: Request with groups ["knowledge", "compute"] and state "undefined" +When: Agent executes knowledge-query tool (transitions to "analysis") + And: Agent executes complex-analysis tool (transitions to "results") + And: Agent executes reset-workflow tool (transitions to "undefined") +Then: Each step has correctly filtered available tools + And: State transitions are logged with timestamps + And: Final state allows initial workflow to repeat +``` + +### 10. प्रदर्शन संबंधी विचार + +#### 10.1 टूल लोडिंग का प्रभाव + +**कॉन्फ़िगरेशन लोडिंग:** +समूह और स्थिति मेटाडेटा स्टार्टअप पर एक बार लोड होता है +प्रति टूल न्यूनतम मेमोरी ओवरहेड (अतिरिक्त फ़ील्ड) +टूल इनिशियलाइज़ेशन समय पर कोई प्रभाव नहीं + +**अनुरोध प्रसंस्करण:** +समूह+स्थिति फ़िल्टरिंग एक बार प्रति अनुरोध होती है +O(n) जटिलता, जहाँ n = कॉन्फ़िगर किए गए टूल की संख्या +राज्य परिवर्तन न्यूनतम ओवरहेड जोड़ते हैं (स्ट्रिंग असाइनमेंट) +विशिष्ट टूल गणना के लिए नगण्य प्रभाव (< 100) + +#### 10.2 अनुकूलन रणनीतियाँ + +**पूर्व-गणना किए गए टूल सेट:** +समूह+स्थिति संयोजन द्वारा टूल सेट को कैश करें +सामान्य समूह/स्थिति पैटर्न के लिए बार-बार फ़िल्टरिंग से बचें +बार-बार उपयोग किए जाने वाले संयोजनों के लिए मेमोरी बनाम गणना का समझौता + +**लेज़ी लोडिंग:** +केवल आवश्यकता पड़ने पर टूल कार्यान्वयन लोड करें +कई टूल वाले डिप्लॉयमेंट के लिए स्टार्टअप समय कम करें +समूह आवश्यकताओं के आधार पर गतिशील टूल पंजीकरण + +### 11. भविष्य के सुधार + +#### 11.1 गतिशील समूह असाइनमेंट + +**संदर्भ-जागरूक समूहीकरण:** +अनुरोध संदर्भ के आधार पर टूल को समूहों में असाइन करें +समय-आधारित समूह उपलब्धता (केवल व्यावसायिक घंटों के दौरान) +लोड-आधारित समूह प्रतिबंध (कम उपयोग के दौरान महंगे टूल) + +#### 11.2 समूह पदानुक्रम + +**नेस्टेड समूह संरचना:** +```json +{ + "knowledge": { + "read": ["knowledge-query", "entity-search"], + "write": ["graph-update", "entity-create"] + } +} +``` + +#### 11.3 उपकरण अनुशंसाएँ + +**समूह-आधारित सुझाव:** +अनुरोध प्रकारों के लिए इष्टतम उपकरण समूहों का सुझाव दें +अनुशंसाओं को बेहतर बनाने के लिए उपयोग पैटर्न से सीखें +जब पसंदीदा उपकरण उपलब्ध न हों तो वैकल्पिक समूहों का प्रावधान करें + +### 12. खुले प्रश्न + +1. **समूह सत्यापन**: क्या अनुरोधों में अमान्य समूह नामों के कारण हार्ड विफलताएँ या चेतावनियाँ आनी चाहिए? + +2. **समूह खोज**: क्या सिस्टम उपलब्ध समूहों और उनके उपकरणों की सूची प्रदान करने के लिए एक एपीआई प्रदान करना चाहिए? + +3. **गतिशील समूह**: क्या समूहों को रनटाइम पर या केवल स्टार्टअप पर ही कॉन्फ़िगर किया जाना चाहिए? + +4. **समूह विरासत**: क्या उपकरणों को अपने मूल श्रेणियों या कार्यान्वयन से समूहों को विरासत में मिलना चाहिए? + +5. **प्रदर्शन निगरानी**: समूह-आधारित उपकरण उपयोग को प्रभावी ढंग से ट्रैक करने के लिए किन अतिरिक्त मेट्रिक्स की आवश्यकता है? + +### 13. निष्कर्ष + +उपकरण समूह प्रणाली निम्नलिखित प्रदान करती है: + +**सुरक्षा**: एजेंट क्षमताओं पर बारीक पहुंच नियंत्रण +**प्रदर्शन**: उपकरण लोडिंग और चयन ओवरहेड में कमी +**लचीलापन**: बहु-आयामी उपकरण वर्गीकरण +**संगतता**: मौजूदा एजेंट आर्किटेक्चर के साथ निर्बाध एकीकरण + +यह प्रणाली ट्रस्टग्राफ परिनियोजन को उपकरण पहुंच को बेहतर ढंग से प्रबंधित करने, सुरक्षा सीमाओं में सुधार करने और मौजूदा कॉन्फ़िगरेशन और अनुरोधों के साथ पूर्ण पिछड़े संगतता बनाए रखते हुए संसाधन उपयोग को अनुकूलित करने में सक्षम बनाती है। diff --git a/docs/tech-specs/tool-group.pt.md b/docs/tech-specs/tool-group.pt.md new file mode 100644 index 00000000..ba206ee9 --- /dev/null +++ b/docs/tech-specs/tool-group.pt.md @@ -0,0 +1,491 @@ +# TrustGraph Tool Group System +## Especificação Técnica v1.0 + +### Resumo Executivo + +Esta especificação define um sistema de agrupamento de ferramentas para agentes TrustGraph que permite um controle preciso sobre quais ferramentas estão disponíveis para solicitações específicas. O sistema introduz filtragem de ferramentas baseada em grupos por meio de configuração e especificação no nível da solicitação, permitindo melhores limites de segurança, gerenciamento de recursos e particionamento funcional das capacidades do agente. + +### 1. Visão Geral + +#### 1.1 Declaração do Problema + +Atualmente, os agentes TrustGraph têm acesso a todas as ferramentas configuradas, independentemente do contexto da solicitação ou dos requisitos de segurança. Isso cria vários desafios: + +**Risco de Segurança**: Ferramentas sensíveis (por exemplo, modificação de dados) estão disponíveis mesmo para consultas somente leitura. +**Desperdício de Recursos**: Ferramentas complexas são carregadas mesmo quando consultas simples não as exigem. +**Confusão Funcional**: Os agentes podem selecionar ferramentas inadequadas quando alternativas mais simples existem. +**Isolamento Multi-inquilino**: Diferentes grupos de usuários precisam de acesso a conjuntos de ferramentas diferentes. + +#### 1.2 Visão Geral da Solução + +O sistema de agrupamento de ferramentas introduz: + +1. **Classificação por Grupo**: As ferramentas são marcadas com associações de grupo durante a configuração. +2. **Filtragem no Nível da Solicitação**: AgentRequest especifica quais grupos de ferramentas são permitidos. +3. **Aplicação em Tempo de Execução**: Os agentes têm acesso apenas a ferramentas que correspondem aos grupos solicitados. +4. **Agrupamento Flexível**: As ferramentas podem pertencer a vários grupos para cenários complexos. + +### 2. Alterações no Esquema + +#### 2.1 Aprimoramento do Esquema de Configuração da Ferramenta + +A configuração existente da ferramenta é aprimorada com um campo `group`: + +**Antes:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph" +} +``` + +**Depois:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"] +} +``` + +**Especificação do Campo do Grupo:** +`group`: Array(String) - Lista de grupos aos quais esta ferramenta pertence +**Opcional**: Ferramentas sem campo de grupo pertencem ao grupo "padrão" +**Múltipla associação**: As ferramentas podem pertencer a vários grupos +**Sensível a maiúsculas e minúsculas**: Os nomes dos grupos são correspondências exatas de strings + +#### 2.1.2 Melhoria da Transição de Estado da Ferramenta + +As ferramentas podem, opcionalmente, especificar transições de estado e disponibilidade baseada no estado: + +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"], + "state": "analysis", + "available_in_states": ["undefined", "research"] +} +``` + +**Especificação do Campo de Estado:** +`state`: String - **Opcional** - Estado para o qual transitar após a execução bem-sucedida da ferramenta +`available_in_states`: Array(String) - **Opcional** - Estados nos quais esta ferramenta está disponível +**Comportamento padrão**: Ferramentas sem `available_in_states` estão disponíveis em todos os estados +**Transição de estado**: Ocorre apenas após a execução bem-sucedida da ferramenta + +#### 2.2 Melhoria do Esquema AgentRequest + +O esquema `AgentRequest` em `trustgraph-base/trustgraph/schema/services/agent.py` é aprimorado: + +**AgentRequest Atual:** +`question`: String - Consulta do usuário +`plan`: String - Plano de execução (pode ser removido) +`state`: String - Estado do agente +`history`: Array(AgentStep) - Histórico de execução + +**AgentRequest Aprimorado:** +`question`: String - Consulta do usuário +`state`: String - Estado de execução do agente (agora usado ativamente para filtragem de ferramentas) +`history`: Array(AgentStep) - Histórico de execução +`group`: Array(String) - **NOVO** - Grupos de ferramentas permitidos para este pedido + +**Alterações no Esquema:** +**Removido**: O campo `plan` não é mais necessário e pode ser removido (originalmente destinado à especificação de ferramentas) +**Adicionado**: O campo `group` para especificação de grupos de ferramentas +**Aprimorado**: O campo `state` agora controla a disponibilidade de ferramentas durante a execução + +**Comportamentos dos Campos:** + +**Grupo de Campo:** +**Opcional**: Se não especificado, o padrão é ["default"] +**Interseção**: Apenas as ferramentas que correspondem a pelo menos um grupo especificado estão disponíveis +**Array vazio**: Nenhuma ferramenta disponível (o agente só pode usar o raciocínio interno) +**Curinga**: O grupo especial "*" concede acesso a todas as ferramentas + +**Campo de Estado:** +**Opcional**: Se não especificado, o padrão é "undefined" +**Filtragem baseada em estado**: Apenas as ferramentas disponíveis no estado atual são elegíveis +**Estado padrão**: O estado "undefined" permite todas as ferramentas (sujeito à filtragem de grupos) +**Transições de estado**: As ferramentas podem alterar o estado após a execução bem-sucedida + +### 3. Exemplos de Grupos Personalizados + +As organizações podem definir grupos específicos do domínio: + +```json +{ + "financial-tools": ["stock-query", "portfolio-analysis"], + "medical-tools": ["diagnosis-assist", "drug-interaction"], + "legal-tools": ["contract-analysis", "case-search"] +} +``` + +### 4. Detalhes de Implementação + +#### 4.1 Carregamento e Filtragem de Ferramentas + +**Fase de Configuração:** +1. Todas as ferramentas são carregadas da configuração com suas atribuições de grupo. +2. Ferramentas sem grupos explícitos são atribuídas ao grupo "padrão". +3. A associação a grupos é validada e armazenada no registro de ferramentas. + +**Fase de Processamento de Solicitações:** +1. Uma solicitação do agente chega com uma especificação de grupo opcional. +2. O agente filtra as ferramentas disponíveis com base na interseção de grupos. +3. Apenas as ferramentas correspondentes são passadas para o contexto de execução do agente. +4. O agente opera com o conjunto de ferramentas filtrado durante todo o ciclo de vida da solicitação. + +#### 4.2 Lógica de Filtragem de Ferramentas + +**Filtragem Combinada de Grupo e Estado:** + +``` +For each configured tool: + tool_groups = tool.group || ["default"] + tool_states = tool.available_in_states || ["*"] // Available in all states + +For each request: + requested_groups = request.group || ["default"] + current_state = request.state || "undefined" + +Tool is available if: + // Group filtering + (intersection(tool_groups, requested_groups) is not empty OR "*" in requested_groups) + AND + // State filtering + (current_state in tool_states OR "*" in tool_states) +``` + +**Lógica de Transição de Estado:** + +``` +After successful tool execution: + if tool.state is defined: + next_request.state = tool.state + else: + next_request.state = current_request.state // No change +``` + +#### 4.3 Pontos de Integração do Agente + +**Agente ReAct:** +O filtro de ferramentas ocorre em agent_manager.py durante a criação do registro de ferramentas. +A lista de ferramentas disponíveis é filtrada por grupo e estado antes da geração do plano. +As transições de estado atualizam o campo AgentRequest.state após a execução bem-sucedida da ferramenta. +A próxima iteração usa o estado atualizado para o filtro de ferramentas. + +**Agente Baseado em Confiança:** +O filtro de ferramentas ocorre em planner.py durante a geração do plano. +A validação de ExecutionStep garante que apenas as ferramentas elegíveis por grupo e estado sejam usadas. +O controlador de fluxo impõe a disponibilidade da ferramenta em tempo de execução. +As transições de estado são gerenciadas pelo Controlador de Fluxo entre os passos. + +### 5. Exemplos de Configuração + +#### 5.1 Configuração de Ferramentas com Grupos e Estados + +```yaml +tool: + knowledge-query: + type: knowledge-query + name: "Knowledge Graph Query" + description: "Query the knowledge graph for entities and relationships" + group: ["read-only", "knowledge", "basic"] + state: "analysis" + available_in_states: ["undefined", "research"] + + graph-update: + type: graph-update + name: "Graph Update" + description: "Add or modify entities in the knowledge graph" + group: ["write", "knowledge", "admin"] + available_in_states: ["analysis", "modification"] + + text-completion: + type: text-completion + name: "Text Completion" + description: "Generate text using language models" + group: ["read-only", "text", "basic"] + state: "undefined" + # No available_in_states = available in all states + + complex-analysis: + type: mcp-tool + name: "Complex Analysis Tool" + description: "Perform complex data analysis" + group: ["advanced", "compute", "expensive"] + state: "results" + available_in_states: ["analysis"] + mcp_tool_id: "analysis-server" + + reset-workflow: + type: mcp-tool + name: "Reset Workflow" + description: "Reset to initial state" + group: ["admin"] + state: "undefined" + available_in_states: ["analysis", "results"] +``` + +#### 5.2 Exemplos de Solicitações com Fluxos de Trabalho de Estado + +**Solicitação de Pesquisa Inicial:** +```json +{ + "question": "What entities are connected to Company X?", + "group": ["read-only", "knowledge"], + "state": "undefined" +} +``` +*Ferramentas disponíveis: knowledge-query, text-completion* +*Após knowledge-query: estado → "análise"* + +**Fase de Análise:** +```json +{ + "question": "Continue analysis based on previous results", + "group": ["advanced", "compute", "write"], + "state": "analysis" +} +``` +*Ferramentas disponíveis: complex-analysis, graph-update, reset-workflow* +*Após complex-analysis: estado → "results"* + +**Fase de Resultados:** +```json +{ + "question": "What should I do with these results?", + "group": ["admin"], + "state": "results" +} +``` +*Ferramentas disponíveis: apenas reset-workflow* +*Após reset-workflow: estado → "indefinido"* + +**Exemplo de Fluxo de Trabalho - Fluxo Completo:** +1. **Início (indefinido)**: Use knowledge-query → transições para "análise" +2. **Estado de análise**: Use complex-analysis → transições para "resultados" +3. **Estado de resultados**: Use reset-workflow → transições de volta para "indefinido" +4. **Retorno ao início**: Todas as ferramentas iniciais estão disponíveis novamente + +### 6. Considerações de Segurança + +#### 6.1 Integração de Controle de Acesso + +**Filtragem no Nível do Gateway:** +O gateway pode impor restrições de grupo com base nas permissões do usuário +Previne a elevação de privilégios através da manipulação de solicitações +O registro de auditoria inclui os grupos de ferramentas solicitados e concedidos + +**Exemplo de Lógica do Gateway:** +``` +user_permissions = get_user_permissions(request.user_id) +allowed_groups = user_permissions.tool_groups +requested_groups = request.group + +# Validate request doesn't exceed permissions +if not is_subset(requested_groups, allowed_groups): + reject_request("Insufficient permissions for requested tool groups") +``` + +#### 6.2 Auditoria e Monitoramento + +**Rastreamento de Auditoria Aprimorado:** +Registrar os grupos de ferramentas solicitados e o estado inicial por solicitação +Rastrear as transições de estado e o uso de ferramentas por associação a grupos +Monitorar tentativas de acesso não autorizado a grupos e transições de estado inválidas +Alertar sobre padrões de uso de grupos incomuns ou fluxos de trabalho de estado suspeitos + +### 7. Estratégia de Migração + +#### 7.1 Compatibilidade com Versões Anteriores + +**Fase 1: Alterações Aditivas** +Adicionar campo opcional `group` às configurações de ferramentas +Adicionar campo opcional `group` ao esquema AgentRequest +Comportamento padrão: Todas as ferramentas existentes pertencem ao grupo "default" +Solicitações existentes sem o campo de grupo usam o grupo "default" + +**Comportamento Existente Preservado:** +Ferramentas sem configuração de grupo continuam a funcionar (grupo default) +Ferramentas sem configuração de estado estão disponíveis em todos os estados +Solicitações sem especificação de grupo acessam todas as ferramentas (grupo default) +Solicitações sem especificação de estado usam o estado "undefined" (todas as ferramentas disponíveis) +Nenhuma alteração disruptiva para implantações existentes + +### 8. Monitoramento e Observabilidade + +#### 8.1 Novas Métricas + +**Uso de Grupos de Ferramentas:** +`agent_tool_group_requests_total` - Contador de solicitações por grupo +`agent_tool_group_availability` - Indicador do número de ferramentas disponíveis por grupo +`agent_filtered_tools_count` - Histograma do número de ferramentas após a filtragem por grupo + estado + +**Métricas de Fluxo de Trabalho de Estado:** +`agent_state_transitions_total` - Contador de transições de estado por ferramenta +`agent_workflow_duration_seconds` - Histograma do tempo gasto em cada estado +`agent_state_availability` - Indicador do número de ferramentas disponíveis por estado + +**Métricas de Segurança:** +`agent_group_access_denied_total` - Contador de acessos a grupos não autorizados +`agent_invalid_state_transition_total` - Contador de transições de estado inválidas +`agent_privilege_escalation_attempts_total` - Contador de solicitações suspeitas + +#### 8.2 Melhorias de Registro (Logging) + +**Registro de Solicitações:** +```json +{ + "request_id": "req-123", + "requested_groups": ["read-only", "knowledge"], + "initial_state": "undefined", + "state_transitions": [ + {"tool": "knowledge-query", "from": "undefined", "to": "analysis", "timestamp": "2024-01-01T10:00:01Z"} + ], + "available_tools": ["knowledge-query", "text-completion"], + "filtered_by_group": ["graph-update", "admin-tool"], + "filtered_by_state": [], + "execution_time": "1.2s" +} +``` + +### 9. Estratégia de Testes + +#### 9.1 Testes Unitários + +**Lógica de Filtragem de Ferramentas:** +Cálculos de interseção de grupos de teste +Lógica de filtragem baseada em estado +Verificar a atribuição padrão de grupo e estado +Testar o comportamento de grupos curinga +Validar o tratamento de grupos vazios +Testar cenários de filtragem combinada de grupo+estado + +**Validação de Configuração:** +Testar o carregamento de ferramentas com várias configurações de grupo e estado +Verificar a validação de esquema para especificações inválidas de grupo e estado +Testar a compatibilidade com versões anteriores com as configurações existentes +Validar as definições e ciclos de transição de estado + +#### 9.2 Testes de Integração + +**Comportamento do Agente:** +Verificar se os agentes veem apenas as ferramentas filtradas por grupo+estado +Testar a execução de solicitações com várias combinações de grupos +Testar as transições de estado durante a execução do agente +Validar o tratamento de erros quando nenhuma ferramenta está disponível +Testar a progressão do fluxo de trabalho por meio de vários estados + +**Testes de Segurança:** +Testar a prevenção de escalada de privilégios +Verificar a precisão do registro de auditoria +Testar a integração do gateway com as permissões do usuário + +#### 9.3 Cenários de Ponta a Ponta + +**Uso Multi-tenant com Fluxos de Trabalho de Estado:** +``` +Scenario: Different users with different tool access and workflow states +Given: User A has "read-only" permissions, state "undefined" + And: User B has "write" permissions, state "analysis" +When: Both request knowledge operations +Then: User A gets read-only tools available in "undefined" state + And: User B gets write tools available in "analysis" state + And: State transitions are tracked per user session + And: All usage and transitions are properly audited +``` + +**Progressão do Estado do Fluxo de Trabalho:** +``` +Scenario: Complete workflow execution +Given: Request with groups ["knowledge", "compute"] and state "undefined" +When: Agent executes knowledge-query tool (transitions to "analysis") + And: Agent executes complex-analysis tool (transitions to "results") + And: Agent executes reset-workflow tool (transitions to "undefined") +Then: Each step has correctly filtered available tools + And: State transitions are logged with timestamps + And: Final state allows initial workflow to repeat +``` + +### 10. Considerações de Desempenho + +#### 10.1 Impacto do Carregamento de Ferramentas + +**Carregamento de Configuração:** +Metadados de grupo e estado carregados uma vez na inicialização +Sobrecarga de memória mínima por ferramenta (campos adicionais) +Sem impacto no tempo de inicialização da ferramenta + +**Processamento de Requisições:** +Filtragem combinada de grupo+estado ocorre uma vez por requisição +Complexidade O(n) onde n = número de ferramentas configuradas +Transições de estado adicionam uma sobrecarga mínima (atribuição de string) +Impacto insignificante para um número típico de ferramentas (< 100) + +#### 10.2 Estratégias de Otimização + +**Conjuntos de Ferramentas Pré-calculados:** +Armazene em cache os conjuntos de ferramentas por combinação de grupo+estado +Evite filtragem repetida para padrões comuns de grupo/estado +Troca entre memória e computação para combinações frequentemente usadas + +**Carregamento Preguiçoso (Lazy Loading):** +Carregue as implementações das ferramentas somente quando necessário +Reduza o tempo de inicialização para implantações com muitas ferramentas +Registro dinâmico de ferramentas com base nos requisitos do grupo + +### 11. Melhorias Futuras + +#### 11.1 Atribuição Dinâmica de Grupos + +**Agrupamento Contextual:** +Atribua ferramentas a grupos com base no contexto da requisição +Disponibilidade do grupo baseada no tempo (apenas horário comercial) +Restrições de grupo baseadas na carga (ferramentas caras durante baixo uso) + +#### 11.2 Hierarquias de Grupos + +**Estrutura de Grupo Aninhada:** +```json +{ + "knowledge": { + "read": ["knowledge-query", "entity-search"], + "write": ["graph-update", "entity-create"] + } +} +``` + +#### 11.3 Recomendações de Ferramentas + +**Sugestões Baseadas em Grupos:** +Sugerir grupos de ferramentas ideais para tipos de requisições +Aprender com padrões de uso para melhorar as recomendações +Fornecer grupos de fallback quando as ferramentas preferidas não estiverem disponíveis + +### 12. Perguntas Abertas + +1. **Validação de Grupos**: Nomes de grupos inválidos em requisições devem causar falhas graves ou avisos? + +2. **Descoberta de Grupos**: O sistema deve fornecer uma API para listar os grupos disponíveis e suas ferramentas? + +3. **Grupos Dinâmicos**: Os grupos devem ser configuráveis em tempo de execução ou apenas na inicialização? + +4. **Herança de Grupos**: As ferramentas devem herdar grupos de suas categorias ou implementações pai? + +5. **Monitoramento de Desempenho**: Quais métricas adicionais são necessárias para rastrear o uso de ferramentas com base em grupos de forma eficaz? + +### 13. Conclusão + +O sistema de grupos de ferramentas fornece: + +**Segurança**: Controle de acesso granular sobre as capacidades do agente +**Desempenho**: Redução da sobrecarga de carregamento e seleção de ferramentas +**Flexibilidade**: Classificação de ferramentas multidimensional +**Compatibilidade**: Integração perfeita com arquiteturas de agentes existentes + +Este sistema permite que as implementações do TrustGraph gerenciem melhor o acesso às ferramentas, aprimorem as fronteiras de segurança e otimizem o uso de recursos, mantendo total compatibilidade com versões anteriores de configurações e requisições. diff --git a/docs/tech-specs/tool-group.ru.md b/docs/tech-specs/tool-group.ru.md new file mode 100644 index 00000000..f415de6e --- /dev/null +++ b/docs/tech-specs/tool-group.ru.md @@ -0,0 +1,491 @@ +# TrustGraph Tool Group System +## Техническая спецификация v1.0 + +### Краткое описание + +Эта спецификация определяет систему группировки инструментов для агентов TrustGraph, которая позволяет осуществлять детальный контроль над тем, какие инструменты доступны для конкретных запросов. Система вводит фильтрацию инструментов на основе групп с помощью конфигурации и указания на уровне запроса, что обеспечивает более строгие границы безопасности, управление ресурсами и функциональное разделение возможностей агентов. + +### 1. Обзор + +#### 1.1 Описание проблемы + +В настоящее время агенты TrustGraph имеют доступ ко всем настроенным инструментам, независимо от контекста запроса или требований безопасности. Это создает несколько проблем: + +**Риск безопасности**: Чувствительные инструменты (например, изменение данных) доступны даже для запросов только для чтения. +**Неэффективное использование ресурсов**: Сложные инструменты загружаются даже тогда, когда простые запросы не требуют их. +**Функциональная путаница**: Агенты могут выбирать неподходящие инструменты, когда существуют более простые альтернативы. +**Изоляция для многопользовательских сред**: Различным группам пользователей требуется доступ к разным наборам инструментов. + +#### 1.2 Обзор решения + +Система группировки инструментов включает в себя: + +1. **Классификация по группам**: Инструменты помечаются принадлежностью к группам во время конфигурации. +2. **Фильтрация на уровне запроса**: AgentRequest указывает, какие группы инструментов разрешены. +3. **Принудительное исполнение во время выполнения**: Агенты имеют доступ только к инструментам, соответствующим запрошенным группам. +4. **Гибкая группировка**: Инструменты могут принадлежать к нескольким группам для сложных сценариев. + +### 2. Изменения схемы + +#### 2.1 Расширение схемы конфигурации инструмента + +Существующая схема конфигурации инструмента расширена с помощью поля `group`: + +**До:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph" +} +``` + +**После:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"] +} +``` + +**Спецификация поля группы:** +`group`: Array(String) - Список групп, к которым принадлежит этот инструмент. +**Необязательно**: Инструменты без поля группы принадлежат к группе "по умолчанию". +**Множественная принадлежность**: Инструменты могут принадлежать к нескольким группам. +**Чувствительность к регистру**: Имена групп должны точно соответствовать строке. + +#### 2.1.2 Улучшение переходов состояния инструмента + +Инструменты могут опционально указывать переходы состояний и доступность, зависящую от состояния: + +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"], + "state": "analysis", + "available_in_states": ["undefined", "research"] +} +``` + +**Спецификация состояния:** +`state`: String - **Необязательно** - Состояние, в которое система переходит после успешного выполнения инструмента. +`available_in_states`: Array(String) - **Необязательно** - Состояния, в которых этот инструмент доступен. +**Поведение по умолчанию**: Инструменты без `available_in_states` доступны во всех состояниях. +**Переход состояния**: Происходит только после успешного выполнения инструмента. + +#### 2.2 Улучшение схемы AgentRequest + +Схема `AgentRequest` в `trustgraph-base/trustgraph/schema/services/agent.py` улучшена: + +**Текущий AgentRequest:** +`question`: String - Пользовательский запрос. +`plan`: String - План выполнения (может быть удален). +`state`: String - Состояние агента. +`history`: Array(AgentStep) - История выполнения. + +**Улучшенный AgentRequest:** +`question`: String - Пользовательский запрос. +`state`: String - Состояние выполнения агента (теперь активно используется для фильтрации инструментов). +`history`: Array(AgentStep) - История выполнения. +`group`: Array(String) - **НОВОЕ** - Группы инструментов, разрешенные для этого запроса. + +**Изменения в схеме:** +**Удалено**: Поле `plan` больше не требуется и может быть удалено (изначально предназначалось для указания инструментов). +**Добавлено**: Поле `group` для указания групп инструментов. +**Улучшено**: Поле `state` теперь контролирует доступность инструментов во время выполнения. + +**Поведение полей:** + +**Группа (Group):** +**Необязательно**: Если не указано, по умолчанию используется ["default"]. +**Пересечение**: Доступны только инструменты, соответствующие хотя бы одной указанной группе. +**Пустой массив**: Ни один инструмент не доступен (агент может использовать только внутренние рассуждения). +**Подстановочный знак**: Специальная группа "*" предоставляет доступ ко всем инструментам. + +**Состояние (State):** +**Необязательно**: Если не указано, по умолчанию используется "undefined". +**Фильтрация по состоянию**: Доступны только инструменты, доступные в текущем состоянии. +**Состояние по умолчанию**: Состояние "undefined" позволяет использовать все инструменты (с учетом фильтрации по группам). +**Переходы состояний**: Состояние инструментов может меняться после успешного выполнения. + +### 3. Примеры пользовательских групп + +Организации могут определять группы, специфичные для домена: + +```json +{ + "financial-tools": ["stock-query", "portfolio-analysis"], + "medical-tools": ["diagnosis-assist", "drug-interaction"], + "legal-tools": ["contract-analysis", "case-search"] +} +``` + +### 4. Детали реализации + +#### 4.1 Загрузка и фильтрация инструментов + +**Фаза конфигурации:** +1. Все инструменты загружаются из конфигурации вместе с их групповыми назначениями. +2. Инструменты, не имеющие явных групповых назначений, назначаются в группу "default". +3. Групповая принадлежность проверяется и сохраняется в реестре инструментов. + +**Фаза обработки запросов:** +1. Запрос AgentRequest поступает с опциональной спецификацией группы. +2. Agent фильтрует доступные инструменты на основе пересечения групп. +3. Только соответствующие инструменты передаются в контекст выполнения агента. +4. Agent работает с отфильтрованным набором инструментов на протяжении всего жизненного цикла запроса. + +#### 4.2 Логика фильтрации инструментов + +**Комбинированная фильтрация по группам и состоянию:** + +``` +For each configured tool: + tool_groups = tool.group || ["default"] + tool_states = tool.available_in_states || ["*"] // Available in all states + +For each request: + requested_groups = request.group || ["default"] + current_state = request.state || "undefined" + +Tool is available if: + // Group filtering + (intersection(tool_groups, requested_groups) is not empty OR "*" in requested_groups) + AND + // State filtering + (current_state in tool_states OR "*" in tool_states) +``` + +**Логика переходов состояний:** + +``` +After successful tool execution: + if tool.state is defined: + next_request.state = tool.state + else: + next_request.state = current_request.state // No change +``` + +#### 4.3 Точки интеграции агента + +**Агент ReAct:** +Фильтрация инструментов происходит в файле agent_manager.py во время создания регистрации инструментов. +Список доступных инструментов фильтруется как по группе, так и по состоянию перед генерацией плана. +Изменения состояния обновляют поле AgentRequest.state после успешного выполнения инструмента. +Следующая итерация использует обновленное состояние для фильтрации инструментов. + +**Агент, основанный на оценке уверенности:** +Фильтрация инструментов происходит в файле planner.py во время генерации плана. +Проверка ExecutionStep гарантирует, что используются только инструменты, соответствующие группе и состоянию. +Контроллер потока обеспечивает доступность инструментов во время выполнения. +Изменения состояния управляются контроллером потока между шагами. + +### 5. Примеры конфигурации + +#### 5.1 Конфигурация инструментов с группами и состояниями + +```yaml +tool: + knowledge-query: + type: knowledge-query + name: "Knowledge Graph Query" + description: "Query the knowledge graph for entities and relationships" + group: ["read-only", "knowledge", "basic"] + state: "analysis" + available_in_states: ["undefined", "research"] + + graph-update: + type: graph-update + name: "Graph Update" + description: "Add or modify entities in the knowledge graph" + group: ["write", "knowledge", "admin"] + available_in_states: ["analysis", "modification"] + + text-completion: + type: text-completion + name: "Text Completion" + description: "Generate text using language models" + group: ["read-only", "text", "basic"] + state: "undefined" + # No available_in_states = available in all states + + complex-analysis: + type: mcp-tool + name: "Complex Analysis Tool" + description: "Perform complex data analysis" + group: ["advanced", "compute", "expensive"] + state: "results" + available_in_states: ["analysis"] + mcp_tool_id: "analysis-server" + + reset-workflow: + type: mcp-tool + name: "Reset Workflow" + description: "Reset to initial state" + group: ["admin"] + state: "undefined" + available_in_states: ["analysis", "results"] +``` + +#### 5.2 Примеры запросов с рабочими процессами, зависящими от состояния. + +**Первоначальный запрос на исследование:** +```json +{ + "question": "What entities are connected to Company X?", + "group": ["read-only", "knowledge"], + "state": "undefined" +} +``` +*Доступные инструменты: knowledge-query, text-completion* +*После knowledge-query: состояние → "analysis"* + +**Фаза анализа:** +```json +{ + "question": "Continue analysis based on previous results", + "group": ["advanced", "compute", "write"], + "state": "analysis" +} +``` +*Доступные инструменты: complex-analysis, graph-update, reset-workflow* +*После complex-analysis: состояние → "results"* + +**Фаза результатов:** +```json +{ + "question": "What should I do with these results?", + "group": ["admin"], + "state": "results" +} +``` +*Доступные инструменты: только reset-workflow* +*После выполнения reset-workflow: состояние → "undefined"* + +**Пример рабочего процесса - Полный цикл:** +1. **Начало (undefined):** Используйте knowledge-query → переходы в состояние "analysis" +2. **Состояние анализа:** Используйте complex-analysis → переходы в состояние "results" +3. **Состояние результатов:** Используйте reset-workflow → возврат в состояние "undefined" +4. **Возврат к началу:** Все начальные инструменты снова доступны + +### 6. Вопросы безопасности + +#### 6.1 Интеграция с контролем доступа + +**Фильтрация на уровне шлюза:** +Шлюз может применять ограничения для групп на основе прав доступа пользователя +Предотвращение повышения привилегий путем манипулирования запросами +Журнал аудита включает запрошенные и предоставленные группы инструментов + +**Пример логики шлюза:** +``` +user_permissions = get_user_permissions(request.user_id) +allowed_groups = user_permissions.tool_groups +requested_groups = request.group + +# Validate request doesn't exceed permissions +if not is_subset(requested_groups, allowed_groups): + reject_request("Insufficient permissions for requested tool groups") +``` + +#### 6.2 Аудит и мониторинг + +**Расширенный журнал аудита:** +Регистрировать запрошенные группы инструментов и начальное состояние для каждого запроса. +Отслеживать переходы состояний и использование инструментов по принадлежности к группе. +Мониторить попытки несанкционированного доступа к группам и недопустимые переходы состояний. +Оповещать об необычных шаблонах использования групп или подозрительных рабочих процессах состояний. + +### 7. Стратегия миграции + +#### 7.1 Обратная совместимость + +**Этап 1: Аддитивные изменения** +Добавить необязательное поле `group` в конфигурации инструментов. +Добавить необязательное поле `group` в схему AgentRequest. +Поведение по умолчанию: Все существующие инструменты принадлежат к группе "default". +Существующие запросы без поля группы используют группу "default". + +**Сохранение существующего поведения:** +Инструменты без конфигурации группы продолжают работать (группа "default"). +Инструменты без конфигурации состояния доступны во всех состояниях. +Запросы без указания группы получают доступ ко всем инструментам (группа "default"). +Запросы без указания состояния используют состояние "не определено" (доступны все инструменты). +Отсутствуют изменения, нарушающие работу существующих развертываний. + +### 8. Мониторинг и наблюдаемость + +#### 8.1 Новые метрики + +**Использование групп инструментов:** +`agent_tool_group_requests_total` - Счетчик запросов по группе. +`agent_tool_group_availability` - Показатель количества доступных инструментов для каждой группы. +`agent_filtered_tools_count` - Гистограмма количества инструментов после фильтрации по группе и состоянию. + +**Метрики рабочих процессов состояний:** +`agent_state_transitions_total` - Счетчик переходов состояний по инструменту. +`agent_workflow_duration_seconds` - Гистограмма времени, проведенного в каждом состоянии. +`agent_state_availability` - Показатель количества доступных инструментов для каждого состояния. + +**Метрики безопасности:** +`agent_group_access_denied_total` - Счетчик несанкционированного доступа к группам. +`agent_invalid_state_transition_total` - Счетчик недопустимых переходов состояний. +`agent_privilege_escalation_attempts_total` - Счетчик подозрительных запросов. + +#### 8.2 Улучшения ведения журнала + +**Ведение журнала запросов:** +```json +{ + "request_id": "req-123", + "requested_groups": ["read-only", "knowledge"], + "initial_state": "undefined", + "state_transitions": [ + {"tool": "knowledge-query", "from": "undefined", "to": "analysis", "timestamp": "2024-01-01T10:00:01Z"} + ], + "available_tools": ["knowledge-query", "text-completion"], + "filtered_by_group": ["graph-update", "admin-tool"], + "filtered_by_state": [], + "execution_time": "1.2s" +} +``` + +### 9. Стратегия тестирования + +#### 9.1 Юнит-тесты + +**Логика фильтрации инструментов:** +Расчет пересечений тестовых групп +Логика фильтрации на основе состояния теста +Проверка назначения групп и состояний по умолчанию +Тестирование поведения групп с подстановочными знаками +Проверка обработки пустых групп +Тестирование сценариев комбинированной фильтрации групп и состояний + +**Проверка конфигурации:** +Тестирование загрузки инструментов с различными конфигурациями групп и состояний +Проверка валидации схемы для неверных спецификаций групп и состояний +Тестирование обратной совместимости с существующими конфигурациями +Проверка определений и циклов переходов состояний + +#### 9.2 Интеграционные тесты + +**Поведение агента:** +Проверка того, что агенты видят только инструменты, отфильтрованные по группам и состояниям +Тестирование выполнения запросов с различными комбинациями групп +Тестирование переходов состояний во время выполнения агентом +Проверка обработки ошибок, когда ни один инструмент недоступен +Тестирование прогресса рабочего процесса через несколько состояний + +**Тестирование безопасности:** +Тестирование предотвращения повышения привилегий +Проверка точности журнала аудита +Тестирование интеграции шлюза с разрешениями пользователей + +#### 9.3 Сценарии сквозного тестирования + +**Многопользовательское использование с рабочими процессами состояний:** +``` +Scenario: Different users with different tool access and workflow states +Given: User A has "read-only" permissions, state "undefined" + And: User B has "write" permissions, state "analysis" +When: Both request knowledge operations +Then: User A gets read-only tools available in "undefined" state + And: User B gets write tools available in "analysis" state + And: State transitions are tracked per user session + And: All usage and transitions are properly audited +``` + +**Прогрессия состояний рабочего процесса:** +``` +Scenario: Complete workflow execution +Given: Request with groups ["knowledge", "compute"] and state "undefined" +When: Agent executes knowledge-query tool (transitions to "analysis") + And: Agent executes complex-analysis tool (transitions to "results") + And: Agent executes reset-workflow tool (transitions to "undefined") +Then: Each step has correctly filtered available tools + And: State transitions are logged with timestamps + And: Final state allows initial workflow to repeat +``` + +### 10. Соображения производительности + +#### 10.1 Влияние загрузки инструментов + +**Загрузка конфигурации:** +Метаданные группы и состояния загружаются один раз при запуске +Минимальные накладные расходы памяти на каждый инструмент (дополнительные поля) +Отсутствие влияния на время инициализации инструмента + +**Обработка запросов:** +Объединенная фильтрация группы+состояния выполняется один раз для каждого запроса +Сложность O(n), где n = количество настроенных инструментов +Переходы состояний добавляют минимальные накладные расходы (назначение строки) +Незначительное влияние для типичного количества инструментов (< 100) + +#### 10.2 Стратегии оптимизации + +**Предварительно вычисленные наборы инструментов:** +Кэширование наборов инструментов по комбинации группа+состояние +Избежание повторной фильтрации для распространенных шаблонов группы/состояния +Компромисс между памятью и вычислениями для часто используемых комбинаций + +**Отложенная загрузка:** +Загрузка реализаций инструментов только при необходимости +Уменьшение времени запуска для развертываний с большим количеством инструментов +Динамическая регистрация инструментов на основе требований группы + +### 11. Будущие улучшения + +#### 11.1 Динамическое назначение групп + +**Группировка, учитывающая контекст:** +Назначение инструментов группам на основе контекста запроса +Доступность групп во времени (только в рабочее время) +Ограничения групп на основе нагрузки (дорогие инструменты при низком использовании) + +#### 11.2 Иерархии групп + +**Вложенная структура групп:** +```json +{ + "knowledge": { + "read": ["knowledge-query", "entity-search"], + "write": ["graph-update", "entity-create"] + } +} +``` + +#### 11.3 Рекомендации по инструментам + +**Предложения, основанные на группах:** +Предлагать оптимальные группы инструментов для типов запросов. +Учиться на основе моделей использования для улучшения рекомендаций. +Предоставлять резервные группы, когда предпочитаемые инструменты недоступны. + +### 12. Открытые вопросы + +1. **Проверка групп**: Должны ли недопустимые имена групп в запросах вызывать критические ошибки или предупреждения? + +2. **Обнаружение групп**: Должна ли система предоставлять API для перечисления доступных групп и их инструментов? + +3. **Динамические группы**: Должны ли группы быть настраиваемыми во время выполнения или только при запуске? + +4. **Наследование групп**: Должны ли инструменты наследовать группы от своих родительских категорий или реализаций? + +5. **Мониторинг производительности**: Какие дополнительные метрики необходимы для эффективного отслеживания использования инструментов на основе групп? + +### 13. Заключение + +Система групп инструментов обеспечивает: + +**Безопасность**: Гранулярный контроль доступа к возможностям агента. +**Производительность**: Снижение накладных расходов на загрузку и выбор инструментов. +**Гибкость**: Многомерная классификация инструментов. +**Совместимость**: Бесшовная интеграция с существующими архитектурами агентов. + +Эта система позволяет развертываниям TrustGraph лучше управлять доступом к инструментам, улучшать границы безопасности и оптимизировать использование ресурсов, сохраняя полную обратную совместимость с существующими конфигурациями и запросами. diff --git a/docs/tech-specs/tool-group.sw.md b/docs/tech-specs/tool-group.sw.md new file mode 100644 index 00000000..d2fd7044 --- /dev/null +++ b/docs/tech-specs/tool-group.sw.md @@ -0,0 +1,491 @@ +# Mfumo wa Kikundi cha Zana za TrustGraph +## Maelezo ya Kiufundi v1.0 + +### Muhtasari + +Maelezo haya yanafafanua mfumo wa kuunganisha zana kwa wakala wa TrustGraph ambao huruhusu udhibiti wa kina kuhusu zana zipi zinazopatikana kwa ombi fulani. Mfumo huu huleta uchujaji wa zana unaotegemea kikundi kupitia usanidi na maelezo ya ombi, na hivyo kuwezesha mipaka bora ya usalama, usimamizi wa rasilimali, na ugawaji wa kazi wa uwezo wa wakala. + +### 1. Muhtasari + +#### 1.1 Tatizo + +Kwa sasa, wakala wa TrustGraph wana uwezo wa kutumia zana zote zilizosanidiwa, bila kujali muktadha wa ombi au mahitaji ya usalama. Hii huleta changamoto kadhaa: + +**Hatari ya Usalama**: Zana nyeti (k.m., uhariri wa data) zinapatikana hata kwa maswali ya kusoma tu. +**Uharibifu wa Rasilimali**: Zana ngumu huzingirwa hata wakati maswali rahisi hayahitaji. +**Uchanganyifu wa Kazi**: Wakala wanaweza kuchagua zana zisizofaa wakati mbadala rahisi zipo. +**Tenganisho la Wafanyabiashara Wengi**: Makundi tofauti ya watumiaji yanahitaji ufikiaji wa seti tofauti za zana. + +#### 1.2 Muhtasari wa Suluhisho + +Mfumo wa kikundi cha zana huleta: + +1. **Uainishaji wa Kikundi**: Zana huwekwa alama na uanachama wa kikundi wakati wa usanidi. +2. **Uchujaji wa Kwenye Ombi**: Ombi la Wakala (AgentRequest) linaonyesha ambayo makundi ya zana yanaruhusiwa. +3. **Utendaji wa Wakati Halisi**: Wakala wana uwezo wa kutumia zana zinazolingana na makundi yaliyoomba. +4. **Uunganishaji Wenye Ugumu**: Zana zinaweza kuwa katika makundi mengi kwa hali ngumu. + +### 2. Mabadiliko ya Muundo + +#### 2.1 Ongezeko la Muundo wa Usanidi wa Zana + +Usanidi wa zana uliopo umeongezwa na sehemu `group`: + +**Kabla:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph" +} +``` + +**Baada ya:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"] +} +``` + +**Maelezo ya Kundi:** +`group`: Array(String) - Orodha ya vikundi ambavyo zana hii inahusishwa nayo. +**Hiari:** Zana ambazo hazina uwanja wa kundi huenda katika kundi "linaloepuka". +**Uanachama wa mengi:** Zana zinaweza kuhusishwa na vikundi vingi. +**Huwezi kubadilishwa (Case-sensitive):** Majina ya vikundi ni mechi kamili ya herufi. + +#### 2.1.2 Kuboresha Mabadiliko ya Hali ya Zana + +Zana zinaweza, kwa hiari, kutaja mabadiliko ya hali na upatikanaji unaotegemea hali: + +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"], + "state": "analysis", + "available_in_states": ["undefined", "research"] +} +``` + +**Maelezo ya Kikoa:** +`state`: String - **Hiari** - Hali ya kuhamia baada ya utekelezaji wa zana. +`available_in_states`: Array(String) - **Hiari** - Hali ambazo zana hii inapatikana. +**Tabia ya kawaida**: Zana ambazo hazina `available_in_states` zinapatikana katika hali zote. +**Mabadiliko ya hali**: Hutokea tu baada ya utekelezaji wa zana. + +#### 2.2 Uboreshaji wa Mfumo wa AgentRequest + +Mfumo wa `AgentRequest` katika `trustgraph-base/trustgraph/schema/services/agent.py` umeboreshwa: + +**AgentRequest ya Sasa:** +`question`: String - Uliza wa mtumiaji. +`plan`: String - Mpango wa utekelezaji (unaweza kuondolewa). +`state`: String - Hali ya wakala. +`history`: Array(AgentStep) - Historia ya utekelezaji. + +**AgentRequest Iliyoboreshwa:** +`question`: String - Uliza wa mtumiaji. +`state`: String - Hali ya utekelezaji wa wakala (sasa inatumika kikamilifu kwa kuchuja zana). +`history`: Array(AgentStep) - Historia ya utekelezaji. +`group`: Array(String) - **MPYA** - Vikundi vya zana ambavyo vinaruhusiwa kwa ombi hili. + +**Mabadiliko ya Mfumo:** +**Imeondolewa**: Uwanja wa `plan` hauhitajiki tena na unaweza kuondolewa (hapo awali ulikuwa umekusudiwa kwa vipimo vya zana). +**Imeongezwa**: Uwanja wa `group` kwa vipimo vya kikundi cha zana. +**Imeboreshwa**: Uwanja wa `state` sasa unadhibiti upatikanaji wa zana wakati wa utekelezaji. + +**Tabia za Uwanja:** + +**Kikundi cha Uwanja:** +**Hiari**: Ikiwa haijaainishwa, huanguka kwenye ["default"]. +**Uunganishaji**: Zana zinazofanana na angalau kikundi kilichoainishwa ndizo zinazopatikana. +**Safisha ya tupu**: Hakuna zana zinazopatikana (wakala anaweza kutumia tu utafakari wa ndani). +**Kikundi cha "Wildcard"**: Kikundi maalum "*" kinatoa ufikiaji kwa zana zote. + +**Uwanja wa Hali:** +**Hiari**: Ikiwa haijaainishwa, huanguka kwenye "haijulikani". +**Uchujaji wa msingi wa hali**: Zana zinazopatikana katika hali ya sasa ndizo zinazoweza kutumika. +**Hali ya kawaida**: Hali ya "haijulikani" inaruhusu zana zote (kulingana na uchujaji wa kikundi). +**Mabadiliko ya hali**: Zana zinaweza kubadilisha hali baada ya utekelezaji wa mafanikio. + +### 3. Mifano ya Kikundi Maalum + +Mashirika yanaweza kuainisha vikundi maalum ya kikoa: + +```json +{ + "financial-tools": ["stock-query", "portfolio-analysis"], + "medical-tools": ["diagnosis-assist", "drug-interaction"], + "legal-tools": ["contract-analysis", "case-search"] +} +``` + +### 4. Maelezo ya Utendaji + +#### 4.1 Kupakia na Kuchuja Vifaa + +**Awamu ya Usanidi:** +1. Vifaa vyote hupakuliwa kutoka usanidi pamoja na uamlisho wao wa kundi. +2. Vifaa visivyokuwa na uamlisho wa kundi wanakabidhiwa kwenye kundi la "default". +3. Uanachama wa kundi huthibitishwa na kuhifadhiwa kwenye rejista ya vifaa. + +**Awamu ya Usimamizi wa Ombi:** +1. Ombi la Wakala (AgentRequest) linafika pamoja na maelezo ya kundi (group) ambayo ni ya hiari. +2. Wakala huchuja vifaa vinavyopatikana kulingana na msalaba wa makundi. +3. Vifaa vinavyolingana pekee hupitishwa kwa muktadha wa utekelezaji wa wakala. +4. Wakala hutumia seti ya vifaa vilivyochujwa katika mchakato wote wa ombi. + +#### 4.2 Mantiki ya Kuchuja Vifaa + +**Kuchuja kwa Pamoja kwa Kundi na Hali:** + +``` +For each configured tool: + tool_groups = tool.group || ["default"] + tool_states = tool.available_in_states || ["*"] // Available in all states + +For each request: + requested_groups = request.group || ["default"] + current_state = request.state || "undefined" + +Tool is available if: + // Group filtering + (intersection(tool_groups, requested_groups) is not empty OR "*" in requested_groups) + AND + // State filtering + (current_state in tool_states OR "*" in tool_states) +``` + +**Mantiki ya Mabadiliko ya Hali:** + +``` +After successful tool execution: + if tool.state is defined: + next_request.state = tool.state + else: + next_request.state = current_request.state // No change +``` + +#### 4.3 Maeneo ya Uunganisho wa Mwakala + +**Mwakala wa ReAct:** +Uchujaji wa zana hufanyika katika `agent_manager.py` wakati wa uundaji wa usajili wa zana. +Orodha ya zana zinazopatikana huchujwa na kikundi na hali kabla ya utayarishaji wa mpango. +Mabadiliko ya hali husasisha sehemu `AgentRequest.state` baada ya utekelezaji wa zana kwa mafanikio. +Iteration inayofuata hutumia hali iliyosasishwa kwa uchujaji wa zana. + +**Mwakala Kulingana na Umoja wa Maoni:** +Uchujaji wa zana hufanyika katika `planner.py` wakati wa utayarishaji wa mpango. +Uthibitisho wa `ExecutionStep` huhakikisha kuwa zana zinazofaa tu za kikundi na hali hutumiwa. +Kidhibiti cha mtiririko huweka upatikanaji wa zana wakati wa utendakazi. +Mabadiliko ya hali yanadhibitiwa na Kidhibiti cha Mtiririko kati ya hatua. + +### 5. Mifano ya Usanidi + +#### 5.1 Usanidi wa Zana na Vikundi na Hali + +```yaml +tool: + knowledge-query: + type: knowledge-query + name: "Knowledge Graph Query" + description: "Query the knowledge graph for entities and relationships" + group: ["read-only", "knowledge", "basic"] + state: "analysis" + available_in_states: ["undefined", "research"] + + graph-update: + type: graph-update + name: "Graph Update" + description: "Add or modify entities in the knowledge graph" + group: ["write", "knowledge", "admin"] + available_in_states: ["analysis", "modification"] + + text-completion: + type: text-completion + name: "Text Completion" + description: "Generate text using language models" + group: ["read-only", "text", "basic"] + state: "undefined" + # No available_in_states = available in all states + + complex-analysis: + type: mcp-tool + name: "Complex Analysis Tool" + description: "Perform complex data analysis" + group: ["advanced", "compute", "expensive"] + state: "results" + available_in_states: ["analysis"] + mcp_tool_id: "analysis-server" + + reset-workflow: + type: mcp-tool + name: "Reset Workflow" + description: "Reset to initial state" + group: ["admin"] + state: "undefined" + available_in_states: ["analysis", "results"] +``` + +#### 5.2 Mifano ya Maombi na Mchakato wa Kazi wa Jimbo + +**Maombi ya Uchunguzi wa Mwanzo:** +```json +{ + "question": "What entities are connected to Company X?", + "group": ["read-only", "knowledge"], + "state": "undefined" +} +``` +*Vifaa vinavyopatikana: knowledge-query, text-completion* +*Baada ya knowledge-query: hali → "uchambuzi"* + +**Awamu ya Uchambuzi:** +```json +{ + "question": "Continue analysis based on previous results", + "group": ["advanced", "compute", "write"], + "state": "analysis" +} +``` +*Vifaa vinavyopatikana: uchambuzi-wa-mazingo, sasisho-la-picha, upya-mchakato* +*Baada ya uchambuzi-wa-mazingo: hali → "matokeo"* + +**Awamu ya Matokeo:** +```json +{ + "question": "What should I do with these results?", + "group": ["admin"], + "state": "results" +} +``` +*Vifaa vinavyopatikana: reset-workflow pekee* +*Baada ya reset-workflow: hali → "haijulikani"* + +**Mfano wa Mchakato - Mchakato Kamili:** +1. **Anza (haijulikani)**: Tumia utafutaji wa maarifa → mabadiliko hadi "uchambuzi" +2. **Hali ya uchambuzi**: Tumia uchambuzi tata → mabadiliko hadi "matokeo" +3. **Hali ya matokeo**: Tumia reset-workflow → mabadiliko kurudi "haijulikani" +4. **Kurudi kwenye mwanzo**: Vifaa vyote vya awali vinapatikana tena + +### 6. Masuala ya Usalama + +#### 6.1 Uunganisho wa Udhibiti wa Ufikiaji + +**Uchujaji wa Kawaida ya Mawasiliano:** +Kawaida ya mawasiliano inaweza kutekeleza vizuizi vya kikundi kulingana na ruhusa za mtumiaji +Kuzuia ongezeko la madaraka kupitia ubadilishaji wa ombi +Rekodi ya ukaguzi inajumuisha vikundi vya vifaa vilivyoomba na vilivyokabidhiwa + +**Mfano wa Mantiki ya Kawaida ya Mawasiliano:** +``` +user_permissions = get_user_permissions(request.user_id) +allowed_groups = user_permissions.tool_groups +requested_groups = request.group + +# Validate request doesn't exceed permissions +if not is_subset(requested_groups, allowed_groups): + reject_request("Insufficient permissions for requested tool groups") +``` + +#### 6.2 Ukaguzi na Ufuatiliaji + +**Ukaguzi Ulioboreshwa:** +Kurekodi vikundi vya zana vilivyoomba na hali ya awali kwa kila ombi +Kufuatilia mabadiliko ya hali na matumizi ya zana kwa kila kundi +Kufuatilia majaribio ya kupata vikundi bila ruhusa na mabadiliko ya hali yasiyofaa +Kutoa arifa kuhusu mifumo isiyo ya kawaida ya matumizi ya kundi au mchakato wa hali unaotishiwa + +### 7. Mkakati wa Uhamisho + +#### 7.1 Ulinganifu na Mifumo ya Zamani + +**Awamu ya 1: Mabadiliko ya Ongezeko** +Ongeza sehemu ya `group` ya hiari kwenye usanidi wa zana +Ongeza sehemu ya `group` ya hiari kwenye schema ya AgentRequest +Tabia ya chagu ya: Zana zote zilizopo zinahusishwa na kundi "linalingana" +Maombi yaliyopo bila sehemu ya kundi hutumia kundi "linalingana" + +**Tabia Zilizopo Zinahifadhiwa:** +Zana ambazo hazina usanidi wa kundi zinaendelea kufanya kazi (kundi linalingana) +Zana ambazo hazina usanidi wa hali zinapatikana katika hali zote +Maombi ambayo hayajainisha kundi hupata zana zote (kundi linalingana) +Maombi ambayo hayajainisha hali hutumia hali "isiyojulikana" (zana zote zinapatikana) +Hakuna mabadiliko yanayoweza kusababisha hitilafu katika matumizi yaliyopo + +### 8. Ufuatiliaji na Uonevu + +#### 8.1 Vipimo Vipya + +**Matumizi ya Kundi la Zana:** +`agent_tool_group_requests_total` - Idadi ya maombi kwa kila kundi +`agent_tool_group_availability` - Kiwango cha zana zinazopatikana kwa kila kundi +`agent_filtered_tools_count` - Jadili ya idadi ya zana baada ya kuchujwa kwa kundi na hali + +**Vipimo vya Mchakato wa Hali:** +`agent_state_transitions_total` - Idadi ya mabadiliko ya hali kwa kila zana +`agent_workflow_duration_seconds` - Jadili ya muda uliotumika katika kila hali +`agent_state_availability` - Kiwango cha zana zinazopatikana kwa kila hali + +**Vipimo vya Usalama:** +`agent_group_access_denied_total` - Idadi ya upataji usioidhinishwa wa kundi +`agent_invalid_state_transition_total` - Idadi ya mabadiliko ya hali yasiyofaa +`agent_privilege_escalation_attempts_total` - Idadi ya maombi yanayoshukiwa + +#### 8.2 Uboreshaji wa Kurekodi + +**Kurekodi ya Maombi:** +```json +{ + "request_id": "req-123", + "requested_groups": ["read-only", "knowledge"], + "initial_state": "undefined", + "state_transitions": [ + {"tool": "knowledge-query", "from": "undefined", "to": "analysis", "timestamp": "2024-01-01T10:00:01Z"} + ], + "available_tools": ["knowledge-query", "text-completion"], + "filtered_by_group": ["graph-update", "admin-tool"], + "filtered_by_state": [], + "execution_time": "1.2s" +} +``` + +### 9. Mbinu ya Majaribio + +#### 9.1 Majaribio ya Kitengo + +**Mantiki ya Kuchuja Zana:** +Majaribio ya hesabu za makutano ya vikundi +Majaribio ya mantiki ya kuchuja kulingana na hali +Thibitisha utoaji wa kikundi na hali chagu +Majaribio ya tabia ya kikundi cha "wildcard" +Thibitisha usimamizi wa kikundi tupu +Majaribio ya hali ya kuchuja iliyounganisha kikundi+hali + +**Uthibitisho wa Usanidi:** +Majaribio ya kupakia zana pamoja na usanidi mbalimbali wa kikundi na hali +Thibitisha uthibitisho wa schema kwa vipimo visivyo sahihi vya kikundi na hali +Majaribio ya utangamano wa nyuma na usanidi uliopo +Thibitisha ufafanuzi na mizunguko ya mabadiliko ya hali + +#### 9.2 Majaribio ya Uunganisho + +**Tabia ya Wakala:** +Thibitisha kwamba wakala huona tu zana zilizochujwa kwa kikundi+hali +Majaribio ya utekelezaji wa ombi kwa mchanganyiko mbalimbali wa vikundi +Majaribio ya mabadiliko ya hali wakati wa utekelezaji wa wakala +Thibitisha usimamizi wa makosa wakati hakuna zana zinazopatikana +Majaribio ya maendeleo ya mtiririko wa kazi kupitia hali nyingi + +**Majaribio ya Usalama:** +Majaribio ya kuzuia kupanda kwa madaraka +Thibitisha usahihi wa njia ya ukaguzi +Majaribio ya ujumuishaji wa lango pamoja na ruhusa za mtumiaji + +#### 9.3 Hali za Jumla + +**Matumizi ya Mfumo Mwingi Pamoja na Mitiririko ya Kazi ya Hali:** +``` +Scenario: Different users with different tool access and workflow states +Given: User A has "read-only" permissions, state "undefined" + And: User B has "write" permissions, state "analysis" +When: Both request knowledge operations +Then: User A gets read-only tools available in "undefined" state + And: User B gets write tools available in "analysis" state + And: State transitions are tracked per user session + And: All usage and transitions are properly audited +``` + +**Maendeleo ya Hatua ya Mchakato:** +``` +Scenario: Complete workflow execution +Given: Request with groups ["knowledge", "compute"] and state "undefined" +When: Agent executes knowledge-query tool (transitions to "analysis") + And: Agent executes complex-analysis tool (transitions to "results") + And: Agent executes reset-workflow tool (transitions to "undefined") +Then: Each step has correctly filtered available tools + And: State transitions are logged with timestamps + And: Final state allows initial workflow to repeat +``` + +### 10. Mambo Muhimu ya Utendaji + +#### 10.1 Athari ya Kuanzisha Zana + +**Uteuzi wa Vipimo:** +Meta data ya kikundi na hali huwekwa mara moja wakati wa kuanzishwa +Uwezekano mdogo wa matumizi ya kumbukumbu kwa kila zana (nafasi za ziada) +Hakuna athari kwenye muda wa kuanzisha zana + +**Uchakataji wa Maombi:** +Kuchujwa kwa pamoja kwa kikundi + hali hufanyika mara moja kwa kila ombi +Ufumbuzi wa O(n) ambapo n = idadi ya zana zilizosanidiwa +Mabadiliko ya hali huongeza uwezekano mdogo (utambulisho wa herufi) +Athari ndogo kwa idadi ya kawaida ya zana (< 100) + +#### 10.2 Mikakati ya Ubora + +**Kikundi cha Zana Zilizopangwa Mapema:** +Hifadhi vikundi vya zana kwa kila mchanganyiko wa kikundi + hali +Epuka kuchujwa mara kwa mara kwa mifumo ya kawaida ya kikundi/hali +Usawa kati ya kumbukumbu na hesabu kwa mchanganyiko unaotumika mara kwa mara + +**Kupakua kwa Kila Matumizi:** +Pakua matumizi ya zana tu wakati inahitajika +Punguza muda wa kuanzishwa kwa matumizi ambayo yana zana nyingi +Usajili wa zana kwa njia ya moja kwa moja kulingana na mahitaji ya kikundi + +### 11. Maboresho ya Baadaye + +#### 11.1 Uteuzi wa Kikundi wa Kila Muda + +**Uteuzi wa Kikundi Kulingana na Mazingira:** +Weka zana katika vikundi kulingana na mazingira ya ombi +Upatikanaji wa kikundi kulingana na wakati (sawa za biashara tu) +Marekebisho ya kikundi kulingana na mzigo (zana ghali wakati wa matumizi kidogo) + +#### 11.2 Hierarkia za Kikundi + +**Muundo Ulioingilishwa wa Kikundi:** +```json +{ + "knowledge": { + "read": ["knowledge-query", "entity-search"], + "write": ["graph-update", "entity-create"] + } +} +``` + +#### 11.3 Mapendekezo ya Zana + +**Mapendekezo Kulingana na Kikundi:** +Pendekeza vikundi bora vya zana kwa aina za ombi. +Jifunze kutoka kwa mitindo ya matumizi ili kuboresha mapendekezo. +Toa vikundi vya dharura wakati zana zinazopendekezwa hazipatikani. + +### 12. Maswali ya Kufungua + +1. **Uthibitisho wa Kikundi**: Je, majina ya vikundi yasiyo halali katika maombi yanapaswa kusababisha hitilafu kubwa au onyo? + +2. **Udagano wa Kikundi**: Je, mfumo unapaswa kutoa API ili kuorodhesha vikundi vinavyopatikana na zana zao? + +3. **Vikundi vya Njia Moja Moja**: Je, vikundi vinapaswa kupangwa wakati wa utendaji au wakati wa kuanzishwa tu? + +4. **Urithi wa Kikundi**: Je, zana zinapaswa kurithi vikundi kutoka kwa makundi yao ya wazazi au matoleo? + +5. **Ufuatiliaji wa Utendaji**: Ni vipimo vipi vya ziada vinavyohitajika kufuatilia matumizi ya zana kulingana na vikundi kwa ufanisi? + +### 13. Hitimisho + +Mfumo wa vikundi vya zana hutoa: + +**Usalama**: Udhibiti wa kina wa ufikiaji wa uwezo wa wakala. +**Utendaji**: Kupunguza mzigo wa kupakua na kuchagua zana. +**Unyumbufu**: Uainishaji wa zana wa mwelekeo mwingi. +**Ulinganifu**: Ujumuishaji laini na miundo ya wakala iliyopo. + +Mfumo huu huruhusu usakinishaji wa TrustGraph kusimamia ufikiaji wa zana vizuri zaidi, kuboresha mipaka ya usalama, na kuongeza matumizi ya rasilimali huku ikiendelea kuwa na ulinganifu kamili na usanidi na maombi iliyopo. diff --git a/docs/tech-specs/tool-group.tr.md b/docs/tech-specs/tool-group.tr.md new file mode 100644 index 00000000..fc325ded --- /dev/null +++ b/docs/tech-specs/tool-group.tr.md @@ -0,0 +1,491 @@ +# TrustGraph Araç Grubu Sistemi +## Teknik Özellikler v1.0 + +### Yönetici Özeti + +Bu özellik, TrustGraph ajanları için, belirli istekler için hangi araçların kullanılabilir olduğuna ince ayar yapılmasına olanak tanıyan bir araç gruplama sistemi tanımlar. Sistem, yapılandırma ve istek düzeyinde belirtme yoluyla, grup tabanlı araç filtrelemesi sunarak, daha iyi güvenlik sınırları, kaynak yönetimi ve ajan yeteneklerinin işlevsel ayrımı sağlar. + +### 1. Genel Bakış + +#### 1.1 Problem Tanımı + +Şu anda, TrustGraph ajanları, istek bağlamı veya güvenlik gereksinimlerinden bağımsız olarak, yapılandırılmış tüm araçlara erişebilir. Bu, çeşitli zorluklara yol açmaktadır: + +**Güvenlik Riski**: Hassas araçlar (örneğin, veri değişikliği), yalnızca okuma istekleri için bile kullanılabilir. +**Kaynak İsrafı**: Karmaşık araçlar, basit istekler için gerekli olmadığında bile yüklenir. +**İşlevsel Karmaşa**: Ajanlar, daha basit alternatifler varken, uygun olmayan araçları seçebilir. +**Çok Kiracılı İzolasyon**: Farklı kullanıcı gruplarının farklı araç setlerine erişmesi gerekir. + +#### 1.2 Çözümün Genel Bakışı + +Araç grubu sistemi aşağıdaki özellikleri sunar: + +1. **Grup Sınıflandırması**: Araçlar, yapılandırma sırasında grup üyelikleriyle etiketlenir. +2. **İstek Düzeyinde Filtreleme**: AgentRequest, hangi araç gruplarının izinli olduğunu belirtir. +3. **Çalışma Zamanı Uygulaması**: Ajanlar, yalnızca istenen gruplarla eşleşen araçlara erişebilir. +4. **Esnek Gruplandırma**: Araçlar, karmaşık senaryolar için birden fazla gruba ait olabilir. + +### 2. Şema Değişiklikleri + +#### 2.1 Araç Yapılandırma Şeması Geliştirmesi + +Mevcut araç yapılandırması, bir `group` alanı ile geliştirilmiştir: + +**Önce:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph" +} +``` + +**Sonra:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"] +} +``` + +**Grup Alanı Tanımlaması:** +`group`: Array(String) - Bu aracın ait olduğu grupların listesi +**İsteğe Bağlı:** Grup alanı olmayan araçlar, "varsayılan" gruba aittir +**Çoklu Üyelik:** Araçlar, birden fazla gruba ait olabilir +**Büyük/Küçük Harf Duyarlılığı:** Grup adları, tam string eşleşmeleridir + +#### 2.1.2 Araç Durum Geçişi Geliştirmesi + +Araçlar, isteğe bağlı olarak durum geçişlerini ve duruma bağlı kullanılabilirliği belirtebilir: + +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"], + "state": "analysis", + "available_in_states": ["undefined", "research"] +} +``` + +**Durum Alanı Tanımlaması:** +`state`: String - **İsteğe bağlı** - Başarılı araç çalıştırması sonrasında geçilecek durum +`available_in_states`: Array(String) - **İsteğe bağlı** - Bu aracın mevcut olduğu durumlar +**Varsayılan davranış:** `available_in_states` değeri olmayan araçlar, tüm durumlarda kullanılabilir +**Durum geçişi:** Sadece başarılı araç çalıştırması sonrasında gerçekleşir + +#### 2.2 AgentRequest Şema Geliştirmesi + +`trustgraph-base/trustgraph/schema/services/agent.py` içindeki `AgentRequest` şeması geliştirilmiştir: + +**Mevcut AgentRequest:** +`question`: String - Kullanıcı sorgusu +`plan`: String - Çalıştırma planı (kaldırılabilir) +`state`: String - Ajan durumu +`history`: Array(AgentStep) - Çalıştırma geçmişi + +**Geliştirilmiş AgentRequest:** +`question`: String - Kullanıcı sorgusu +`state`: String - Ajan çalıştırma durumu (artık araç filtreleme için aktif olarak kullanılıyor) +`history`: Array(AgentStep) - Çalıştırma geçmişi +`group`: Array(String) - **YENİ** - Bu istek için izin verilen araç grupları + +**Şema Değişiklikleri:** +**Kaldırıldı:** `plan` alanı artık gerekli değildir ve kaldırılabilir (başlangıçta araç belirtimi için tasarlanmıştı) +**Eklendi:** Araç grubu belirtimi için `group` alanı +**Geliştirildi:** `state` alanı artık çalıştırma sırasında araç kullanılabilirliğini kontrol eder + +**Alan Davranışları:** + +**Grup Alanı:** +**İsteğe bağlı:** Belirtilmezse, varsayılan olarak ["default"] değerini alır +**Kesişim:** Sadece en az bir belirtilen grupla eşleşen araçlar kullanılabilir +**Boş dizi:** Hiçbir araç kullanılamaz (ajan yalnızca dahili akıl yürütmeyi kullanabilir) +**Yıldız işareti:** Özel "*" grubu, tüm araçlara erişim sağlar + +**Durum Alanı:** +**İsteğe bağlı:** Belirtilmezse, varsayılan olarak "undefined" değerini alır +**Durum tabanlı filtreleme:** Yalnızca mevcut durumda bulunan araçlar uygun olabilir +**Varsayılan durum:** "undefined" durumu, tüm araçlara izin verir (grup filtrelemesine tabidir) +**Durum geçişleri:** Araçlar, başarılı çalıştırmadan sonra durumu değiştirebilir + +### 3. Özel Grup Örnekleri + +Kuruluşlar, alanla ilgili özel gruplar tanımlayabilir: + +```json +{ + "financial-tools": ["stock-query", "portfolio-analysis"], + "medical-tools": ["diagnosis-assist", "drug-interaction"], + "legal-tools": ["contract-analysis", "case-search"] +} +``` + +### 4. Uygulama Detayları + +#### 4.1 Araç Yükleme ve Filtreleme + +**Yapılandırma Aşaması:** +1. Tüm araçlar, grup atamalarıyla birlikte yapılandırmadan yüklenir. +2. Açık bir grup atanmamış araçlar, "varsayılan" gruba atanır. +3. Grup üyeliği doğrulanır ve araç kaydında saklanır. + +**İstek İşleme Aşaması:** +1. İsteğe bağlı grup belirtimiyle birlikte AgentRequest gelir. +2. Agent, mevcut araçları grup kesişimi temelinde filtreler. +3. Yalnızca eşleşen araçlar, agent yürütme bağlamına iletilir. +4. Agent, istek yaşam döngüsü boyunca filtrelenmiş araç kümesiyle çalışır. + +#### 4.2 Araç Filtreleme Mantığı + +**Birleştirilmiş Grup ve Durum Filtreleme:** + +``` +For each configured tool: + tool_groups = tool.group || ["default"] + tool_states = tool.available_in_states || ["*"] // Available in all states + +For each request: + requested_groups = request.group || ["default"] + current_state = request.state || "undefined" + +Tool is available if: + // Group filtering + (intersection(tool_groups, requested_groups) is not empty OR "*" in requested_groups) + AND + // State filtering + (current_state in tool_states OR "*" in tool_states) +``` + +**Durum Geçişi Mantığı:** + +``` +After successful tool execution: + if tool.state is defined: + next_request.state = tool.state + else: + next_request.state = current_request.state // No change +``` + +#### 4.3 Ajan Entegrasyon Noktaları + +**ReAct Ajanı:** +Araç filtrelemesi, araç kaydı oluşturulurken agent_manager.py dosyasında gerçekleşir. +Kullanılabilir araçlar listesi, plan oluşturulmadan önce hem grup hem de duruma göre filtrelenir. +Durum geçişleri, başarılı araç çalıştırması sonrasında AgentRequest.state alanını günceller. +Bir sonraki yineleme, araç filtrelemesi için güncellenmiş durumu kullanır. + +**Güvenilirlik Tabanlı Ajan:** +Araç filtrelemesi, plan oluşturulurken planner.py dosyasında gerçekleşir. +ExecutionStep doğrulama, yalnızca grup+durum uygun araçların kullanıldığından emin olur. +Akış denetleyicisi, çalışma zamanında araç kullanılabilirliğini zorlar. +Durum geçişleri, adımlar arasında Akış Denetleyicisi tarafından yönetilir. + +### 5. Yapılandırma Örnekleri + +#### 5.1 Gruplar ve Durumlarla Araç Yapılandırması + +```yaml +tool: + knowledge-query: + type: knowledge-query + name: "Knowledge Graph Query" + description: "Query the knowledge graph for entities and relationships" + group: ["read-only", "knowledge", "basic"] + state: "analysis" + available_in_states: ["undefined", "research"] + + graph-update: + type: graph-update + name: "Graph Update" + description: "Add or modify entities in the knowledge graph" + group: ["write", "knowledge", "admin"] + available_in_states: ["analysis", "modification"] + + text-completion: + type: text-completion + name: "Text Completion" + description: "Generate text using language models" + group: ["read-only", "text", "basic"] + state: "undefined" + # No available_in_states = available in all states + + complex-analysis: + type: mcp-tool + name: "Complex Analysis Tool" + description: "Perform complex data analysis" + group: ["advanced", "compute", "expensive"] + state: "results" + available_in_states: ["analysis"] + mcp_tool_id: "analysis-server" + + reset-workflow: + type: mcp-tool + name: "Reset Workflow" + description: "Reset to initial state" + group: ["admin"] + state: "undefined" + available_in_states: ["analysis", "results"] +``` + +#### 5.2 Durum İş Akışlarıyla Birlikte İstek Örnekleri + +**Başlangıç Araştırma İsteği:** +```json +{ + "question": "What entities are connected to Company X?", + "group": ["read-only", "knowledge"], + "state": "undefined" +} +``` +*Mevcut araçlar: knowledge-query, text-completion* +*knowledge-query işleminden sonra: durum → "analiz"* + +**Analiz Aşaması:** +```json +{ + "question": "Continue analysis based on previous results", + "group": ["advanced", "compute", "write"], + "state": "analysis" +} +``` +*Mevcut araçlar: karmaşık analiz, grafik güncelleme, iş akışı sıfırlama* +*Karmaşık analizden sonra: durum → "sonuçlar"* + +**Sonuçlar Aşaması:** +```json +{ + "question": "What should I do with these results?", + "group": ["admin"], + "state": "results" +} +``` +*Mevcut araçlar: yalnızca reset-workflow* +*reset-workflow'dan sonra: durum → "undefined"* + +**İş Akışı Örneği - Tam Akış:** +1. **Başlangıç (undefined):** knowledge-query kullanın → "analysis" durumuna geçiş yapar. +2. **Analiz durumu:** complex-analysis kullanın → "results" durumuna geçiş yapar. +3. **Sonuç durumu:** reset-workflow kullanın → "undefined" durumuna geri döner. +4. **Başlangıca dönüş:** Tüm başlangıç araçları tekrar kullanılabilir. + +### 6. Güvenlik Hususları + +#### 6.1 Erişim Kontrolü Entegrasyonu + +**Ağ Geçidi Seviyesinde Filtreleme:** +Ağ geçidi, kullanıcı izinlerine göre grup kısıtlamalarını uygulayabilir. +İstek manipülasyonu yoluyla yetki yükseltmesini engelleyin. +Denetim kaydı, istenen ve verilen araç gruplarını içerir. + +**Örnek Ağ Geçidi Mantığı:** +``` +user_permissions = get_user_permissions(request.user_id) +allowed_groups = user_permissions.tool_groups +requested_groups = request.group + +# Validate request doesn't exceed permissions +if not is_subset(requested_groups, allowed_groups): + reject_request("Insufficient permissions for requested tool groups") +``` + +#### 6.2 Denetim ve İzleme + +**Gelişmiş Denetim Kayıtları:** +İstenen araç gruplarını ve her istek için başlangıç durumunu kaydet. +Grup üyeliği tarafından durum geçişlerini ve araç kullanımını izle. +Yetkisiz grup erişim girişimlerini ve geçersiz durum geçişlerini izle. +Olağandışı grup kullanım kalıplarını veya şüpheli durum iş akışlarını tespit etme konusunda uyarı ver. + +### 7. Geçiş Stratejisi + +#### 7.1 Geriye Dönük Uyumluluk + +**1. Aşama: Eklemeler** +Araç yapılandırmalarına isteğe bağlı `group` alanı ekle. +AgentRequest şemasına isteğe bağlı `group` alanı ekle. +Varsayılan davranış: Tüm mevcut araçlar "varsayılan" grubuna aittir. +Grup alanı olmayan mevcut istekler "varsayılan" grubunu kullanır. + +**Mevcut Davranış Korunmuştur:** +Grup yapılandırması olmayan araçlar çalışmaya devam eder (varsayılan grup). +Durum yapılandırması olmayan araçlar tüm durumlarda kullanılabilir. +Grup belirtimi olmayan istekler tüm araçlara erişebilir (varsayılan grup). +Durum belirtimi olmayan istekler "belirsiz" durumu kullanır (tüm araçlar kullanılabilir). +Mevcut dağıtımlarda herhangi bir değişiklik yapılmamıştır. + +### 8. İzleme ve Gözlemlenebilirlik + +#### 8.1 Yeni Metrikler + +**Araç Grubu Kullanımı:** +`agent_tool_group_requests_total` - Grup başına istek sayısı. +`agent_tool_group_availability` - Grup başına kullanılabilir araç sayısı. +`agent_filtered_tools_count` - Grup+durum filtrelemesinden sonraki araç sayısı histogramı. + +**Durum İş Akışı Metrikleri:** +`agent_state_transitions_total` - Araç başına durum geçişleri sayısı. +`agent_workflow_duration_seconds` - Her durumda geçirilen süre histogramı. +`agent_state_availability` - Durum başına kullanılabilir araç sayısı. + +**Güvenlik Metrikleri:** +`agent_group_access_denied_total` - Yetkisiz grup erişim sayısı. +`agent_invalid_state_transition_total` - Geçersiz durum geçişleri sayısı. +`agent_privilege_escalation_attempts_total` - Şüpheli istekler sayısı. + +#### 8.2 Kayıt Güncellemeleri + +**İstek Kayıtları:** +```json +{ + "request_id": "req-123", + "requested_groups": ["read-only", "knowledge"], + "initial_state": "undefined", + "state_transitions": [ + {"tool": "knowledge-query", "from": "undefined", "to": "analysis", "timestamp": "2024-01-01T10:00:01Z"} + ], + "available_tools": ["knowledge-query", "text-completion"], + "filtered_by_group": ["graph-update", "admin-tool"], + "filtered_by_state": [], + "execution_time": "1.2s" +} +``` + +### 9. Test Stratejisi + +#### 9.1 Birim Testleri + +**Araç Filtreleme Mantığı:** +Test grubu kesişimi hesaplamaları +Test durumu tabanlı filtreleme mantığı +Varsayılan grup ve durum atamasını doğrulayın +Test joker karakterli grup davranışını +Boş grup işleme doğrulamasını +Test birleştirilmiş grup+durum filtreleme senaryolarını + +**Yapılandırma Doğrulama:** +Test farklı grup ve durum yapılandırmalarıyla araç yüklemeyi +Geçersiz grup ve durum tanımları için şema doğrulamasını +Test mevcut yapılandırmalarla geriye dönük uyumluluğu +Durum geçişi tanımlarını ve döngülerini doğrulayın + +#### 9.2 Entegrasyon Testleri + +**Ajan Davranışı:** +Ajanların yalnızca grup+durumla filtrelenmiş araçları gördüğünü doğrulayın +Test farklı grup kombinasyonlarıyla istek yürütmeyi +Ajan yürütülmesi sırasında durum geçişlerini test edin +Kullanılabilir araç olmadığında hata işleme doğrulamasını +Test çoklu durumlar aracılığıyla iş akışı ilerlemesini + +**Güvenlik Testleri:** +Test ayrıcalık yükseltme önlemini +Denetim kaydı doğruluğunu doğrulayın +Kullanıcı izinleriyle ağ geçidi entegrasyonunu test edin + +#### 9.3 Uçtan Uca Senaryolar + +**Durum İş Akışlarıyla Çok Kiracılı Kullanım:** +``` +Scenario: Different users with different tool access and workflow states +Given: User A has "read-only" permissions, state "undefined" + And: User B has "write" permissions, state "analysis" +When: Both request knowledge operations +Then: User A gets read-only tools available in "undefined" state + And: User B gets write tools available in "analysis" state + And: State transitions are tracked per user session + And: All usage and transitions are properly audited +``` + +**İş Akışı Durumu İlerlemesi:** +``` +Scenario: Complete workflow execution +Given: Request with groups ["knowledge", "compute"] and state "undefined" +When: Agent executes knowledge-query tool (transitions to "analysis") + And: Agent executes complex-analysis tool (transitions to "results") + And: Agent executes reset-workflow tool (transitions to "undefined") +Then: Each step has correctly filtered available tools + And: State transitions are logged with timestamps + And: Final state allows initial workflow to repeat +``` + +### 10. Performans Hususları + +#### 10.1 Araç Yükleme Etkisi + +**Yapılandırma Yükleme:** +Grup ve durum meta verileri, başlatmada yalnızca bir kez yüklenir. +Her araç için minimum bellek yükü (ek alanlar). +Araç başlatma süresi üzerinde herhangi bir etkisi yoktur. + +**İstek İşleme:** +Grup+durum filtrelemesi, her istek için yalnızca bir kez yapılır. +Yapılandırılmış araç sayısına (n) bağlı olarak O(n) karmaşıklığı. +Durum geçişleri, minimum bir yük ekler (dize ataması). +Tipik araç sayıları (< 100) için ihmal edilebilir bir etki. + +#### 10.2 Optimizasyon Stratejileri + +**Önceden Hesaplanan Araç Kümeleri:** +Araç kümelerini grup+durum kombinasyonuna göre önbelleğe alın. +Yaygın grup/durum kalıpları için tekrarlanan filtrelemeyi önleyin. +Sık kullanılan kombinasyonlar için bellek ve hesaplama arasında bir denge. + +**Gecikmeli Yükleme:** +Araç uygulamalarını yalnızca ihtiyaç duyulduğunda yükleyin. +Birçok araca sahip dağıtımların başlatma süresini azaltın. +Grup gereksinimlerine göre dinamik araç kaydı. + +### 11. Gelecekteki Geliştirmeler + +#### 11.1 Dinamik Grup Ataması + +**Bağlam Farkındalığına Sahip Gruplandırma:** +Araçları, istek bağlamına göre gruplara atayın. +Zaman tabanlı grup kullanılabilirliği (sadece iş saatleri). +Yük tabanlı grup kısıtlamaları (düşük kullanımda pahalı araçlar). + +#### 11.2 Grup Hiyerarşileri + +**İç İçe Geçmiş Grup Yapısı:** +```json +{ + "knowledge": { + "read": ["knowledge-query", "entity-search"], + "write": ["graph-update", "entity-create"] + } +} +``` + +#### 11.3 Araç Önerileri + +**Grup Tabanlı Öneriler:** +İstek türleri için en uygun araç gruplarını önerin +Önerileri iyileştirmek için kullanım kalıplarından öğrenin +Tercih edilen araçlar kullanılamadığında yedek gruplar sağlayın + +### 12. Açık Sorular + +1. **Grup Doğrulama**: İstehlerdeki geçersiz grup adları, sert hatalara mı yoksa uyarı mesajlarına mı neden olmalıdır? + +2. **Grup Keşfi**: Sistem, mevcut grupları ve araçlarını listelemek için bir API sağlamalı mıdır? + +3. **Dinamik Gruplar**: Gruplar, çalışma zamanında mı yoksa yalnızca başlangıçta mı yapılandırılabilir olmalıdır? + +4. **Grup Mirası**: Araçlar, grup bilgilerini ebeveyn kategorilerinden veya uygulamalarından mı miras almalıdır? + +5. **Performans İzleme**: Grup tabanlı araç kullanımını etkili bir şekilde izlemek için hangi ek metrikler gereklidir? + +### 13. Sonuç + +Araç grubu sistemi şunları sağlar: + +**Güvenlik**: Aracılar üzerindeki yetenekler için ayrıntılı erişim kontrolü +**Performans**: Araç yükleme ve seçim üzerindeki ek yükün azaltılması +**Esneklik**: Çok boyutlu araç sınıflandırması +**Uyumluluk**: Mevcut araç mimarileriyle sorunsuz entegrasyon + +Bu sistem, TrustGraph dağıtımlarının araç erişimini daha iyi yönetmesini, güvenlik sınırlarını iyileştirmesini ve mevcut yapılandırmalar ve isteklerle tam uyumluluğu korurken kaynak kullanımını optimize etmesini sağlar. diff --git a/docs/tech-specs/tool-group.zh-cn.md b/docs/tech-specs/tool-group.zh-cn.md new file mode 100644 index 00000000..5293609a --- /dev/null +++ b/docs/tech-specs/tool-group.zh-cn.md @@ -0,0 +1,491 @@ +# TrustGraph 工具组系统 +## 技术规范 v1.0 + +### 摘要 + +本规范定义了一个用于 TrustGraph 代理的工具分组系统,该系统允许对哪些工具可用于特定请求进行细粒度控制。该系统通过配置和请求级别的指定,引入基于组的工具过滤,从而实现更好的安全边界、资源管理以及代理功能的划分。 + +### 1. 概述 + +#### 1.1 问题陈述 + +目前,TrustGraph 代理可以访问所有配置的工具,而与请求上下文或安全要求无关。这带来了一些挑战: + +**安全风险**: 即使是只读查询,也可能访问到敏感工具(例如,数据修改)。 +**资源浪费**: 即使简单的查询也不需要,也会加载复杂的工具。 +**功能混淆**: 代理可能会选择不合适的工具,而存在更简单的替代方案。 +**多租户隔离**: 不同的用户组需要访问不同的工具集。 + +#### 1.2 解决方案概述 + +工具分组系统引入了: + +1. **组分类**: 工具在配置时会被标记为所属的组。 +2. **请求级别过滤**: AgentRequest 指定允许使用的工具组。 +3. **运行时强制**: 代理只能访问与请求的组匹配的工具。 +4. **灵活分组**: 工具可以属于多个组,以适应复杂的场景。 + +### 2. 模式变更 + +#### 2.1 工具配置模式增强 + +现有的工具配置通过添加一个 `group` 字段进行增强: + +**之前:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph" +} +``` + +**翻译后:** +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"] +} +``` + +**组字段规范:** +`group`: Array(String) - 此工具所属的组列表 +**可选:** 没有组字段的工具属于 "默认" 组 +**多重隶属:** 工具可以属于多个组 +**区分大小写:** 组名必须是完全匹配的字符串 + +#### 2.1.2 工具状态转换增强 + +工具可以选择性地指定状态转换和基于状态的可用性: + +```json +{ + "name": "knowledge-query", + "type": "knowledge-query", + "description": "Query the knowledge graph", + "group": ["read-only", "knowledge", "basic"], + "state": "analysis", + "available_in_states": ["undefined", "research"] +} +``` + +**状态字段规范:** +`state`: String - **可选** - 成功执行工具后要转换到的状态 +`available_in_states`: Array(String) - **可选** - 此工具可用的状态 +**默认行为:** 没有 `available_in_states` 的工具在所有状态下都可用 +**状态转换:** 仅在成功执行工具后发生 + +#### 2.2 AgentRequest 模式增强 + +`trustgraph-base/trustgraph/schema/services/agent.py` 中的 `AgentRequest` 模式已增强: + +**当前 AgentRequest:** +`question`: String - 用户查询 +`plan`: String - 执行计划(可以删除) +`state`: String - Agent 状态 +`history`: Array(AgentStep) - 执行历史 + +**增强后的 AgentRequest:** +`question`: String - 用户查询 +`state`: String - Agent 执行状态(现在被积极用于工具过滤) +`history`: Array(AgentStep) - 执行历史 +`group`: Array(String) - **新增** - 此请求允许的工具组 + +**模式变更:** +**已移除:** `plan` 字段不再需要,可以删除(最初用于工具规范) +**已添加:** `group` 字段用于工具组规范 +**已增强:** `state` 字段现在控制执行期间的工具可用性 + +**字段行为:** + +**组字段:** +**可选:** 如果未指定,默认为 ["default"] +**交集:** 只有匹配至少一个指定组的工具才可用 +**空数组:** 没有可用工具(agent 只能使用内部推理) +**通配符:** 特殊组 "*" 授予访问所有工具的权限 + +**状态字段:** +**可选:** 如果未指定,默认为 "undefined" +**基于状态的过滤:** 只有在当前状态下可用的工具才有资格 +**默认状态:** "undefined" 状态允许所有工具(受组过滤限制) +**状态转换:** 成功执行后,工具可以更改状态 + +### 3. 自定义组示例 + +组织可以定义特定领域的组: + +```json +{ + "financial-tools": ["stock-query", "portfolio-analysis"], + "medical-tools": ["diagnosis-assist", "drug-interaction"], + "legal-tools": ["contract-analysis", "case-search"] +} +``` + +### 4. 实现细节 + +#### 4.1 工具加载和过滤 + +**配置阶段:** +1. 所有工具从配置文件中加载,并带有其组分配信息。 +2. 没有明确组分配的工具将被分配到 "默认" 组。 +3. 组成员关系将被验证并存储在工具注册表中。 + +**请求处理阶段:** +1. AgentRequest 携带可选的组指定信息。 +2. Agent 根据组的交集过滤可用的工具。 +3. 只有匹配的工具才会被传递到 Agent 执行上下文。 +4. Agent 在整个请求生命周期内都使用过滤后的工具集。 + +#### 4.2 工具过滤逻辑 + +**组合组和状态过滤:** + +``` +For each configured tool: + tool_groups = tool.group || ["default"] + tool_states = tool.available_in_states || ["*"] // Available in all states + +For each request: + requested_groups = request.group || ["default"] + current_state = request.state || "undefined" + +Tool is available if: + // Group filtering + (intersection(tool_groups, requested_groups) is not empty OR "*" in requested_groups) + AND + // State filtering + (current_state in tool_states OR "*" in tool_states) +``` + +**状态转换逻辑:** + +``` +After successful tool execution: + if tool.state is defined: + next_request.state = tool.state + else: + next_request.state = current_request.state // No change +``` + +#### 4.3 代理集成点 + +**ReAct 代理:** +工具过滤在 `agent_manager.py` 中在工具注册创建期间发生。 +可用工具列表在计划生成之前,会根据组和状态进行过滤。 +状态转换会在工具执行成功后更新 `AgentRequest.state` 字段。 +下一次迭代使用更新后的状态进行工具过滤。 + +**基于置信度的代理:** +工具过滤在 `planner.py` 中在计划生成期间发生。 +`ExecutionStep` 验证确保只使用组+状态符合条件的工具。 +流程控制器在运行时强制执行工具可用性。 +状态转换由流程控制器在步骤之间管理。 + +### 5. 配置示例 + +#### 5.1 带有组和状态的工具配置 + +```yaml +tool: + knowledge-query: + type: knowledge-query + name: "Knowledge Graph Query" + description: "Query the knowledge graph for entities and relationships" + group: ["read-only", "knowledge", "basic"] + state: "analysis" + available_in_states: ["undefined", "research"] + + graph-update: + type: graph-update + name: "Graph Update" + description: "Add or modify entities in the knowledge graph" + group: ["write", "knowledge", "admin"] + available_in_states: ["analysis", "modification"] + + text-completion: + type: text-completion + name: "Text Completion" + description: "Generate text using language models" + group: ["read-only", "text", "basic"] + state: "undefined" + # No available_in_states = available in all states + + complex-analysis: + type: mcp-tool + name: "Complex Analysis Tool" + description: "Perform complex data analysis" + group: ["advanced", "compute", "expensive"] + state: "results" + available_in_states: ["analysis"] + mcp_tool_id: "analysis-server" + + reset-workflow: + type: mcp-tool + name: "Reset Workflow" + description: "Reset to initial state" + group: ["admin"] + state: "undefined" + available_in_states: ["analysis", "results"] +``` + +#### 5.2 请求示例与状态工作流 + +**初始研究请求:** +```json +{ + "question": "What entities are connected to Company X?", + "group": ["read-only", "knowledge"], + "state": "undefined" +} +``` +*可用工具:知识查询,文本补全* +*知识查询后:状态 → "分析"* + +**分析阶段:** +```json +{ + "question": "Continue analysis based on previous results", + "group": ["advanced", "compute", "write"], + "state": "analysis" +} +``` +*可用工具:复杂分析、图更新、重置工作流程* +*复杂分析之后:状态 → "结果"* + +**结果阶段:** +```json +{ + "question": "What should I do with these results?", + "group": ["admin"], + "state": "results" +} +``` +*可用的工具:仅限 reset-workflow* +*reset-workflow 之后:状态 → "undefined"* + +**工作流程示例 - 完整流程:** +1. **开始 (undefined)**:使用 knowledge-query → 转换到 "analysis" +2. **分析状态:** 使用 complex-analysis → 转换到 "results" +3. **结果状态:** 使用 reset-workflow → 转换回 "undefined" +4. **返回开始:** 所有初始工具再次可用 + +### 6. 安全注意事项 + +#### 6.1 访问控制集成 + +**网关级别的过滤:** +网关可以根据用户权限强制执行组限制 +防止通过请求修改来提升权限 +审计跟踪包括请求和授予的工具组 + +**示例网关逻辑:** +``` +user_permissions = get_user_permissions(request.user_id) +allowed_groups = user_permissions.tool_groups +requested_groups = request.group + +# Validate request doesn't exceed permissions +if not is_subset(requested_groups, allowed_groups): + reject_request("Insufficient permissions for requested tool groups") +``` + +#### 6.2 审计和监控 + +**增强的审计跟踪:** +记录每个请求所请求的工具组和初始状态 +跟踪按组成员划分的状态转换和工具使用情况 +监控未经授权的组访问尝试和无效的状态转换 +警报不寻常的组使用模式或可疑的状态工作流程 + +### 7. 迁移策略 + +#### 7.1 向后兼容性 + +**第一阶段:增量更改** +向工具配置添加可选的 `group` 字段 +向 AgentRequest 模式添加可选的 `group` 字段 +默认行为:所有现有工具都属于 "默认" 组 +现有请求如果没有组字段,则使用 "默认" 组 + +**保留现有行为:** +没有组配置的工具继续工作(默认组) +没有状态配置的工具在所有状态下都可用 +没有组指定的请求可以访问所有工具(默认组) +没有状态指定的请求使用 "未定义" 状态(所有工具可用) +没有对现有部署进行破坏性更改 + +### 8. 监控和可观察性 + +#### 8.1 新指标 + +**工具组使用情况:** +`agent_tool_group_requests_total` - 按组划分的请求计数器 +`agent_tool_group_availability` - 每个组可用的工具计量 +`agent_filtered_tools_count` - 组+状态过滤后工具计数的直方图 + +**状态工作流程指标:** +`agent_state_transitions_total` - 按工具划分的状态转换计数器 +`agent_workflow_duration_seconds` - 每个状态花费时间的直方图 +`agent_state_availability` - 每个状态可用的工具计量 + +**安全指标:** +`agent_group_access_denied_total` - 未经授权的组访问计数器 +`agent_invalid_state_transition_total` - 无效状态转换计数器 +`agent_privilege_escalation_attempts_total` - 具有可疑请求的计数器 + +#### 8.2 日志增强 + +**请求日志记录:** +```json +{ + "request_id": "req-123", + "requested_groups": ["read-only", "knowledge"], + "initial_state": "undefined", + "state_transitions": [ + {"tool": "knowledge-query", "from": "undefined", "to": "analysis", "timestamp": "2024-01-01T10:00:01Z"} + ], + "available_tools": ["knowledge-query", "text-completion"], + "filtered_by_group": ["graph-update", "admin-tool"], + "filtered_by_state": [], + "execution_time": "1.2s" +} +``` + +### 9. 测试策略 + +#### 9.1 单元测试 + +**工具过滤逻辑:** +测试组的交集计算 +测试基于状态的过滤逻辑 +验证默认组和状态的分配 +测试通配符组的行为 +验证空组的处理 +测试组合的组+状态过滤场景 + +**配置验证:** +测试使用各种组和状态配置加载工具 +验证无效的组和状态规范的模式验证 +测试与现有配置的向后兼容性 +验证状态转换的定义和循环 + +#### 9.2 集成测试 + +**代理行为:** +验证代理只看到组+状态过滤的工具 +测试使用各种组组合的请求执行 +测试代理执行期间的状态转换 +验证在没有可用工具时错误处理 +测试通过多个状态的工作流程进度 + +**安全测试:** +测试特权提升预防 +验证审计跟踪的准确性 +测试网关与用户权限的集成 + +#### 9.3 完整场景 + +**具有状态工作流程的多租户使用:** +``` +Scenario: Different users with different tool access and workflow states +Given: User A has "read-only" permissions, state "undefined" + And: User B has "write" permissions, state "analysis" +When: Both request knowledge operations +Then: User A gets read-only tools available in "undefined" state + And: User B gets write tools available in "analysis" state + And: State transitions are tracked per user session + And: All usage and transitions are properly audited +``` + +**工作流程状态演进:** +``` +Scenario: Complete workflow execution +Given: Request with groups ["knowledge", "compute"] and state "undefined" +When: Agent executes knowledge-query tool (transitions to "analysis") + And: Agent executes complex-analysis tool (transitions to "results") + And: Agent executes reset-workflow tool (transitions to "undefined") +Then: Each step has correctly filtered available tools + And: State transitions are logged with timestamps + And: Final state allows initial workflow to repeat +``` + +### 10. 性能考虑 + +#### 10.1 工具加载的影响 + +**配置加载:** +组和状态元数据在启动时加载一次 +每个工具的内存开销很小(附加字段) +不会影响工具的初始化时间 + +**请求处理:** +组+状态过滤的组合在每个请求中执行一次 +复杂度为 O(n),其中 n = 配置的工具数量 +状态转换会增加微小的开销(字符串赋值) +对于典型的工具数量(< 100),影响可以忽略不计 + +#### 10.2 优化策略 + +**预计算的工具集:** +根据组+状态组合缓存工具集 +避免重复过滤常见的组/状态模式 +内存与计算之间的权衡,适用于经常使用的组合 + +**延迟加载:** +仅在需要时才加载工具实现 +减少具有许多工具的部署的启动时间 +基于组需求的动态工具注册 + +### 11. 未来增强功能 + +#### 11.1 动态组分配 + +**基于上下文的组:** +根据请求上下文将工具分配到组 +基于时间的组可用性(仅在工作时间内) +基于负载的组限制(在低使用情况下限制昂贵的工具) + +#### 11.2 组层级结构 + +**嵌套的组结构:** +```json +{ + "knowledge": { + "read": ["knowledge-query", "entity-search"], + "write": ["graph-update", "entity-create"] + } +} +``` + +#### 11.3 工具推荐 + +**基于组的建议:** +针对请求类型,推荐最佳工具组。 +从使用模式中学习,以改进推荐。 +在首选工具不可用时,提供备用组。 + +### 12. 开放性问题 + +1. **组验证:** 请求中无效的组名是否应导致硬性错误或警告? + +2. **组发现:** 系统是否应提供一个 API 来列出可用的组及其工具? + +3. **动态组:** 组是否应在运行时配置,或者仅在启动时配置? + +4. **组继承:** 工具是否应从其父类别或实现继承组? + +5. **性能监控:** 需要哪些额外的指标来有效跟踪基于组的工具使用情况? + +### 13. 结论 + +工具组系统提供: + +**安全性:** 对代理功能进行细粒度的访问控制。 +**性能:** 减少工具加载和选择开销。 +**灵活性:** 多维工具分类。 +**兼容性:** 与现有代理架构无缝集成。 + +该系统使 TrustGraph 部署能够更好地管理工具访问,提高安全边界,并优化资源利用率,同时与现有的配置和请求完全兼容。 diff --git a/docs/tech-specs/tool-services.ar.md b/docs/tech-specs/tool-services.ar.md index 37b67791..ebfc14b6 100644 --- a/docs/tech-specs/tool-services.ar.md +++ b/docs/tech-specs/tool-services.ar.md @@ -1,96 +1,471 @@ -**تعليمات مهمة:** - -- احتفظ بجميع التنسيقات (العناوين، الروابط، علامات HTML) بشكل صحيح. -- لا تترجم أي شي داخل علامات backticks أو كتل التعليمات البرمجية. -- قم بإخراج النص المترجم فقط، بدون أي مقدمة أو تفسيرات. - -**النص المراد ترجمته:** - -# خدمات الأداة: أدوات الوكلاء القابلة للتوصيل ديناميكيًا +# خدمات الأدوات: أدوات وكيل قابلة للتوصيل ديناميكيًا ## الحالة -مُنفَّذ +تم التنفيذ ## نظرة عامة -يحدد هذا المواصفق آلية لأدوات الوكلاء القابلة للتوصيل ديناميكيًا تسمى "خدمات الأدوات". على عكس أنواع الأدوات المدمجة الموجودة (`KnowledgeService`, `McPTool`), لا تتطلب هذه الطريقة إعداد مسبق. +تحدد هذه المواصفات آلية لأدوات وكيل قابلة للتوصيل ديناميكيًا تسمى "خدمات الأدوات". على عكس أنواع الأدوات المضمنة الحالية (`KnowledgeQueryImpl`، `McpToolImpl`، إلخ)، تسمح خدمات الأدوات بإدخال أدوات جديدة عن طريق: -## مفاهيم أساسية +1. نشر خدمة جديدة تعتمد على Pulsar +2. إضافة وصف تهيئة يخبر الوكيل كيفية استدعائها -* **خدمات الأدوات:** مكونات قابلة للتوصيل ديناميكيًا يمكن للوكيل استدعائها. -* **الوكيل:** التطبيق الذي يستخدم خدمات الأدوات. -* **موضوع الرسائل:** قناة اتصال بين الوكيل وخدمة الأدوات. +يتيح ذلك إمكانية التوسع دون تعديل إطار عمل الاستجابة الأساسي للوكيل. -## التصميم +## المصطلحات -يعمل نظام خدمات الأدوات على مبدأ "الطلب والاستجابة". يقوم الوكيل بإنشاء طلب (رسالة) إلى خدمة الأدوات، وتقوم خدمة الأدوات بمعالجة الطلب وإرجاع استجابة (رسالة) إلى الوكيل. +| المصطلح | التعريف | +|------|------------| +| **أداة مضمنة** | أنواع الأدوات الحالية مع تطبيقات مضمنة في `tools.py` | +| **خدمة أداة** | خدمة Pulsar التي يمكن استدعاؤها كأداة وكيل، ويتم تعريفها بواسطة وصف الخدمة | +| **أداة** | نسخة مُكوّنة تشير إلى خدمة أداة، وتُعرض للوكيل/نموذج اللغة الكبير | -## بنية الطلب والاستجابة +هذا نموذج من مستويين، مماثل لأدوات MCP: +MCP: يحدد خادم MCP واجهة الأداة → إعداد الأداة يشير إليها +خدمات الأدوات: تحدد خدمة الأداة واجهة Pulsar → إعداد الأداة يشير إليها -تستخدم خدمات الأدوات تنسيق رسائل بسيط وموحد لتبادل البيانات بين الوكيل وخدمة الأدوات. تتكون كل رسالة من جزئين: +## الخلفية: الأدوات الحالية -* **الطلب:** يحتوي على بيانات الإدخال المطلوبة لخدمة الأدوات. -* **الاستجابة:** تحتوي على نتيجة معالجة الطلب من قبل خدمة الأدوات. +### تنفيذ الأداة المضمنة -## مثال +يتم تعريف الأدوات حاليًا في `trustgraph-flow/trustgraph/agent/react/tools.py` مع تطبيقات مُصنّفة: -لنفترض أن الوكيل يريد معرفة الطقس في مدينة معينة. يمكن للوكيل إنشاء طلب يحتوي على اسم المدينة وإرساله إلى خدمة الطقس. تتلقى خدمة الطقس الطلب، وتحقق من بيانات الطقس، وترسل استجابة تحتوي على معلومات الطقس إلى الوكيل. +```python +class KnowledgeQueryImpl: + async def invoke(self, question): + client = self.context("graph-rag-request") + return await client.rag(question, self.collection) +``` -## تنفيذ +كل نوع أداة: +لديه خدمة Pulsar مُبرمجة مسبقًا والتي يستدعيها (مثل: `graph-rag-request`) +يعرف بالضبط الطريقة التي يجب استدعاؤها على العميل (مثل: `client.rag()`) +لديه وسائط مُعرّفة من النوع في التنفيذ -يتم تنفيذ خدمات الأدوات كعمليات متزامنة. تسمح هذه الطريقة لخدمات الأدوات بالاستجابة بسرعة لطلبات الوكيل. +### تسجيل الأدوات (service.py:105-214) -## أمثلة +يتم تحميل الأدوات من ملف التكوين باستخدام حقل `type` والذي يربط بتنفيذ: -* **خدمة الطقس:** تتلقى طلبًا يحتوي على اسم المدينة وترجع معلومات الطقس. -* **محرك البحث:** يتلقى طلبًا يحتوي على عبارة بحث ويرجع قائمة بالنتائج. +```python +if impl_id == "knowledge-query": + impl = functools.partial(KnowledgeQueryImpl, collection=data.get("collection")) +elif impl_id == "text-completion": + impl = TextCompletionImpl +# ... etc +``` -## مزايا +## العمارة -* **مرونة:** يمكن إضافة خدمات أدوات جديدة دون تعديل الوكيل. -* **قابلية التوسع:** يمكن للوكيل استخدام العديد من خدمات الأدوات في وقت واحد. -* **سهولة الصيانة:** يمكن تحديث خدمات الأدوات بشكل مستقل عن الوكيل. +### نموذج ذو طبقتين -## الاعتبارات +#### الطبقة الأولى: مُعرّف خدمة الأداة -* يجب أن تكون خدمات الأدوات مصممة لتكون خفيفة الوزن وفعالة. -* يجب أن تكون خدمات الأدوات قادرة على التعامل مع طلبات متعددة من وكلاء مختلفين. -* يجب أن تكون خدمات الأدوات آمنة وموثوقة. +تحدد خدمة الأداة واجهة خدمة Pulsar. وهي تُعلن عن: +قوائم انتظار Pulsar للطلبات/الاستجابات +معلمات التكوين التي تتطلبها من الأدوات التي تستخدمها -## مثال +```json +{ + "id": "custom-rag", + "request-queue": "non-persistent://tg/request/custom-rag", + "response-queue": "non-persistent://tg/response/custom-rag", + "config-params": [ + {"name": "collection", "required": true} + ] +} +``` -لنفترض أن الوكيل يريد البحث عن معلومات حول موضوع معين. يمكن للوكيل إنشاء طلب يحتوي على عبارة البحث وإرساله إلى محرك البحث. يتلقى محرك البحث الطلب، ويقوم بإجراء البحث، ويرجع قائمة بالنتائج إلى الوكيل. +خدمة أداة لا تتطلب أي معلمات تهيئة: -## الوحدة (Module) +```json +{ + "id": "calculator", + "request-queue": "non-persistent://tg/request/calc", + "response-queue": "non-persistent://tg/response/calc", + "config-params": [] +} +``` -يتم تنظيم نظام خدمات الأدوات في وحدات (modules). كل وحدة مسؤولة عن تنفيذ وظيفة معينة. على سبيل المثال، قد يكون هناك وحدة للطقس ومحرك بحث ووحدة للتحقق من صحة البيانات. +#### المستوى الثاني: وصف الأداة -## واجهات برمجة التطبيقات (APIs) +تشير الأداة إلى خدمة الأداة وتوفر: +قيم معلمات التكوين (التي تلبي متطلبات الخدمة) +بيانات وصفية للأداة للوكيل (الاسم، الوصف) +تعريفات الوسائط لنموذج اللغة الكبيرة (LLM) -توفر وحدات خدمات الأدوات واجهات برمجة تطبيقات (APIs) للوكلاء للتفاعل معها. تتضمن هذه الواجهات ما يلي: +```json +{ + "type": "tool-service", + "name": "query-customers", + "description": "Query the customer knowledge base", + "service": "custom-rag", + "collection": "customers", + "arguments": [ + { + "name": "question", + "type": "string", + "description": "The question to ask about customers" + } + ] +} +``` -* **واجهة طلب:** تحدد تنسيق الرسائل المستخدمة لإنشاء طلبات. -* **واجهة استجابة:** تحدد تنسيق الرسائل المستخدمة لتلقي الاستجابات. +يمكن لأدوات متعددة الإشارة إلى نفس الخدمة بتكوينات مختلفة: -## الأمان +```json +{ + "type": "tool-service", + "name": "query-products", + "description": "Query the product knowledge base", + "service": "custom-rag", + "collection": "products", + "arguments": [ + { + "name": "question", + "type": "string", + "description": "The question to ask about products" + } + ] +} +``` -يتم تأمين نظام خدمات الأدوات باستخدام آليات الأمان القياسية. تتضمن هذه الآليات ما يلي: +### تنسيق الطلب -* **التحقق من الهوية:** التحقق من هوية الوكيل قبل السماح له بالوصول إلى خدمات الأدوات. -* **الترخيص:** تحديد صلاحيات الوصول التي يتمتع بها كل وكيل. -* **التشفير:** تشفير جميع البيانات المرسلة بين الوكيل وخدمات الأدوات. +عندما يتم استدعاء أداة، يتضمن الطلب المرسل إلى خدمة الأداة ما يلي: +`user`: من طلب الوكيل (دعم تعدد المستأجرين) +`config`: قيم التكوين المشفرة بتنسيق JSON والمستمدة من وصف الأداة +`arguments`: وسائط مشفرة بتنسيق JSON والمستمدة من نموذج اللغة الكبير (LLM) -## التوثيق +```json +{ + "user": "alice", + "config": "{\"collection\": \"customers\"}", + "arguments": "{\"question\": \"What are the top customer complaints?\"}" +} +``` -يتم توثيق نظام خدمات الأدوات بشكل كامل. يتضمن التوثيق ما يلي: +تتلقى خدمة الأداة هذه البيانات كقاموسات مُحللة في الطريقة `invoke`. -* **وصف للواجهات:** وصف لواجهات برمجة التطبيقات (APIs) المتاحة. -* **أمثلة التعليمات البرمجية:** أمثلة للتعليمات البرمجية توضح كيفية استخدام خدمات الأدوات. -* **دليل المستخدم:** دليل المستخدم الذي يشرح كيفية استخدام نظام خدمات الأدوات. +### تطبيق عام لخدمة الأداة -## الإصدارات المستقبلية +تستدعي فئة `ToolServiceImpl` خدمات الأداة بناءً على التكوين: -* **التعلم الآلي:** يمكن استخدام التعلم الآلي لتحسين أداء خدمات الأدوات. -* **الذكاء الاصطناعي:** يمكن استخدام الذكاء الاصطناعي لتمكين خدمات الأدوات من أداء مهام أكثر تعقيدًا. -* **الأمن:** يمكن تحسين أمان نظام خدمات الأدوات باستخدام تقنيات أمان جديدة. \ No newline at end of file +```python +class ToolServiceImpl: + def __init__(self, context, request_queue, response_queue, config_values, arguments, processor): + self.request_queue = request_queue + self.response_queue = response_queue + self.config_values = config_values # e.g., {"collection": "customers"} + # ... + + async def invoke(self, **arguments): + client = await self._get_or_create_client() + response = await client.call(user, self.config_values, arguments) + if isinstance(response, str): + return response + else: + return json.dumps(response) +``` + +## قرارات التصميم + +### نموذج التكوين ثنائي الطبقات + +تتبع خدمات الأدوات نموذجًا ثنائي الطبقات مشابهًا لأدوات MCP: + +1. **خدمة الأداة**: تحدد واجهة خدمة Pulsar (الموضوع، ومعلمات التكوين المطلوبة). +2. **الأداة**: تشير إلى خدمة أداة، وتوفر قيم التكوين، وتحدد وسائط LLM. + +يسمح هذا الفصل بما يلي: +يمكن لخدمة أداة واحدة أن تستخدمها أدوات متعددة بتكوينات مختلفة. +تمييز واضح بين واجهة الخدمة وتكوين الأداة. +إمكانية إعادة استخدام تعريفات الخدمة. + +### تعيين الطلبات: تمرير مع الغلاف + +الطلب إلى خدمة الأداة هو غلاف منظم يحتوي على: +`user`: يتم تمريره من طلب الوكيل لخدمة العملاء المتعددة. +قيم التكوين: من وصف الأداة (مثل `collection`). +`arguments`: وسائط LLM، يتم تمريرها كقاموس. + +يقوم مدير الوكيل بتحليل استجابة LLM إلى `act.arguments` كقاموس (`agent_manager.py:117-154`). يتم تضمين هذا القاموس في غلاف الطلب. + +### معالجة المخططات: غير مُعَرَّفة الأنواع + +تستخدم الطلبات والاستجابات قواميس غير مُعَرَّفة الأنواع. لا يوجد تحقق من صحة المخطط على مستوى الوكيل - خدمة الأداة مسؤولة عن التحقق من صحة مدخلاتها. يوفر هذا أقصى قدر من المرونة لتعريف خدمات جديدة. + +### واجهة العميل: مواضيع Pulsar مباشرة + +تستخدم خدمات الأدوات مواضيع Pulsar مباشرة دون الحاجة إلى تكوين التدفق. يحدد وصف خدمة الأداة أسماء قائمة الانتظار الكاملة: + +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [...] +} +``` + +هذا يسمح باستضافة الخدمات في أي مساحة اسم. + +### معالجة الأخطاء: الاصطلاح القياسي للأخطاء. + +تتبع استجابات خدمات الأدوات الاصطلاح الحالي للمخطط مع حقل `error`: + +```python +@dataclass +class Error: + type: str = "" + message: str = "" +``` + +هيكل الاستجابة: +النجاح: إذا كانت `error` تساوي `None`، تحتوي الاستجابة على النتيجة. +الخطأ: يتم ملء `error` بـ `type` و `message`. + +هذا يتوافق مع النمط المستخدم في مخططات الخدمة الحالية (مثل: `PromptResponse`، `QueryResponse`، `AgentResponse`). + +### الارتباط بين الطلبات والاستجابات + +يتم ربط الطلبات والاستجابات باستخدام `id` في خصائص رسائل Pulsar: + +يتضمن الطلب `id` في الخصائص: `properties={"id": id}`. +تتضمن الاستجابة (أو الاستجابات) نفس `id`: `properties={"id": id}`. + +هذا يتبع النمط الحالي المستخدم في قاعدة التعليمات البرمجية بأكملها (مثل: `agent_service.py`، `llm_service.py`). + +### دعم التدفق + +يمكن لخدمات الأدوات إرجاع استجابات متدفقة: + +رسائل استجابة متعددة بنفس `id` في الخصائص. +تتضمن كل استجابة حقل `end_of_stream: bool`. +تحتوي الاستجابة النهائية على `end_of_stream: True`. + +هذا يتوافق مع النمط المستخدم في `AgentResponse` وخدمات التدفق الأخرى. + +### معالجة الاستجابة: إرجاع سلسلة نصية + +تتبع جميع الأدوات الموجودة نفس النمط: **استقبال الوسائط كقاموس، وإرجاع الملاحظة كسلسلة نصية**. + +| الأداة | معالجة الاستجابة | +|------|------------------| +| `KnowledgeQueryImpl` | إرجاع `client.rag()` مباشرة (سلسلة نصية) | +| `TextCompletionImpl` | إرجاع `client.question()` مباشرة (سلسلة نصية) | +| `McpToolImpl` | إرجاع سلسلة نصية، أو `json.dumps(output)` إذا لم تكن سلسلة نصية | +| `StructuredQueryImpl` | تنسيق النتيجة إلى سلسلة نصية | +| `PromptImpl` | إرجاع `client.prompt()` مباشرة (سلسلة نصية) | + +تتبع خدمات الأدوات نفس العقد: +تقوم الخدمة بإرجاع استجابة سلسلة نصية (الملاحظة). +إذا لم تكن الاستجابة سلسلة نصية، يتم تحويلها عبر `json.dumps()`. +لا يلزم وجود تكوين استخراج في الوصف. + +هذا يبقي الوصف بسيطًا ويضع المسؤولية على الخدمة لإرجاع استجابة نصية مناسبة للوكيل. + +## دليل التكوين + +لإضافة خدمة أداة جديدة، يلزم وجود عنصرين في التكوين: + +### 1. تكوين خدمة الأداة + +يتم تخزينها تحت مفتاح التكوين `tool-service`. تحدد قوائم انتظار Pulsar والمعلمات التكوين المتاحة. + +| الحقل | مطلوب | الوصف | +|-------|----------|-------------| +| `id` | نعم | معرف فريد لخدمة الأداة | +| `request-queue` | نعم | موضوع Pulsar الكامل للطلبات (مثل: `non-persistent://tg/request/joke`) | +| `response-queue` | نعم | موضوع Pulsar الكامل للاستجابات (مثل: `non-persistent://tg/response/joke`) | +| `config-params` | لا | مصفوفة من معلمات التكوين التي تقبلها الخدمة | + +يمكن لكل معلمة تكوين تحديد: +`name`: اسم المعلمة (مطلوب) +`required`: ما إذا كان يجب توفير المعلمة بواسطة الأدوات (افتراضي: خطأ) + +مثال: +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [ + {"name": "style", "required": false} + ] +} +``` + +### 2. إعدادات الأداة + +يتم تخزينها تحت مفتاح التكوين `tool`. تحدد أداة يمكن للوكيل استخدامها. + +| الحقل | مطلوب | الوصف | +|-------|----------|-------------| +| `type` | نعم | يجب أن يكون `"tool-service"` | +| `name` | نعم | اسم الأداة المعروضة لنظام LLM | +| `description` | نعم | وصف لما تفعله الأداة (يُعرض لنظام LLM) | +| `service` | نعم | معرف خدمة الأداة التي سيتم استدعاؤها | +| `arguments` | لا | مصفوفة من تعريفات الوسائط لنظام LLM | +| *(معلمات التكوين)* | يختلف | أي معلمات تكوين معرفة بواسطة الخدمة | + +يمكن لكل وسيط تحديد: +`name`: اسم الوسيط (مطلوب) +`type`: نوع البيانات، على سبيل المثال، `"string"` (مطلوب) +`description`: الوصف المعروض لنظام LLM (مطلوب) + +مثال: +```json +{ + "type": "tool-service", + "name": "tell-joke", + "description": "Tell a joke on a given topic", + "service": "joke-service", + "style": "pun", + "arguments": [ + { + "name": "topic", + "type": "string", + "description": "The topic for the joke (e.g., programming, animals, food)" + } + ] +} +``` + +### تحميل الإعدادات + +استخدم `tg-put-config-item` لتحميل الإعدادات: + +```bash +# Load tool-service config +tg-put-config-item tool-service/joke-service < joke-service.json + +# Load tool config +tg-put-config-item tool/tell-joke < tell-joke.json +``` + +يجب إعادة تشغيل الوكيل الإداري لاستيعاب التكوينات الجديدة. + +## تفاصيل التنفيذ + +### المخطط + +أنواع الطلبات والاستجابات في `trustgraph-base/trustgraph/schema/services/tool_service.py`: + +```python +@dataclass +class ToolServiceRequest: + user: str = "" # User context for multi-tenancy + config: str = "" # JSON-encoded config values from tool descriptor + arguments: str = "" # JSON-encoded arguments from LLM + +@dataclass +class ToolServiceResponse: + error: Error | None = None + response: str = "" # String response (the observation) + end_of_stream: bool = False +``` + +### الخادم: خدمة DynamicToolService + +الفئة الأساسية في `trustgraph-base/trustgraph/base/dynamic_tool_service.py`: + +```python +class DynamicToolService(AsyncProcessor): + """Base class for implementing tool services.""" + + def __init__(self, **params): + topic = params.get("topic", default_topic) + # Constructs topics: non-persistent://tg/request/{topic}, non-persistent://tg/response/{topic} + # Sets up Consumer and Producer + + async def invoke(self, user, config, arguments): + """Override this method to implement the tool's logic.""" + raise NotImplementedError() +``` + +### جانب العميل: ToolServiceImpl + +التنفيذ في `trustgraph-flow/trustgraph/agent/react/tools.py`: + +```python +class ToolServiceImpl: + def __init__(self, context, request_queue, response_queue, config_values, arguments, processor): + # Uses the provided queue paths directly + # Creates ToolServiceClient on first use + + async def invoke(self, **arguments): + client = await self._get_or_create_client() + response = await client.call(user, config_values, arguments) + return response if isinstance(response, str) else json.dumps(response) +``` + +### الملفات + +| الملف | الغرض | +|------|---------| +| `trustgraph-base/trustgraph/schema/services/tool_service.py` | مخططات الطلبات والاستجابات | +| `trustgraph-base/trustgraph/base/tool_service_client.py` | عميل لاستدعاء الخدمات | +| `trustgraph-base/trustgraph/base/dynamic_tool_service.py` | الفئة الأساسية لتنفيذ الخدمة | +| `trustgraph-flow/trustgraph/agent/react/tools.py` | فئة `ToolServiceImpl` | +| `trustgraph-flow/trustgraph/agent/react/service.py` | تحميل التكوين | + +### مثال: خدمة النكت + +مثال لخدمة في `trustgraph-flow/trustgraph/tool_service/joke/`: + +```python +class Processor(DynamicToolService): + async def invoke(self, user, config, arguments): + style = config.get("style", "pun") + topic = arguments.get("topic", "") + joke = pick_joke(topic, style) + return f"Hey {user}! Here's a {style} for you:\n\n{joke}" +``` + +تكوين خدمة الأداة: +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [{"name": "style", "required": false}] +} +``` + +إعدادات الأداة: +```json +{ + "type": "tool-service", + "name": "tell-joke", + "description": "Tell a joke on a given topic", + "service": "joke-service", + "style": "pun", + "arguments": [ + {"name": "topic", "type": "string", "description": "The topic for the joke"} + ] +} +``` + +### التوافق مع الإصدارات السابقة + +تظل أنواع الأدوات المدمجة الحالية تعمل دون تغيير. +`tool-service` هو نوع أداة جديد بالإضافة إلى الأنواع الموجودة (`knowledge-query`، `mcp-tool`، إلخ). + +## اعتبارات مستقبلية + +### الخدمات ذات الإعلان الذاتي + +يمكن أن تسمح ترقية مستقبلية للخدمات بنشر أوصافها الخاصة: + +تنشر الخدمات إلى موضوع `tool-descriptors` معروف عند بدء التشغيل. +يشترك الوكيل ويسجل الأدوات ديناميكيًا. +يتيح ذلك إمكانية التوصيل والتشغيل الحقيقية دون تغييرات في التكوين. + +هذا خارج نطاق التنفيذ الأولي. + +## المراجع + +التنفيذ الحالي للأداة: `trustgraph-flow/trustgraph/agent/react/tools.py` +تسجيل الأداة: `trustgraph-flow/trustgraph/agent/react/service.py:105-214` +مخططات الوكيل: `trustgraph-base/trustgraph/schema/services/agent.py` diff --git a/docs/tech-specs/tool-services.es.md b/docs/tech-specs/tool-services.es.md new file mode 100644 index 00000000..a7c00d6d --- /dev/null +++ b/docs/tech-specs/tool-services.es.md @@ -0,0 +1,471 @@ +# Servicios de Herramientas: Herramientas de Agente Dinámicamente Conectables + +## Estado + +Implementado + +## Resumen + +Esta especificación define un mecanismo para herramientas de agente dinámicamente conectables llamadas "servicios de herramientas". A diferencia de los tipos de herramientas integradas existentes (`KnowledgeQueryImpl`, `McpToolImpl`, etc.), los servicios de herramientas permiten introducir nuevas herramientas mediante: + +1. Desplegar un nuevo servicio basado en Pulsar +2. Agregar un descriptor de configuración que le indique al agente cómo invocarlo + +Esto permite la extensibilidad sin modificar el marco de respuesta del agente principal. + +## Terminología + +| Término | Definición | +|------|------------| +| **Herramienta Integrada** | Tipos de herramientas existentes con implementaciones codificadas en `tools.py` | +| **Servicio de Herramienta** | Un servicio de Pulsar que se puede invocar como una herramienta de agente, definido por un descriptor de servicio | +| **Herramienta** | Una instancia configurada que hace referencia a un servicio de herramienta, expuesta al agente/LLM | + +Este es un modelo de dos niveles, análogo a las herramientas MCP: +MCP: El servidor MCP define la interfaz de la herramienta → La configuración de la herramienta la referencia +Servicios de Herramienta: El servicio de herramienta define la interfaz de Pulsar → La configuración de la herramienta la referencia + +## Antecedentes: Herramientas Existentes + +### Implementación de Herramienta Integrada + +Las herramientas se definen actualmente en `trustgraph-flow/trustgraph/agent/react/tools.py` con implementaciones tipadas: + +```python +class KnowledgeQueryImpl: + async def invoke(self, question): + client = self.context("graph-rag-request") + return await client.rag(question, self.collection) +``` + +Cada tipo de herramienta: +Tiene un servicio Pulsar predefinido al que llama (por ejemplo, `graph-rag-request`) +Conoce el método exacto para llamar al cliente (por ejemplo, `client.rag()`) +Tiene argumentos tipados definidos en la implementación + +### Registro de herramientas (service.py:105-214) + +Las herramientas se cargan desde la configuración con un campo `type` que se mapea a una implementación: + +```python +if impl_id == "knowledge-query": + impl = functools.partial(KnowledgeQueryImpl, collection=data.get("collection")) +elif impl_id == "text-completion": + impl = TextCompletionImpl +# ... etc +``` + +## Arquitectura + +### Modelo de Dos Capas + +#### Capa 1: Descriptor del Servicio de Herramienta + +Un servicio de herramienta define una interfaz de servicio de Pulsar. Declara: +Las colas de Pulsar para solicitud/respuesta +Los parámetros de configuración que requiere de las herramientas que lo utilizan + +```json +{ + "id": "custom-rag", + "request-queue": "non-persistent://tg/request/custom-rag", + "response-queue": "non-persistent://tg/response/custom-rag", + "config-params": [ + {"name": "collection", "required": true} + ] +} +``` + +Un servicio de herramienta que no necesita parámetros de configuración: + +```json +{ + "id": "calculator", + "request-queue": "non-persistent://tg/request/calc", + "response-queue": "non-persistent://tg/response/calc", + "config-params": [] +} +``` + +#### Nivel 2: Descriptor de la herramienta + +Una herramienta hace referencia a un servicio de herramienta y proporciona: +Valores de parámetros de configuración (que satisfacen los requisitos del servicio) +Metadatos de la herramienta para el agente (nombre, descripción) +Definiciones de argumentos para el LLM + +```json +{ + "type": "tool-service", + "name": "query-customers", + "description": "Query the customer knowledge base", + "service": "custom-rag", + "collection": "customers", + "arguments": [ + { + "name": "question", + "type": "string", + "description": "The question to ask about customers" + } + ] +} +``` + +Múltiples herramientas pueden referenciar el mismo servicio con diferentes configuraciones: + +```json +{ + "type": "tool-service", + "name": "query-products", + "description": "Query the product knowledge base", + "service": "custom-rag", + "collection": "products", + "arguments": [ + { + "name": "question", + "type": "string", + "description": "The question to ask about products" + } + ] +} +``` + +### Formato de solicitud + +Cuando se invoca una herramienta, la solicitud al servicio de la herramienta incluye: +`user`: Desde la solicitud del agente (multitenencia) +`config`: Valores de configuración codificados en JSON provenientes de la descripción de la herramienta +`arguments`: Argumentos codificados en JSON provenientes del LLM + +```json +{ + "user": "alice", + "config": "{\"collection\": \"customers\"}", + "arguments": "{\"question\": \"What are the top customer complaints?\"}" +} +``` + +El servicio de herramientas recibe esto como diccionarios analizados en el método `invoke`. + +### Implementación Genérica del Servicio de Herramientas + +Una clase `ToolServiceImpl` invoca servicios de herramientas basándose en la configuración: + +```python +class ToolServiceImpl: + def __init__(self, context, request_queue, response_queue, config_values, arguments, processor): + self.request_queue = request_queue + self.response_queue = response_queue + self.config_values = config_values # e.g., {"collection": "customers"} + # ... + + async def invoke(self, **arguments): + client = await self._get_or_create_client() + response = await client.call(user, self.config_values, arguments) + if isinstance(response, str): + return response + else: + return json.dumps(response) +``` + +## Decisiones de Diseño + +### Modelo de Configuración de Dos Niveles + +Los servicios de herramientas siguen un modelo de dos niveles similar a las herramientas de MCP: + +1. **Servicio de Herramienta**: Define la interfaz del servicio de Pulsar (tema, parámetros de configuración requeridos) +2. **Herramienta**: Hace referencia a un servicio de herramienta, proporciona valores de configuración, define argumentos de LLM + +Esta separación permite: +Que un servicio de herramienta sea utilizado por múltiples herramientas con diferentes configuraciones +Una distinción clara entre la interfaz del servicio y la configuración de la herramienta +La reutilización de las definiciones de servicio + +### Mapeo de Solicitudes: Transmisión con Sobre + +La solicitud a un servicio de herramienta es un sobre estructurado que contiene: +`user`: Propagado desde la solicitud del agente para la multi-inquilinato +Valores de configuración: Del descriptor de la herramienta (por ejemplo, `collection`) +`arguments`: Argumentos proporcionados por el LLM, transmitidos como un diccionario + +El administrador del agente analiza la respuesta del LLM en `act.arguments` como un diccionario (`agent_manager.py:117-154`). Este diccionario se incluye en el sobre de la solicitud. + +### Manejo de Esquemas: No Tipado + +Las solicitudes y las respuestas utilizan diccionarios no tipados. No hay validación de esquema a nivel del agente; el servicio de herramienta es responsable de validar sus entradas. Esto proporciona la máxima flexibilidad para definir nuevos servicios. + +### Interfaz de Cliente: Temas Directos de Pulsar + +Los servicios de herramientas utilizan temas directos de Pulsar sin requerir configuración de flujo. El descriptor del servicio de herramienta especifica los nombres completos de las colas: + +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [...] +} +``` + +Esto permite que los servicios se alojen en cualquier espacio de nombres. + +### Manejo de errores: Convención de error estándar + +Las respuestas del servicio de herramientas siguen la convención de esquema existente con un campo `error`: + +```python +@dataclass +class Error: + type: str = "" + message: str = "" +``` + +Estructura de la respuesta: +Éxito: `error` es `None`, la respuesta contiene el resultado +Error: `error` se completa con `type` y `message` + +Esto coincide con el patrón utilizado en todo el esquema de servicios existente (por ejemplo, `PromptResponse`, `QueryResponse`, `AgentResponse`). + +### Correlación de solicitudes/respuestas + +Las solicitudes y las respuestas se correlacionan mediante un `id` en las propiedades del mensaje de Pulsar: + +La solicitud incluye `id` en las propiedades: `properties={"id": id}` +La(s) respuesta(s) incluyen el mismo `id`: `properties={"id": id}` + +Esto sigue el patrón existente utilizado en todo el código base (por ejemplo, `agent_service.py`, `llm_service.py`). + +### Soporte de transmisión + +Los servicios de herramientas pueden devolver respuestas de transmisión: + +Múltiples mensajes de respuesta con el mismo `id` en las propiedades +Cada respuesta incluye el campo `end_of_stream: bool` +La respuesta final tiene `end_of_stream: True` + +Esto coincide con el patrón utilizado en `AgentResponse` y otros servicios de transmisión. + +### Manejo de la respuesta: retorno de cadena + +Todas las herramientas existentes siguen el mismo patrón: **recibir argumentos como un diccionario, devolver la observación como una cadena**. + +| Herramienta | Manejo de la respuesta | +|------|------------------| +| `KnowledgeQueryImpl` | Devuelve `client.rag()` directamente (cadena) | +| `TextCompletionImpl` | Devuelve `client.question()` directamente (cadena) | +| `McpToolImpl` | Devuelve una cadena, o `json.dumps(output)` si no es una cadena | +| `StructuredQueryImpl` | Formatea el resultado a una cadena | +| `PromptImpl` | Devuelve `client.prompt()` directamente (cadena) | + +Los servicios de herramientas siguen el mismo contrato: +El servicio devuelve una respuesta de cadena (la observación) +Si la respuesta no es una cadena, se convierte mediante `json.dumps()` +No se necesita ninguna configuración de extracción en el descriptor + +Esto mantiene el descriptor simple y delega la responsabilidad de devolver una respuesta de texto adecuada al agente en el servicio. + +## Guía de configuración + +Para agregar un nuevo servicio de herramientas, se requieren dos elementos de configuración: + +### 1. Configuración del servicio de herramientas + +Se almacena bajo la clave de configuración `tool-service`. Define las colas de Pulsar y los parámetros de configuración disponibles. + +| Campo | Requerido | Descripción | +|-------|----------|-------------| +| `id` | Sí | Identificador único para el servicio de herramientas | +| `request-queue` | Sí | Tema de Pulsar completo para las solicitudes (por ejemplo, `non-persistent://tg/request/joke`) | +| `response-queue` | Sí | Tema de Pulsar completo para las respuestas (por ejemplo, `non-persistent://tg/response/joke`) | +| `config-params` | No | Matriz de parámetros de configuración que el servicio acepta | + +Cada parámetro de configuración puede especificar: +`name`: Nombre del parámetro (obligatorio) +`required`: Si el parámetro debe ser proporcionado por las herramientas (por defecto: falso) + +Ejemplo: +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [ + {"name": "style", "required": false} + ] +} +``` + +### 2. Configuración de la herramienta + +Almacenado bajo la clave de configuración `tool`. Define una herramienta que el agente puede utilizar. + +| Campo | Requerido | Descripción | +|-------|----------|-------------| +| `type` | Sí | Debe ser `"tool-service"` | +| `name` | Sí | Nombre de la herramienta expuesto al LLM | +| `description` | Sí | Descripción de lo que hace la herramienta (mostrada al LLM) | +| `service` | Sí | ID del servicio de herramientas a invocar | +| `arguments` | No | Matriz de definiciones de argumentos para el LLM | +| *(parámetros de configuración)* | Varía | Cualquier parámetro de configuración definido por el servicio | + +Cada argumento puede especificar: +`name`: Nombre del argumento (requerido) +`type`: Tipo de datos, por ejemplo, `"string"` (requerido) +`description`: Descripción mostrada al LLM (requerido) + +Ejemplo: +```json +{ + "type": "tool-service", + "name": "tell-joke", + "description": "Tell a joke on a given topic", + "service": "joke-service", + "style": "pun", + "arguments": [ + { + "name": "topic", + "type": "string", + "description": "The topic for the joke (e.g., programming, animals, food)" + } + ] +} +``` + +### Carga de la configuración + +Utilice `tg-put-config-item` para cargar configuraciones: + +```bash +# Load tool-service config +tg-put-config-item tool-service/joke-service < joke-service.json + +# Load tool config +tg-put-config-item tool/tell-joke < tell-joke.json +``` + +El agente-administrador debe reiniciarse para cargar nuevas configuraciones. + +## Detalles de implementación + +### Esquema + +Tipos de solicitud y respuesta en `trustgraph-base/trustgraph/schema/services/tool_service.py`: + +```python +@dataclass +class ToolServiceRequest: + user: str = "" # User context for multi-tenancy + config: str = "" # JSON-encoded config values from tool descriptor + arguments: str = "" # JSON-encoded arguments from LLM + +@dataclass +class ToolServiceResponse: + error: Error | None = None + response: str = "" # String response (the observation) + end_of_stream: bool = False +``` + +### Servidor: Servicio DynamicToolService + +Clase base en `trustgraph-base/trustgraph/base/dynamic_tool_service.py`: + +```python +class DynamicToolService(AsyncProcessor): + """Base class for implementing tool services.""" + + def __init__(self, **params): + topic = params.get("topic", default_topic) + # Constructs topics: non-persistent://tg/request/{topic}, non-persistent://tg/response/{topic} + # Sets up Consumer and Producer + + async def invoke(self, user, config, arguments): + """Override this method to implement the tool's logic.""" + raise NotImplementedError() +``` + +### Cliente: ToolServiceImpl + +Implementación en `trustgraph-flow/trustgraph/agent/react/tools.py`: + +```python +class ToolServiceImpl: + def __init__(self, context, request_queue, response_queue, config_values, arguments, processor): + # Uses the provided queue paths directly + # Creates ToolServiceClient on first use + + async def invoke(self, **arguments): + client = await self._get_or_create_client() + response = await client.call(user, config_values, arguments) + return response if isinstance(response, str) else json.dumps(response) +``` + +### Archivos + +| Archivo | Propósito | +|------|---------| +| `trustgraph-base/trustgraph/schema/services/tool_service.py` | Esquemas de solicitud/respuesta | +| `trustgraph-base/trustgraph/base/tool_service_client.py` | Cliente para invocar servicios | +| `trustgraph-base/trustgraph/base/dynamic_tool_service.py` | Clase base para la implementación de servicios | +| `trustgraph-flow/trustgraph/agent/react/tools.py` | Clase `ToolServiceImpl` | +| `trustgraph-flow/trustgraph/agent/react/service.py` | Carga de configuración | + +### Ejemplo: Servicio de Chistes + +Un ejemplo de servicio en `trustgraph-flow/trustgraph/tool_service/joke/`: + +```python +class Processor(DynamicToolService): + async def invoke(self, user, config, arguments): + style = config.get("style", "pun") + topic = arguments.get("topic", "") + joke = pick_joke(topic, style) + return f"Hey {user}! Here's a {style} for you:\n\n{joke}" +``` + +Configuración del servicio de herramientas: +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [{"name": "style", "required": false}] +} +``` + +Configuración de la herramienta: +```json +{ + "type": "tool-service", + "name": "tell-joke", + "description": "Tell a joke on a given topic", + "service": "joke-service", + "style": "pun", + "arguments": [ + {"name": "topic", "type": "string", "description": "The topic for the joke"} + ] +} +``` + +### Compatibilidad hacia atrás + +Los tipos de herramientas integradas existentes continúan funcionando sin cambios. +`tool-service` es un nuevo tipo de herramienta, además de los tipos existentes (`knowledge-query`, `mcp-tool`, etc.). + +## Consideraciones futuras + +### Servicios de autoanuncio + +Una mejora futura podría permitir que los servicios publiquen sus propios descriptores: + +Los servicios publican en un tema `tool-descriptors` conocido al inicio. +El agente se suscribe y registra dinámicamente las herramientas. +Permite una verdadera funcionalidad de conexión y uso sin cambios de configuración. + +Esto está fuera del alcance de la implementación inicial. + +## Referencias + +Implementación actual de la herramienta: `trustgraph-flow/trustgraph/agent/react/tools.py` +Registro de herramientas: `trustgraph-flow/trustgraph/agent/react/service.py:105-214` +Esquemas del agente: `trustgraph-base/trustgraph/schema/services/agent.py` diff --git a/docs/tech-specs/tool-services.he.md b/docs/tech-specs/tool-services.he.md index 61fc5f49..3d19369b 100644 --- a/docs/tech-specs/tool-services.he.md +++ b/docs/tech-specs/tool-services.he.md @@ -1,98 +1,471 @@ -## שירותי כלי: כלים מתואמים +# שירותי כלים: כלים דינמיים הניתנים לחיבור ## סטטוס -יישום +מיושם ## סקירה כללית -מפרט זה מגדיר מנגנון לכלים מתואמים של כלי, המכונים "שירותי כלי". בניגוד לסוגי הכלים הקיצוניים המובנים (`KnowledgeQueryImpl`, `McpToolImpl` וכו'), שירותי כלי מאפשרים להטמיע כלים חדשים על ידי: +מפרט זה מגדיר מנגנון לכלים דינמיים הניתנים לחיבור הנקראים "שירותי כלים". בניגוד לסוגי הכלים המובנים הקיימים (`KnowledgeQueryImpl`, `McpToolImpl`, וכו'), שירותי כלים מאפשרים להציג כלים חדשים על ידי: -1. פריסת שירות פולסר חדש -2. הוספת תיאור תצורה שמורה לאגנט כיצד להפעיל אותו +1. פריסת שירות חדש המבוסס על Pulsar +2. הוספת תיאור תצורה המציין לסוכן כיצד להפעיל אותו -זה מאפשר הרחבה מבלי לשנות את המסגרת הליבה של `agent-flow`. +זה מאפשר הרחבה מבלי לשנות את מסגרת התגובה הבסיסית של הסוכן. -## איך להשתמש +## מונחים -1. הגדירו שירות כלי בתצורה, כולל שמות הנושאים עבור בקשות ותגובות. -2. הגדירו כלי באמצעות הגדרות שירות כלי. -3. השתמשו בכלי בתוך קוד ה-agent. -4. הגדירו את סוג הכלים בתיאור התצורה. +| מונח | הגדרה | +|------|------------| +| **כלי מובנה** | סוגי כלים קיימים עם יישומים מוגדרים מראש ב-`tools.py` | +| **שירות כלי** | שירות Pulsar שניתן להפעיל ככלי סוכן, המוגדר על ידי תיאור שירות | +| **כלי** | מופע מוגדר המתייחס לשירות כלי, החשוף לסוכן/LLM | -## דוגמה +זהו מודל דו-שכבתי, אנלוגי לכלי MCP: +MCP: שרת MCP מגדיר את ממשק הכלי → תצורת הכלי מתייחסת אליו +שירותי כלים: שירות הכלי מגדיר את ממשק Pulsar → תצורת הכלי מתייחסת אליו -הנה דוגמה להגדרת שירות כלי בשם "joke-service": +## רקע: כלים קיימים -1. **שירות כלי:** +### יישום כלי מובנה - ```json +כלי מוגדרים כיום ב-`trustgraph-flow/trustgraph/agent/react/tools.py` עם יישומים מטיפוסים: + +```python +class KnowledgeQueryImpl: + async def invoke(self, question): + client = self.context("graph-rag-request") + return await client.rag(question, self.collection) +``` + +כל סוג כלי: +כולל שירות Pulsar מובנה שהוא קורא אליו (לדוגמה: `graph-rag-request`) +יודע בדיוק את השיטה לקריאה בלקוח (לדוגמה: `client.rag()`) +מכיל ארגומנטים מוגדרים בסביבת היישום + +### רישום כלים (service.py:105-214) + +כלים נטענים מקובץ תצורה עם שדה `type` שממפה ליישום: + +```python +if impl_id == "knowledge-query": + impl = functools.partial(KnowledgeQueryImpl, collection=data.get("collection")) +elif impl_id == "text-completion": + impl = TextCompletionImpl +# ... etc +``` + +## ארכיטקטורה + +### מודל דו-שכבתי + +#### שכבה 1: תיאור שירות כלי + +שירות כלי מגדיר ממשק שירות של פולסר. הוא מכריז על: +תורי הפולסר עבור בקשות/תגובות +פרמטרי תצורה שהוא דורש מכלי המשתמשים בו + +```json +{ + "id": "custom-rag", + "request-queue": "non-persistent://tg/request/custom-rag", + "response-queue": "non-persistent://tg/response/custom-rag", + "config-params": [ + {"name": "collection", "required": true} + ] +} +``` + +שירות כלי שאינו דורש פרמטרים של תצורה: + +```json +{ + "id": "calculator", + "request-queue": "non-persistent://tg/request/calc", + "response-queue": "non-persistent://tg/response/calc", + "config-params": [] +} +``` + +#### שכבה 2: תיאור כלי + +כלי מפנה לשירות כלי ומספק: +ערכי פרמטרים של תצורה (העונים על דרישות השירות) +מטא-נתונים של הכלי עבור הסוכן (שם, תיאור) +הגדרות ארגומנטים עבור מודל השפה הגדול (LLM) + +```json +{ + "type": "tool-service", + "name": "query-customers", + "description": "Query the customer knowledge base", + "service": "custom-rag", + "collection": "customers", + "arguments": [ { - "id": "joke-service", - "request-queue": "non-persistent://tg/request/joke", - "response-queue": "non-persistent://tg/response/joke", - "config-params": [ - {"name": "style", "required": false} - ] + "name": "question", + "type": "string", + "description": "The question to ask about customers" } - ``` + ] +} +``` -2. **כלי:** +מספר כלים יכולים להתייחס לאותה שירות עם תצורות שונות: - ```json +```json +{ + "type": "tool-service", + "name": "query-products", + "description": "Query the product knowledge base", + "service": "custom-rag", + "collection": "products", + "arguments": [ { - "type": "tool-service", - "name": "tell-joke", - "description": "Tell a joke on a given topic", - "service": "joke-service", - "style": "pun", - "arguments": [ - {"name": "topic", "type": "string", "description": "The topic for the joke"} - ] + "name": "question", + "type": "string", + "description": "The question to ask about products" } - ``` + ] +} +``` -3. **קוד ה-agent (פסאודו-קוד):** +### פורמט בקשה - ```python - # Load the joke service configuration - tool_service_config = tg_get_config_item("tool-service/joke-service") +כאשר כלי מופעל, הבקשה לשירות הכלי כוללת: +`user`: מהבקשה של הסוכן (ריבוי דיירים) +`config`: ערכי תצורה מקודדים ב-JSON מהתיאור של הכלי +`arguments`: ארגומנטים מקודדים ב-JSON מהמודל הלשוני הגדול (LLM) - # Load the tool configuration - tool_config = tg_get_config_item("tool/tell-joke") +```json +{ + "user": "alice", + "config": "{\"collection\": \"customers\"}", + "arguments": "{\"question\": \"What are the top customer complaints?\"}" +} +``` - # Instantiate the tool service - joke_service = DynamicToolService( - request_queue=tool_service_config["request-queue"], - response_queue=tool_service_config["response-queue"], - config_values=tool_config["config-params"], # Map config parameters - arguments=tool_config["arguments"], - ) +השירות של הכלי מקבל זאת כ-dicts שעברו ניתוח בשיטה `invoke`. - # Call the tool service - user_name = get_user_name() # Get the current user - joke_topic = "programming" # Or get this from the LLM - joke = joke_service.invoke(user_name, {}, {"topic": joke_topic}) +### יישום כללי של שירות הכלי - # Display the joke - print(f"Hey {user_name}! Here's a {tool_config['style']} for you:\n\n{joke}") - ``` +מחלקה `ToolServiceImpl` מפעילה שירותי כלי בהתבסס על תצורה: -## הערות חשובות +```python +class ToolServiceImpl: + def __init__(self, context, request_queue, response_queue, config_values, arguments, processor): + self.request_queue = request_queue + self.response_queue = response_queue + self.config_values = config_values # e.g., {"collection": "customers"} + # ... -* **`tg-put-config-item`**: השתמשו בפקודה הזו כדי לטעון את תצורות השירות והכלי. לדוגמה, `tg-put-config-item tool-service/joke-service < joke-service.json`. -* **`agent-flow`**: קוד ה-agent חייב להיות מותאם כך שיתפקד בהתאם למפרט. שימו לב במיוחד ל-`DynamicToolService` ואיך הוא מעובד. -* **שמות נושאים**: שימו לב לשמות הנושאים. הם חייבים להיות תואמים למה שמוגדר ב-`trustgraph-base/trustgraph/schema/services/tool_service.py`. -* **תצורת כלי**: שימו לב לתצורת הכלי, במיוחד לשדות ה-`type` (חייב להיות `"tool-service"`) ו-`arguments`. -* **תצורה דינמית**: השירותים עצמם יצטרכו לקרוא את תצורת ה-`tool-service` כדי לדעת מה לקבל, ולאחר מכן להגדיר את הלקוח (Client). -* **קוד דוגמה**: קוד הדוגמה מספק תצורה מפורטת, אבל הוא רק דוגמה. אתם צריכים להבין איך קוד ה-agent קורא לתצורה הזו. + async def invoke(self, **arguments): + client = await self._get_or_create_client() + response = await client.call(user, self.config_values, arguments) + if isinstance(response, str): + return response + else: + return json.dumps(response) +``` -## שאלות נפוצות +## החלטות עיצוב -* **איך למצוא את הקוד המתאים?** הקודים שצוינו נמצאים ב-`trustgraph-flow/trustgraph/agent/react/tools.py`, `trustgraph-flow/trustgraph/agent/react/service.py`, `trustgraph-flow/trustgraph/base/dynamic_tool_service.py`, ו-`trustgraph-flow/trustgraph/schema/services/tool_service.py`. -* **מהו `tg-put-config-item`?** זו פקודה שמשמשת לטעינת תצורות. -* **איך אני יודע מתי הכל עובד?** בדקו שהכלים מוגדרים כראוי, ושהתצורה מועברת נכון. השתמשו ב-logging כדי לראות אם התהליכים מתחילים, מסיטים בקשות, ומחזירים תגובות. +### מודל תצורה דו-שכבתי -## סיכום +שירותי כלים פועלים לפי מודל דו-שכבתי הדומה לכלי MCP: -ההגדרה הזו מספקת מסגרת לשימוש בכלים מתואמים בתוך `trustgraph-flow`. על ידי הבנת התצורה, הקוד, והדגמים, תוכלו לשלב כלים חדשים בקלות. \ No newline at end of file +1. **שירות כלי**: מגדיר את ממשק השירות של Pulsar (נושא, פרמטרי תצורה נדרשים) +2. **כלי**: מפנה לשירות כלי, מספק ערכי תצורה, מגדיר ארגומנטים של LLM + +הפרדה זו מאפשרת: +שירות כלי אחד יכול לשמש מספר כלים עם תצורות שונות +הבחנה ברורה בין ממשק השירות לתצורת הכלי +שימוש חוזר בהגדרות שירות + +### מיפוי בקשות: העברה עם מעטפה + +הבקשה לשירות כלי היא מעטפה מובנית המכילה: +`user`: מועבר מבקשת הסוכן עבור ריבוי דיירים +ערכי תצורה: מתיאור הכלי (לדוגמה, `collection`) +`arguments`: ארגומנטים המסופקים על ידי LLM, מועברים כמילון + +מנהל הסוכן מנתח את התגובה של ה-LLM ל-`act.arguments` כמילון (`agent_manager.py:117-154`). מילון זה כלול במעטפת הבקשה. + +### טיפול בסכימה: לא מסווג + +בקשות ותגובות משתמשות במילונים לא מסווגים. אין אימות סכימה ברמת הסוכן - שירות הכלי אחראי לאימות הקלט שלו. זה מספק גמישות מרבית בהגדרת שירותים חדשים. + +### ממשק לקוח: נושאים ישירים של Pulsar + +שירותי כלים משתמשים בנושאים ישירים של Pulsar מבלי לדרוש תצורת זרימה. תיאור שירות הכלי מציין את שמות התורים המלאים: + +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [...] +} +``` + +זה מאפשר לארח שירותים בכל מרחב שם. + +### טיפול בשגיאות: מוסכמות שגיאות סטנדרטיות + +תגובות של שירותי כלים עוקבות אחר מוסכמות הסכימה הקיימות עם שדה `error`: + +```python +@dataclass +class Error: + type: str = "" + message: str = "" +``` + +מבנה תגובה: +הצלחה: `error` הוא `None`, התגובה מכילה תוצאה +שגיאה: `error` מאוכלס עם `type` ו- `message` + +זה תואם לדפוס המשמש בכל סכימות השירות הקיימות (לדוגמה, `PromptResponse`, `QueryResponse`, `AgentResponse`). + +### התאמה בין בקשה לתגובה + +בקשות ותגובות משויכות באמצעות `id` במאפייני הודעות Pulsar: + +בקשה כוללת `id` במאפיינים: `properties={"id": id}` +התגובות כוללות את אותו `id`: `properties={"id": id}` + +זה עוקב אחר הדפוס הקיים המשמש בכל בסיס הקוד (לדוגמה, `agent_service.py`, `llm_service.py`). + +### תמיכה בסטרימינג + +שירותי כלים יכולים להחזיר תגובות בסטרימינג: + +הודעות תגובה מרובות עם אותו `id` במאפיינים +כל תגובה כוללת את השדה `end_of_stream: bool` +התגובה הסופית כוללת את `end_of_stream: True` + +זה תואם לדפוס המשמש ב- `AgentResponse` ובשירותי סטרימינג אחרים. + +### טיפול בתגובה: החזרת מחרוזת + +כל הכלים הקיימים עוקבים אחר אותו דפוס: **קבלת ארגומנטים כמילון, החזרת התצפית כמחרוזת**. + +| כלי | טיפול בתגובה | +|------|------------------| +| `KnowledgeQueryImpl` | מחזיר את `client.rag()` ישירות (מחרוזת) | +| `TextCompletionImpl` | מחזיר את `client.question()` ישירות (מחרוזת) | +| `McpToolImpl` | מחזיר מחרוזת, או `json.dumps(output)` אם אינה מחרוזת | +| `StructuredQueryImpl` | מעצב את התוצאה למחרוזת | +| `PromptImpl` | מחזיר את `client.prompt()` ישירות (מחרוזת) | + +שירותי כלים עוקבים אחר אותו חוזה: +השירות מחזיר תגובת מחרוזת (התצפית) +אם התגובה אינה מחרוזת, היא מומרת באמצעות `json.dumps()` +אין צורך בתצורת חילוץ במגדיר + +זה שומר על המגדיר פשוט ומעביר את האחריות לשירות להחזיר תגובת טקסט מתאימה עבור הסוכן. + +## מדריך תצורה + +כדי להוסיף שירות כלי חדש, נדרשים שני פריטי תצורה: + +### 1. תצורת שירות כלי + +מאוחסן תחת מפתח התצורה `tool-service`. מגדיר את תורי Pulsar ואת פרמטרי התצורה הזמינים. + +| שדה | נדרש | תיאור | +|-------|----------|-------------| +| `id` | כן | מזהה ייחודי עבור שירות הכלי | +| `request-queue` | כן | נושא Pulsar מלא עבור בקשות (לדוגמה, `non-persistent://tg/request/joke`) | +| `response-queue` | כן | נושא Pulsar מלא עבור תגובות (לדוגמה, `non-persistent://tg/response/joke`) | +| `config-params` | לא | מערך של פרמטרי תצורה שהשירות מקבל | + +ניתן לציין כל פרמטר תצורה: +`name`: שם הפרמטר (נדרש) +`required`: האם הפרמטר חייב להיות מסופק על ידי כלים (ברירת מחדל: false) + +דוגמה: +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [ + {"name": "style", "required": false} + ] +} +``` + +### 2. תצורת כלי + +שמור תחת מפתח התצורה `tool`. מגדיר כלי שהסוכן יכול להשתמש בו. + +| שדה | נדרש | תיאור | +|-------|----------|-------------| +| `type` | כן | חייב להיות `"tool-service"` | +| `name` | כן | שם הכלי החשוף ל-LLM | +| `description` | כן | תיאור של מה הכלי עושה (מוצג ל-LLM) | +| `service` | כן | מזהה של שירות הכלי לביצוע | +| `arguments` | לא | מערך של הגדרות ארגומנטים עבור ה-LLM | +| *(פרמטרי תצורה)* | משתנה | כל פרמטרי תצורה המוגדרים על ידי השירות | + +כל ארגומנט יכול לציין: +`name`: שם הארגומנט (נדרש) +`type`: סוג נתונים, לדוגמה, `"string"` (נדרש) +`description`: תיאור המוצג ל-LLM (נדרש) + +דוגמה: +```json +{ + "type": "tool-service", + "name": "tell-joke", + "description": "Tell a joke on a given topic", + "service": "joke-service", + "style": "pun", + "arguments": [ + { + "name": "topic", + "type": "string", + "description": "The topic for the joke (e.g., programming, animals, food)" + } + ] +} +``` + +### טעינת הגדרות + +השתמשו ב-`tg-put-config-item` כדי לטעון הגדרות: + +```bash +# Load tool-service config +tg-put-config-item tool-service/joke-service < joke-service.json + +# Load tool config +tg-put-config-item tool/tell-joke < tell-joke.json +``` + +יש להפעיל מחדש את מנהל הסוכן כדי לקלוט הגדרות חדשות. + +## פרטי יישום + +### סכימה + +סוגי בקשות ותגובות ב-`trustgraph-base/trustgraph/schema/services/tool_service.py`: + +```python +@dataclass +class ToolServiceRequest: + user: str = "" # User context for multi-tenancy + config: str = "" # JSON-encoded config values from tool descriptor + arguments: str = "" # JSON-encoded arguments from LLM + +@dataclass +class ToolServiceResponse: + error: Error | None = None + response: str = "" # String response (the observation) + end_of_stream: bool = False +``` + +### צד שרת: DynamicToolService + +מחלקה בסיסית ב-`trustgraph-base/trustgraph/base/dynamic_tool_service.py`: + +```python +class DynamicToolService(AsyncProcessor): + """Base class for implementing tool services.""" + + def __init__(self, **params): + topic = params.get("topic", default_topic) + # Constructs topics: non-persistent://tg/request/{topic}, non-persistent://tg/response/{topic} + # Sets up Consumer and Producer + + async def invoke(self, user, config, arguments): + """Override this method to implement the tool's logic.""" + raise NotImplementedError() +``` + +### צד לקוח: ToolServiceImpl + +יישום ב-`trustgraph-flow/trustgraph/agent/react/tools.py`: + +```python +class ToolServiceImpl: + def __init__(self, context, request_queue, response_queue, config_values, arguments, processor): + # Uses the provided queue paths directly + # Creates ToolServiceClient on first use + + async def invoke(self, **arguments): + client = await self._get_or_create_client() + response = await client.call(user, config_values, arguments) + return response if isinstance(response, str) else json.dumps(response) +``` + +### קבצים + +| קובץ | מטרה | +|------|---------| +| `trustgraph-base/trustgraph/schema/services/tool_service.py` | סכימות בקשה/תגובה | +| `trustgraph-base/trustgraph/base/tool_service_client.py` | לקוח להפעלת שירותים | +| `trustgraph-base/trustgraph/base/dynamic_tool_service.py` | מחלקה בסיסית ליישום שירות | +| `trustgraph-flow/trustgraph/agent/react/tools.py` | מחלקה `ToolServiceImpl` | +| `trustgraph-flow/trustgraph/agent/react/service.py` | טעינת תצורה | + +### דוגמה: שירות בדיחות + +דוגמה לשירות ב-`trustgraph-flow/trustgraph/tool_service/joke/`: + +```python +class Processor(DynamicToolService): + async def invoke(self, user, config, arguments): + style = config.get("style", "pun") + topic = arguments.get("topic", "") + joke = pick_joke(topic, style) + return f"Hey {user}! Here's a {style} for you:\n\n{joke}" +``` + +תצורת שירות הכלי: +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [{"name": "style", "required": false}] +} +``` + +הגדרות כלי: +```json +{ + "type": "tool-service", + "name": "tell-joke", + "description": "Tell a joke on a given topic", + "service": "joke-service", + "style": "pun", + "arguments": [ + {"name": "topic", "type": "string", "description": "The topic for the joke"} + ] +} +``` + +### תאימות לאחור + +סוגי כלים מובנים קיימים ממשיכים לעבוד ללא שינוי. +`tool-service` הוא סוג כלי חדש לצד סוגים קיימים (`knowledge-query`, `mcp-tool`, וכו'). + +## שיקולים עתידיים + +### שירותים המצהירים על עצמם + +שיפור עתידי יכול לאפשר לשירותים לפרסם את התיאורים שלהם: + +שירותים מפרסמים לנושא `tool-descriptors` ידוע בעת ההפעלה. +הסוכן נרשם ורושם כלים באופן דינמי. +מאפשר חיבור והפעלה אמיתיים ללא שינויי תצורה. + +זה מחוץ לתחום של המימוש הראשוני. + +## הפניות + +יישום כלי נוכחי: `trustgraph-flow/trustgraph/agent/react/tools.py` +רישום כלים: `trustgraph-flow/trustgraph/agent/react/service.py:105-214` +סכימות סוכן: `trustgraph-base/trustgraph/schema/services/agent.py` diff --git a/docs/tech-specs/tool-services.hi.md b/docs/tech-specs/tool-services.hi.md new file mode 100644 index 00000000..626cc521 --- /dev/null +++ b/docs/tech-specs/tool-services.hi.md @@ -0,0 +1,471 @@ +# टूल सेवाएं: गतिशील रूप से प्लगेबल एजेंट टूल + +## स्थिति + +कार्यान्वित + +## अवलोकन + +यह विनिर्देश "टूल सेवाओं" नामक गतिशील रूप से प्लगेबल एजेंट टूल के लिए एक तंत्र को परिभाषित करता है। मौजूदा अंतर्निहित टूल प्रकारों (`KnowledgeQueryImpl`, `McpToolImpl`, आदि) के विपरीत, टूल सेवाएं नए टूल को इस प्रकार पेश करने की अनुमति देती हैं: + +1. एक नई पल्सर-आधारित सेवा को तैनात करना +2. एक कॉन्फ़िगरेशन विवरण जोड़ना जो एजेंट को बताता है कि इसे कैसे कॉल करना है + +यह मुख्य एजेंट-रिएक्ट फ्रेमवर्क को संशोधित किए बिना विस्तारशीलता को सक्षम बनाता है। + +## शब्दावली + +| शब्द | परिभाषा | +|------|------------| +| **अंतर्निहित टूल** | `tools.py` में हार्डकोडेड कार्यान्वयन वाले मौजूदा टूल प्रकार +| **टूल सेवा** | एक पल्सर सेवा जिसे एजेंट टूल के रूप में कॉल किया जा सकता है, जिसे एक सेवा विवरण द्वारा परिभाषित किया गया है +| **टूल** | एक कॉन्फ़िगर किया गया उदाहरण जो एक टूल सेवा को संदर्भित करता है, जो एजेंट/एलएलएम को उजागर किया जाता है + +यह एक दो-स्तरीय मॉडल है, जो एमसीपी टूल के समान है: +एमसीपी: एमसीपी सर्वर टूल इंटरफ़ेस को परिभाषित करता है → टूल कॉन्फ़िगरेशन इसका संदर्भ देता है +टूल सेवाएं: टूल सेवा पल्सर इंटरफ़ेस को परिभाषित करती है → टूल कॉन्फ़िगरेशन इसका संदर्भ देता है + +## पृष्ठभूमि: मौजूदा टूल + +### अंतर्निहित टूल कार्यान्वयन + +टूल वर्तमान में `trustgraph-flow/trustgraph/agent/react/tools.py` में टाइप किए गए कार्यान्वयन के साथ परिभाषित किए गए हैं: + +```python +class KnowledgeQueryImpl: + async def invoke(self, question): + client = self.context("graph-rag-request") + return await client.rag(question, self.collection) +``` + +प्रत्येक उपकरण प्रकार: +में एक हार्डकोडेड पल्सर सेवा होती है जिसे वह कॉल करता है (उदाहरण के लिए, `graph-rag-request`) +वह क्लाइंट पर कॉल करने के लिए सटीक विधि जानता है (उदाहरण के लिए, `client.rag()`) +इसमें कार्यान्वयन में परिभाषित टाइप किए गए तर्क होते हैं + +### उपकरण पंजीकरण (service.py:105-214) + +उपकरण कॉन्फ़िगरेशन से लोड किए जाते हैं जिसमें एक `type` फ़ील्ड होता है जो एक कार्यान्वयन से मेल खाता है: + +```python +if impl_id == "knowledge-query": + impl = functools.partial(KnowledgeQueryImpl, collection=data.get("collection")) +elif impl_id == "text-completion": + impl = TextCompletionImpl +# ... etc +``` + +## आर्किटेक्चर + +### दो-स्तरीय मॉडल + +#### स्तर 1: टूल सर्विस डिस्क्रिप्टर + +एक टूल सर्विस, पल्सर सर्विस इंटरफेस को परिभाषित करता है। यह निम्नलिखित घोषित करता है: +अनुरोध/प्रतिक्रिया के लिए पल्सर क्यू +उन कॉन्फ़िगरेशन पैरामीटर जिन्हें इसका उपयोग करने वाले टूल से इसकी आवश्यकता होती है + +```json +{ + "id": "custom-rag", + "request-queue": "non-persistent://tg/request/custom-rag", + "response-queue": "non-persistent://tg/response/custom-rag", + "config-params": [ + {"name": "collection", "required": true} + ] +} +``` + +एक उपकरण सेवा जिसे किसी भी कॉन्फ़िगरेशन पैरामीटर की आवश्यकता नहीं है: + +```json +{ + "id": "calculator", + "request-queue": "non-persistent://tg/request/calc", + "response-queue": "non-persistent://tg/response/calc", + "config-params": [] +} +``` + +#### स्तर 2: टूल विवरणिका + +एक टूल एक टूल सेवा को संदर्भित करता है और निम्नलिखित प्रदान करता है: +कॉन्फ़िगरेशन पैरामीटर मान (सेवा की आवश्यकताओं को पूरा करते हुए) +एजेंट के लिए टूल मेटाडेटा (नाम, विवरण) +एलएलएम के लिए तर्क परिभाषाएँ + +```json +{ + "type": "tool-service", + "name": "query-customers", + "description": "Query the customer knowledge base", + "service": "custom-rag", + "collection": "customers", + "arguments": [ + { + "name": "question", + "type": "string", + "description": "The question to ask about customers" + } + ] +} +``` + +कई उपकरण एक ही सेवा को विभिन्न कॉन्फ़िगरेशन के साथ संदर्भित कर सकते हैं: + +```json +{ + "type": "tool-service", + "name": "query-products", + "description": "Query the product knowledge base", + "service": "custom-rag", + "collection": "products", + "arguments": [ + { + "name": "question", + "type": "string", + "description": "The question to ask about products" + } + ] +} +``` + +### अनुरोध प्रारूप + +जब कोई टूल सक्रिय किया जाता है, तो टूल सेवा को भेजा गया अनुरोध में शामिल होता है: +`user`: एजेंट अनुरोध से (मल्टी-टेनेंसी) +`config`: टूल विवरणिका से JSON-एन्कोडेड कॉन्फ़िगरेशन मान +`arguments`: LLM से JSON-एन्कोडेड तर्क + +```json +{ + "user": "alice", + "config": "{\"collection\": \"customers\"}", + "arguments": "{\"question\": \"What are the top customer complaints?\"}" +} +``` + +टूल सर्विस इन डेटा को पार्स किए गए डिक्शनरी के रूप में `invoke` मेथड में प्राप्त करती है। + +### सामान्य टूल सर्विस कार्यान्वयन + +एक `ToolServiceImpl` क्लास कॉन्फ़िगरेशन के आधार पर टूल सेवाओं को लागू करता है: + +```python +class ToolServiceImpl: + def __init__(self, context, request_queue, response_queue, config_values, arguments, processor): + self.request_queue = request_queue + self.response_queue = response_queue + self.config_values = config_values # e.g., {"collection": "customers"} + # ... + + async def invoke(self, **arguments): + client = await self._get_or_create_client() + response = await client.call(user, self.config_values, arguments) + if isinstance(response, str): + return response + else: + return json.dumps(response) +``` + +## डिज़ाइन निर्णय + +### दो-स्तरीय कॉन्फ़िगरेशन मॉडल + +टूल सेवाएं एमसीपी टूल के समान एक दो-स्तरीय मॉडल का पालन करती हैं: + +1. **टूल सेवा**: पल्सर सेवा इंटरफ़ेस को परिभाषित करती है (विषय, आवश्यक कॉन्फ़िगरेशन पैरामीटर) +2. **टूल**: एक टूल सेवा को संदर्भित करता है, कॉन्फ़िगरेशन मान प्रदान करता है, एलएलएम तर्क को परिभाषित करता है + +यह अलगाव अनुमति देता है: +एक टूल सेवा का उपयोग विभिन्न कॉन्फ़िगरेशन वाले कई टूल द्वारा किया जा सकता है +सेवा इंटरफ़ेस और टूल कॉन्फ़िगरेशन के बीच स्पष्ट अंतर +सेवा परिभाषाओं का पुन: उपयोग + +### अनुरोध मैपिंग: एन्वेलप के साथ पास-थ्रू + +एक टूल सेवा के लिए अनुरोध एक संरचित एन्वेलप होता है जिसमें शामिल हैं: +`user`: मल्टी-टेनेंसी के लिए एजेंट अनुरोध से प्रचारित +कॉन्फ़िगरेशन मान: टूल विवरणिका से (उदाहरण के लिए, `collection`) +`arguments`: एलएलएम-प्रदत्त तर्क, एक डिक्ट के रूप में पास किए जाते हैं + +एजेंट प्रबंधक एलएलएम की प्रतिक्रिया को `act.arguments` के रूप में एक डिक्ट (`agent_manager.py:117-154`) में पार्स करता है। यह डिक्ट अनुरोध एन्वेलप में शामिल है। + +### स्कीमा हैंडलिंग: अनटाइप्ड + +अनुरोध और प्रतिक्रियाएं अनटाइप्ड डिक्ट का उपयोग करती हैं। एजेंट स्तर पर कोई स्कीमा सत्यापन नहीं होता है - टूल सेवा अपने इनपुट को मान्य करने के लिए जिम्मेदार है। यह नई सेवाओं को परिभाषित करने के लिए अधिकतम लचीलापन प्रदान करता है। + +### क्लाइंट इंटरफ़ेस: डायरेक्ट पल्सर टॉपिक + +टूल सेवाएं प्रवाह कॉन्फ़िगरेशन की आवश्यकता के बिना डायरेक्ट पल्सर टॉपिक का उपयोग करती हैं। टूल-सेवा विवरणिका पूर्ण कतार नामों को निर्दिष्ट करती है: + +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [...] +} +``` + +यह सेवाओं को किसी भी नेमस्पेस में होस्ट करने की अनुमति देता है। + +### त्रुटि प्रबंधन: मानक त्रुटि सम्मेलन + +टूल सेवा प्रतिक्रियाएं मौजूदा स्कीमा सम्मेलन का पालन करती हैं, जिसमें एक `error` फ़ील्ड है: + +```python +@dataclass +class Error: + type: str = "" + message: str = "" +``` + +प्रतिक्रिया संरचना: +सफलता: `error` का मान `None` है, प्रतिक्रिया में परिणाम शामिल है +त्रुटि: `error` को `type` और `message` के मानों के साथ भरा जाता है + +यह मौजूदा सेवा स्कीमा में उपयोग किए गए पैटर्न से मेल खाता है (उदाहरण के लिए, `PromptResponse`, `QueryResponse`, `AgentResponse`)। + +### अनुरोध/प्रतिक्रिया सहसंबंध + +अनुरोधों और प्रतिक्रियाओं को पल्सर संदेश गुणों में एक `id` का उपयोग करके सहसंबंधित किया जाता है: + +अनुरोध में गुणों में `id` शामिल है: `properties={"id": id}` +प्रतिक्रिया(ओं) में समान `id` शामिल है: `properties={"id": id}` + +यह पूरे कोडबेस में उपयोग किए गए मौजूदा पैटर्न का अनुसरण करता है (उदाहरण के लिए, `agent_service.py`, `llm_service.py`)। + +### स्ट्रीमिंग समर्थन + +टूल सेवाएं स्ट्रीमिंग प्रतिक्रियाएं वापस कर सकती हैं: + +समान `id` वाले कई प्रतिक्रिया संदेश +प्रत्येक प्रतिक्रिया में `end_of_stream: bool` फ़ील्ड शामिल है +अंतिम प्रतिक्रिया में `end_of_stream: True` है + +यह `AgentResponse` और अन्य स्ट्रीमिंग सेवाओं में उपयोग किए गए पैटर्न से मेल खाता है। + +### प्रतिक्रिया हैंडलिंग: स्ट्रिंग रिटर्न + +सभी मौजूदा टूल समान पैटर्न का पालन करते हैं: **तर्कों को एक डिक्ट के रूप में प्राप्त करें, अवलोकन को एक स्ट्रिंग के रूप में वापस करें।** + +| टूल | प्रतिक्रिया हैंडलिंग | +|------|------------------| +| `KnowledgeQueryImpl` | `client.rag()` को सीधे वापस करता है (स्ट्रिंग) | +| `TextCompletionImpl` | `client.question()` को सीधे वापस करता है (स्ट्रिंग) | +| `McpToolImpl` | एक स्ट्रिंग वापस करता है, या यदि स्ट्रिंग नहीं है तो `json.dumps(output)` | +| `StructuredQueryImpl` | परिणाम को स्ट्रिंग में प्रारूपित करता है | +| `PromptImpl` | `client.prompt()` को सीधे वापस करता है (स्ट्रिंग) | + +टूल सेवाएं समान अनुबंध का पालन करती हैं: +सेवा एक स्ट्रिंग प्रतिक्रिया (अवलोकन) वापस करती है +यदि प्रतिक्रिया एक स्ट्रिंग नहीं है, तो इसे `json.dumps()` के माध्यम से परिवर्तित किया जाता है +वर्णनकर्ता में किसी निष्कर्षण कॉन्फ़िगरेशन की आवश्यकता नहीं है + +यह वर्णनकर्ता को सरल रखता है और सेवा पर एजेंट के लिए एक उपयुक्त पाठ प्रतिक्रिया वापस करने की जिम्मेदारी डालता है। + +## कॉन्फ़िगरेशन गाइड + +एक नई टूल सेवा जोड़ने के लिए, दो कॉन्फ़िगरेशन आइटम की आवश्यकता होती है: + +### 1. टूल सेवा कॉन्फ़िगरेशन + +`tool-service` कॉन्फ़िगरेशन कुंजी के अंतर्गत संग्रहीत। पल्सर कतारों और उपलब्ध कॉन्फ़िगरेशन मापदंडों को परिभाषित करता है। + +| फ़ील्ड | आवश्यक | विवरण | +|-------|----------|-------------| +| `id` | हाँ | टूल सेवा के लिए अद्वितीय पहचानकर्ता | +| `request-queue` | हाँ | अनुरोधों के लिए पूर्ण पल्सर विषय (उदाहरण के लिए, `non-persistent://tg/request/joke`) | +| `response-queue` | हाँ | प्रतिक्रियाओं के लिए पूर्ण पल्सर विषय (उदाहरण के लिए, `non-persistent://tg/response/joke`) | +| `config-params` | नहीं | सेवा द्वारा स्वीकार किए जाने वाले कॉन्फ़िगरेशन मापदंडों की सरणी | + +प्रत्येक कॉन्फ़िगरेशन पैरामीटर में निम्नलिखित निर्दिष्ट किया जा सकता है: +`name`: पैरामीटर नाम (आवश्यक) +`required`: क्या पैरामीटर को टूल द्वारा प्रदान किया जाना चाहिए (डिफ़ॉल्ट: झूठा) + +उदाहरण: +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [ + {"name": "style", "required": false} + ] +} +``` + +### 2. टूल कॉन्फ़िगरेशन + +`tool` कुंजी के अंतर्गत संग्रहीत। यह एक ऐसा टूल परिभाषित करता है जिसका उपयोग एजेंट कर सकता है। + +| फ़ील्ड | आवश्यक | विवरण | +|-------|----------|-------------| +| `type` | हाँ | यह `"tool-service"` होना चाहिए | +| `name` | हाँ | एलएलएम को प्रदर्शित होने वाला टूल नाम | +| `description` | हाँ | टूल क्या करता है इसका विवरण (एलएलएम को दिखाया जाता है) | +| `service` | हाँ | टूल-सर्विस का आईडी जिसे कॉल किया जाना है | +| `arguments` | नहीं | एलएलएम के लिए तर्क परिभाषाओं का सरणी | +| *(कॉन्फ़िगरेशन पैरामीटर)* | भिन्न | सेवा द्वारा परिभाषित कोई भी कॉन्फ़िगरेशन पैरामीटर | + +प्रत्येक तर्क में निम्नलिखित निर्दिष्ट किया जा सकता है: +`name`: तर्क का नाम (आवश्यक) +`type`: डेटा प्रकार, उदाहरण के लिए, `"string"` (आवश्यक) +`description`: एलएलएम को दिखाया जाने वाला विवरण (आवश्यक) + +उदाहरण: +```json +{ + "type": "tool-service", + "name": "tell-joke", + "description": "Tell a joke on a given topic", + "service": "joke-service", + "style": "pun", + "arguments": [ + { + "name": "topic", + "type": "string", + "description": "The topic for the joke (e.g., programming, animals, food)" + } + ] +} +``` + +### कॉन्फ़िगरेशन लोड करना + +कॉन्फ़िगरेशन लोड करने के लिए `tg-put-config-item` का उपयोग करें: + +```bash +# Load tool-service config +tg-put-config-item tool-service/joke-service < joke-service.json + +# Load tool config +tg-put-config-item tool/tell-joke < tell-joke.json +``` + +एजेंट-मैनेजर को नए कॉन्फ़िगरेशन को लागू करने के लिए पुनरारंभ किया जाना चाहिए। + +## कार्यान्वयन विवरण + +### स्कीमा + +`trustgraph-base/trustgraph/schema/services/tool_service.py` में अनुरोध और प्रतिक्रिया प्रकार: + +```python +@dataclass +class ToolServiceRequest: + user: str = "" # User context for multi-tenancy + config: str = "" # JSON-encoded config values from tool descriptor + arguments: str = "" # JSON-encoded arguments from LLM + +@dataclass +class ToolServiceResponse: + error: Error | None = None + response: str = "" # String response (the observation) + end_of_stream: bool = False +``` + +### सर्वर-साइड: डायनामिकटूलसर्विस + +`trustgraph-base/trustgraph/base/dynamic_tool_service.py` में बेस क्लास: + +```python +class DynamicToolService(AsyncProcessor): + """Base class for implementing tool services.""" + + def __init__(self, **params): + topic = params.get("topic", default_topic) + # Constructs topics: non-persistent://tg/request/{topic}, non-persistent://tg/response/{topic} + # Sets up Consumer and Producer + + async def invoke(self, user, config, arguments): + """Override this method to implement the tool's logic.""" + raise NotImplementedError() +``` + +### क्लाइंट-साइड: ToolServiceImpl + +`trustgraph-flow/trustgraph/agent/react/tools.py` में कार्यान्वयन: + +```python +class ToolServiceImpl: + def __init__(self, context, request_queue, response_queue, config_values, arguments, processor): + # Uses the provided queue paths directly + # Creates ToolServiceClient on first use + + async def invoke(self, **arguments): + client = await self._get_or_create_client() + response = await client.call(user, config_values, arguments) + return response if isinstance(response, str) else json.dumps(response) +``` + +### फ़ाइलें + +| फ़ाइल | उद्देश्य | +|------|---------| +| `trustgraph-base/trustgraph/schema/services/tool_service.py` | अनुरोध/प्रतिक्रिया स्कीमा | +| `trustgraph-base/trustgraph/base/tool_service_client.py` | सेवाओं को आमंत्रित करने के लिए क्लाइंट | +| `trustgraph-base/trustgraph/base/dynamic_tool_service.py` | सेवा कार्यान्वयन के लिए आधार वर्ग | +| `trustgraph-flow/trustgraph/agent/react/tools.py` | `ToolServiceImpl` वर्ग | +| `trustgraph-flow/trustgraph/agent/react/service.py` | कॉन्फ़िगरेशन लोडिंग | + +### उदाहरण: जोक सर्विस + +`trustgraph-flow/trustgraph/tool_service/joke/` में एक उदाहरण सेवा: + +```python +class Processor(DynamicToolService): + async def invoke(self, user, config, arguments): + style = config.get("style", "pun") + topic = arguments.get("topic", "") + joke = pick_joke(topic, style) + return f"Hey {user}! Here's a {style} for you:\n\n{joke}" +``` + +टूल सर्विस कॉन्फ़िगरेशन: +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [{"name": "style", "required": false}] +} +``` + +टूल कॉन्फ़िगरेशन: +```json +{ + "type": "tool-service", + "name": "tell-joke", + "description": "Tell a joke on a given topic", + "service": "joke-service", + "style": "pun", + "arguments": [ + {"name": "topic", "type": "string", "description": "The topic for the joke"} + ] +} +``` + +### पिछली अनुकूलता (पिछड़ी संगतता) + +मौजूदा अंतर्निहित टूल प्रकार बिना किसी बदलाव के काम करना जारी रखते हैं। +`tool-service` एक नया टूल प्रकार है जो मौजूदा प्रकारों (`knowledge-query`, `mcp-tool`, आदि) के साथ है। + +## भविष्य के विचार + +### स्व-घोषणा करने वाली सेवाएं + +एक भविष्य का सुधार सेवाओं को अपने स्वयं के विवरण प्रकाशित करने की अनुमति दे सकता है: + +सेवाएं स्टार्टअप पर एक ज्ञात `tool-descriptors` विषय पर प्रकाशित करती हैं। +एजेंट सदस्यता लेता है और गतिशील रूप से टूल पंजीकृत करता है। +यह वास्तविक प्लग-एंड-प्ले को कॉन्फ़िगरेशन परिवर्तनों के बिना सक्षम बनाता है। + +यह प्रारंभिक कार्यान्वयन के दायरे से बाहर है। + +## संदर्भ + +वर्तमान टूल कार्यान्वयन: `trustgraph-flow/trustgraph/agent/react/tools.py` +टूल पंजीकरण: `trustgraph-flow/trustgraph/agent/react/service.py:105-214` +एजेंट स्कीमा: `trustgraph-base/trustgraph/schema/services/agent.py` diff --git a/docs/tech-specs/tool-services.pt.md b/docs/tech-specs/tool-services.pt.md new file mode 100644 index 00000000..a6f8cf26 --- /dev/null +++ b/docs/tech-specs/tool-services.pt.md @@ -0,0 +1,471 @@ +# Serviços de Ferramentas: Ferramentas de Agente Dinamicamente Plugáveis + +## Status + +Implementado + +## Visão Geral + +Esta especificação define um mecanismo para ferramentas de agente dinamicamente plugáveis, chamadas "serviços de ferramentas". Ao contrário dos tipos de ferramentas integradas existentes (`KnowledgeQueryImpl`, `McpToolImpl`, etc.), os serviços de ferramentas permitem que novas ferramentas sejam introduzidas por: + +1. Implantando um novo serviço baseado em Pulsar +2. Adicionando um descritor de configuração que informa ao agente como invocá-lo + +Isso permite a extensibilidade sem modificar o framework de resposta do agente principal. + +## Terminologia + +| Termo | Definição | +|------|------------| +| **Ferramenta Integrada** | Tipos de ferramentas existentes com implementações codificadas em `tools.py` | +| **Serviço de Ferramenta** | Um serviço Pulsar que pode ser invocado como uma ferramenta de agente, definido por um descritor de serviço | +| **Ferramenta** | Uma instância configurada que referencia um serviço de ferramenta, exposta ao agente/LLM | + +Este é um modelo de duas camadas, análogo às ferramentas MCP: +MCP: O servidor MCP define a interface da ferramenta → A configuração da ferramenta a referencia +Serviços de Ferramenta: O serviço de ferramenta define a interface Pulsar → A configuração da ferramenta a referencia + +## Contexto: Ferramentas Existentes + +### Implementação de Ferramenta Integrada + +As ferramentas são atualmente definidas em `trustgraph-flow/trustgraph/agent/react/tools.py` com implementações tipadas: + +```python +class KnowledgeQueryImpl: + async def invoke(self, question): + client = self.context("graph-rag-request") + return await client.rag(question, self.collection) +``` + +Cada tipo de ferramenta: +Possui um serviço Pulsar pré-definido que ele chama (por exemplo, `graph-rag-request`) +Conhece o método exato a ser chamado no cliente (por exemplo, `client.rag()`) +Possui argumentos tipados definidos na implementação + +### Registro de Ferramentas (service.py:105-214) + +As ferramentas são carregadas da configuração com um campo `type` que mapeia para uma implementação: + +```python +if impl_id == "knowledge-query": + impl = functools.partial(KnowledgeQueryImpl, collection=data.get("collection")) +elif impl_id == "text-completion": + impl = TextCompletionImpl +# ... etc +``` + +## Arquitetura + +### Modelo de Duas Camadas + +#### Camada 1: Descritor do Serviço de Ferramenta + +Um serviço de ferramenta define uma interface de serviço Pulsar. Ele declara: +As filas Pulsar para solicitação/resposta +Os parâmetros de configuração que ele requer das ferramentas que o utilizam + +```json +{ + "id": "custom-rag", + "request-queue": "non-persistent://tg/request/custom-rag", + "response-queue": "non-persistent://tg/response/custom-rag", + "config-params": [ + {"name": "collection", "required": true} + ] +} +``` + +Um serviço de ferramenta que não requer parâmetros de configuração: + +```json +{ + "id": "calculator", + "request-queue": "non-persistent://tg/request/calc", + "response-queue": "non-persistent://tg/response/calc", + "config-params": [] +} +``` + +#### Nível 2: Descritor de Ferramenta + +Uma ferramenta referencia um serviço de ferramenta e fornece: +Valores de parâmetros de configuração (que satisfazem os requisitos do serviço) +Metadados da ferramenta para o agente (nome, descrição) +Definições de argumentos para o LLM + +```json +{ + "type": "tool-service", + "name": "query-customers", + "description": "Query the customer knowledge base", + "service": "custom-rag", + "collection": "customers", + "arguments": [ + { + "name": "question", + "type": "string", + "description": "The question to ask about customers" + } + ] +} +``` + +Múltiplas ferramentas podem referenciar o mesmo serviço com diferentes configurações: + +```json +{ + "type": "tool-service", + "name": "query-products", + "description": "Query the product knowledge base", + "service": "custom-rag", + "collection": "products", + "arguments": [ + { + "name": "question", + "type": "string", + "description": "The question to ask about products" + } + ] +} +``` + +### Formato da Requisição + +Quando uma ferramenta é invocada, a requisição ao serviço da ferramenta inclui: +`user`: Do pedido do agente (multi-tenência) +`config`: Valores de configuração codificados em JSON, provenientes da descrição da ferramenta +`arguments`: Argumentos codificados em JSON, provenientes do LLM + +```json +{ + "user": "alice", + "config": "{\"collection\": \"customers\"}", + "arguments": "{\"question\": \"What are the top customer complaints?\"}" +} +``` + +O serviço de ferramenta recebe estes como dicionários analisados no método `invoke`. + +### Implementação Genérica do Serviço de Ferramenta + +Uma classe `ToolServiceImpl` invoca serviços de ferramenta com base na configuração: + +```python +class ToolServiceImpl: + def __init__(self, context, request_queue, response_queue, config_values, arguments, processor): + self.request_queue = request_queue + self.response_queue = response_queue + self.config_values = config_values # e.g., {"collection": "customers"} + # ... + + async def invoke(self, **arguments): + client = await self._get_or_create_client() + response = await client.call(user, self.config_values, arguments) + if isinstance(response, str): + return response + else: + return json.dumps(response) +``` + +## Decisões de Design + +### Modelo de Configuração de Duas Camadas + +Os serviços de ferramentas seguem um modelo de duas camadas semelhante às ferramentas MCP: + +1. **Serviço de Ferramenta**: Define a interface do serviço Pulsar (tópico, parâmetros de configuração necessários) +2. **Ferramenta**: Referencia um serviço de ferramenta, fornece valores de configuração, define argumentos do LLM + +Essa separação permite: +Que um único serviço de ferramenta seja usado por várias ferramentas com diferentes configurações +Uma distinção clara entre a interface do serviço e a configuração da ferramenta +A reutilização das definições de serviço + +### Mapeamento de Solicitações: Transmissão com Envelope + +A solicitação a um serviço de ferramenta é um envelope estruturado contendo: +`user`: Propagado do pedido do agente para multi-inquilinato +Valores de configuração: Do descritor da ferramenta (por exemplo, `collection`) +`arguments`: Argumentos fornecidos pelo LLM, transmitidos como um dicionário + +O gerenciador de agente analisa a resposta do LLM em `act.arguments` como um dicionário (`agent_manager.py:117-154`). Este dicionário é incluído no envelope da solicitação. + +### Tratamento de Esquemas: Não Tipados + +As solicitações e respostas usam dicionários não tipados. Não há validação de esquema no nível do agente - o serviço de ferramenta é responsável por validar suas entradas. Isso fornece o máximo de flexibilidade para definir novos serviços. + +### Interface do Cliente: Tópicos Pulsar Diretos + +Os serviços de ferramentas usam tópicos Pulsar diretos, sem a necessidade de configuração de fluxo. O descritor do serviço de ferramenta especifica os nomes completos das filas: + +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [...] +} +``` + +Isso permite que os serviços sejam hospedados em qualquer namespace. + +### Tratamento de Erros: Convenção de Erro Padrão + +As respostas do serviço de ferramenta seguem a convenção de esquema existente com um campo `error`: + +```python +@dataclass +class Error: + type: str = "" + message: str = "" +``` + +Estrutura da resposta: +Sucesso: `error` é `None`, a resposta contém o resultado +Erro: `error` é preenchido com `type` e `message` + +Isso corresponde ao padrão usado em todo o serviço existente (por exemplo, `PromptResponse`, `QueryResponse`, `AgentResponse`). + +### Correlação de Requisições/Respostas + +As requisições e respostas são correlacionadas usando um `id` nas propriedades da mensagem Pulsar: + +A requisição inclui `id` nas propriedades: `properties={"id": id}` +A(s) resposta(s) incluem o mesmo `id`: `properties={"id": id}` + +Isso segue o padrão existente usado em todo o código-fonte (por exemplo, `agent_service.py`, `llm_service.py`). + +### Suporte a Streaming + +Os serviços de ferramenta podem retornar respostas em streaming: + +Múltiplas mensagens de resposta com o mesmo `id` nas propriedades +Cada resposta inclui o campo `end_of_stream: bool` +A resposta final tem `end_of_stream: True` + +Isso corresponde ao padrão usado em `AgentResponse` e outros serviços de streaming. + +### Tratamento da Resposta: Retorno de String + +Todas as ferramentas existentes seguem o mesmo padrão: **receber argumentos como um dicionário, retornar a observação como uma string**. + +| Ferramenta | Tratamento da Resposta | +|------|------------------| +| `KnowledgeQueryImpl` | Retorna `client.rag()` diretamente (string) | +| `TextCompletionImpl` | Retorna `client.question()` diretamente (string) | +| `McpToolImpl` | Retorna uma string, ou `json.dumps(output)` se não for uma string | +| `StructuredQueryImpl` | Formata o resultado para uma string | +| `PromptImpl` | Retorna `client.prompt()` diretamente (string) | + +Os serviços de ferramenta seguem o mesmo contrato: +O serviço retorna uma resposta em string (a observação) +Se a resposta não for uma string, ela é convertida via `json.dumps()` +Nenhuma configuração de extração é necessária no descritor + +Isso mantém o descritor simples e coloca a responsabilidade de retornar uma resposta de texto apropriada para o agente no serviço. + +## Guia de Configuração + +Para adicionar um novo serviço de ferramenta, são necessários dois itens de configuração: + +### 1. Configuração do Serviço de Ferramenta + +Armazenado sob a chave de configuração `tool-service`. Define as filas Pulsar e os parâmetros de configuração disponíveis. + +| Campo | Obrigatório | Descrição | +|-------|----------|-------------| +| `id` | Sim | Identificador único para o serviço de ferramenta | +| `request-queue` | Sim | Tópico Pulsar completo para requisições (por exemplo, `non-persistent://tg/request/joke`) | +| `response-queue` | Sim | Tópico Pulsar completo para respostas (por exemplo, `non-persistent://tg/response/joke`) | +| `config-params` | Não | Array de parâmetros de configuração que o serviço aceita | + +Cada parâmetro de configuração pode especificar: +`name`: Nome do parâmetro (obrigatório) +`required`: Se o parâmetro deve ser fornecido pelas ferramentas (padrão: falso) + +Exemplo: +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [ + {"name": "style", "required": false} + ] +} +``` + +### 2. Configuração da Ferramenta + +Armazenado sob a chave de configuração `tool`. Define uma ferramenta que o agente pode usar. + +| Campo | Obrigatório | Descrição | +|-------|----------|-------------| +| `type` | Sim | Deve ser `"tool-service"` | +| `name` | Sim | Nome da ferramenta exposto para o LLM | +| `description` | Sim | Descrição do que a ferramenta faz (mostrada para o LLM) | +| `service` | Sim | ID do serviço de ferramenta a ser invocado | +| `arguments` | Não | Array de definições de argumentos para o LLM | +| *(parâmetros de configuração)* | Varia | Quaisquer parâmetros de configuração definidos pelo serviço | + +Cada argumento pode especificar: +`name`: Nome do argumento (obrigatório) +`type`: Tipo de dados, por exemplo, `"string"` (obrigatório) +`description`: Descrição mostrada para o LLM (obrigatório) + +Exemplo: +```json +{ + "type": "tool-service", + "name": "tell-joke", + "description": "Tell a joke on a given topic", + "service": "joke-service", + "style": "pun", + "arguments": [ + { + "name": "topic", + "type": "string", + "description": "The topic for the joke (e.g., programming, animals, food)" + } + ] +} +``` + +### Carregando a Configuração + +Use `tg-put-config-item` para carregar as configurações: + +```bash +# Load tool-service config +tg-put-config-item tool-service/joke-service < joke-service.json + +# Load tool config +tg-put-config-item tool/tell-joke < tell-joke.json +``` + +O agente-gerenciador deve ser reiniciado para aplicar novas configurações. + +## Detalhes da Implementação + +### Esquema + +Tipos de requisição e resposta em `trustgraph-base/trustgraph/schema/services/tool_service.py`: + +```python +@dataclass +class ToolServiceRequest: + user: str = "" # User context for multi-tenancy + config: str = "" # JSON-encoded config values from tool descriptor + arguments: str = "" # JSON-encoded arguments from LLM + +@dataclass +class ToolServiceResponse: + error: Error | None = None + response: str = "" # String response (the observation) + end_of_stream: bool = False +``` + +### Servidor: DynamicToolService + +Classe base em `trustgraph-base/trustgraph/base/dynamic_tool_service.py`: + +```python +class DynamicToolService(AsyncProcessor): + """Base class for implementing tool services.""" + + def __init__(self, **params): + topic = params.get("topic", default_topic) + # Constructs topics: non-persistent://tg/request/{topic}, non-persistent://tg/response/{topic} + # Sets up Consumer and Producer + + async def invoke(self, user, config, arguments): + """Override this method to implement the tool's logic.""" + raise NotImplementedError() +``` + +### Cliente: ToolServiceImpl + +Implementação em `trustgraph-flow/trustgraph/agent/react/tools.py`: + +```python +class ToolServiceImpl: + def __init__(self, context, request_queue, response_queue, config_values, arguments, processor): + # Uses the provided queue paths directly + # Creates ToolServiceClient on first use + + async def invoke(self, **arguments): + client = await self._get_or_create_client() + response = await client.call(user, config_values, arguments) + return response if isinstance(response, str) else json.dumps(response) +``` + +### Arquivos + +| Arquivo | Propósito | +|------|---------| +| `trustgraph-base/trustgraph/schema/services/tool_service.py` | Esquemas de requisição/resposta | +| `trustgraph-base/trustgraph/base/tool_service_client.py` | Cliente para invocar serviços | +| `trustgraph-base/trustgraph/base/dynamic_tool_service.py` | Classe base para implementação de serviço | +| `trustgraph-flow/trustgraph/agent/react/tools.py` | Classe `ToolServiceImpl` | +| `trustgraph-flow/trustgraph/agent/react/service.py` | Carregamento de configuração | + +### Exemplo: Serviço de Piadas + +Um exemplo de serviço em `trustgraph-flow/trustgraph/tool_service/joke/`: + +```python +class Processor(DynamicToolService): + async def invoke(self, user, config, arguments): + style = config.get("style", "pun") + topic = arguments.get("topic", "") + joke = pick_joke(topic, style) + return f"Hey {user}! Here's a {style} for you:\n\n{joke}" +``` + +Configuração do serviço de ferramenta: +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [{"name": "style", "required": false}] +} +``` + +Configuração da ferramenta: +```json +{ + "type": "tool-service", + "name": "tell-joke", + "description": "Tell a joke on a given topic", + "service": "joke-service", + "style": "pun", + "arguments": [ + {"name": "topic", "type": "string", "description": "The topic for the joke"} + ] +} +``` + +### Compatibilidade com versões anteriores + +Os tipos de ferramentas integradas existentes continuam a funcionar sem alterações. +`tool-service` é um novo tipo de ferramenta, juntamente com os tipos existentes (`knowledge-query`, `mcp-tool`, etc.). + +## Considerações futuras + +### Serviços de autoanúncio + +Uma melhoria futura poderia permitir que os serviços publicassem seus próprios descritores: + +Os serviços publicam em um tópico `tool-descriptors` conhecido na inicialização. +O agente se inscreve e registra dinamicamente as ferramentas. +Permite um verdadeiro sistema de plug-and-play sem alterações de configuração. + +Isso está fora do escopo da implementação inicial. + +## Referências + +Implementação atual da ferramenta: `trustgraph-flow/trustgraph/agent/react/tools.py` +Registro de ferramentas: `trustgraph-flow/trustgraph/agent/react/service.py:105-214` +Esquemas do agente: `trustgraph-base/trustgraph/schema/services/agent.py` diff --git a/docs/tech-specs/tool-services.sw.md b/docs/tech-specs/tool-services.sw.md new file mode 100644 index 00000000..564ca365 --- /dev/null +++ b/docs/tech-specs/tool-services.sw.md @@ -0,0 +1,471 @@ +# Huduma za Zana: Zana za Wakala Zinazoweza Kuunganishwa Kwenye Mfumo + +## Hali + +Imetekelezwa + +## Muhtasari + +Maelezo haya yanafafanua mfumo wa zana za wakala ambazo zinaweza kuunganishwa kwenye mfumo, zinazojulikana kama "huduma za zana". Tofauti na aina za zana zilizojumuishwa awali (`KnowledgeQueryImpl`, `McpToolImpl`, n.k.), huduma za zana huruhusu zana mpya kuletwa kwa: + +1. Kuanzisha huduma mpya iliyojengwa kwenye Pulsar +2. Kuongeza maelezo ya usanidi ambayo huambia wakala jinsi ya kuiita + +Hii inaruhusu uboreshaji bila kubadilisha mfumo msingi wa wakala. + +## Dhana + +| Neno | Ufafanuzi | +|------|------------| +| **Zana Iliyojumuishwa** | Aina za zana zilizopo zilizo na matumizi yaliyopangwa mapema katika `tools.py` | +| **Huduma ya Zana** | Huduma ya Pulsar ambayo inaweza kuita kama zana ya wakala, iliyoainishwa na maelezo ya huduma | +| **Zana** | Toleo lililosanidiwa ambalo linarejelea huduma ya zana, lililowezeshwa kwa wakala/LLM | + +Hii ni mfumo wa tabaka mbili, sawa na zana za MCP: +MCP: Seva ya MCP inaainisha kiolesura cha zana → Usanidi wa zana huirejelea +Huduma za Zana: Huduma ya zana inaainisha kiolesura cha Pulsar → Usanidi wa zana huirejelea + +## Asili: Zana Zilizopo + +### Utendaji wa Zana Iliyojumuishwa + +Zana kwa sasa zinafafanuliwa katika `trustgraph-flow/trustgraph/agent/react/tools.py` na matumizi yaliyopangwa: + +```python +class KnowledgeQueryImpl: + async def invoke(self, question): + client = self.context("graph-rag-request") + return await client.rag(question, self.collection) +``` + +Kila aina ya zana: +Ina huduma ya Pulsar iliyopangwa tayari ambayo inaitumia (k.m., `graph-rag-request`) +Inajua njia sahihi ya kuita kwenye mteja (k.m., `client.rag()`) +Ina vigezo vilivyopangwa ambavyo vimefafuliwa katika utekelezaji + +### Usajili wa Zana (service.py:105-214) + +Zana huzamilishwa kutoka kwa usanidi na sehemu ya `type` ambayo inaelekeza kwenye utekelezaji: + +```python +if impl_id == "knowledge-query": + impl = functools.partial(KnowledgeQueryImpl, collection=data.get("collection")) +elif impl_id == "text-completion": + impl = TextCompletionImpl +# ... etc +``` + +## Usanifu + +### Mfumo wa Tabaka Mbili + +#### Tabaka la 1: Kisajili cha Huduma ya Zana + +Huduma ya zana inaelezea kiolesura cha huduma ya Pulsar. Inaangazia: +Mizinga ya Pulsar kwa ombi/jibu +Vigezo vya usanidi ambavyo vinahitajika na zana zinazotumia huduma hiyo + +```json +{ + "id": "custom-rag", + "request-queue": "non-persistent://tg/request/custom-rag", + "response-queue": "non-persistent://tg/response/custom-rag", + "config-params": [ + {"name": "collection", "required": true} + ] +} +``` + +Huduma ya zana ambayo haihitaji vigezo vya usanidi: + +```json +{ + "id": "calculator", + "request-queue": "non-persistent://tg/request/calc", + "response-queue": "non-persistent://tg/response/calc", + "config-params": [] +} +``` + +#### Kategoria ya 2: Kisajili cha Zana + +Zana inarejelea huduma ya zana na hutoa: +Maelezo ya vigezo ya usanidi (yakinayo na mahitaji ya huduma) +Meta-data ya zana kwa wakala (jina, maelezo) +Ufafanuzi wa hoja kwa mfumo wa lugha (LLM) + +```json +{ + "type": "tool-service", + "name": "query-customers", + "description": "Query the customer knowledge base", + "service": "custom-rag", + "collection": "customers", + "arguments": [ + { + "name": "question", + "type": "string", + "description": "The question to ask about customers" + } + ] +} +``` + +Zana nyingi zinaweza kurejelea huduma moja kwa usanidi tofauti: + +```json +{ + "type": "tool-service", + "name": "query-products", + "description": "Query the product knowledge base", + "service": "custom-rag", + "collection": "products", + "arguments": [ + { + "name": "question", + "type": "string", + "description": "The question to ask about products" + } + ] +} +``` + +### Muundo wa Ombi + +Wakati zana inaitwa, ombi kwa huduma ya zana linajumuisha: +`user`: Kutoka ombi la wakala (utumiaji wa pamoja) +`config`: Maelezo ya usanidi yaliyokandwa katika umbizo la JSON kutoka kwa maelezo ya zana +`arguments`: Majadilisho yaliyokandwa katika umbizo la JSON kutoka kwa mfumo wa lugha kubwa (LLM) + +```json +{ + "user": "alice", + "config": "{\"collection\": \"customers\"}", + "arguments": "{\"question\": \"What are the top customer complaints?\"}" +} +``` + +Huduma ya zana hupokea haya kama dictionaries yaliyochanganishwa katika njia ya `invoke`. + +### Utendakazi wa Huduma ya Zana ya Jumla + +Darasa la `ToolServiceImpl` huita huduma za zana kulingana na usanidi: + +```python +class ToolServiceImpl: + def __init__(self, context, request_queue, response_queue, config_values, arguments, processor): + self.request_queue = request_queue + self.response_queue = response_queue + self.config_values = config_values # e.g., {"collection": "customers"} + # ... + + async def invoke(self, **arguments): + client = await self._get_or_create_client() + response = await client.call(user, self.config_values, arguments) + if isinstance(response, str): + return response + else: + return json.dumps(response) +``` + +## Maamuzi ya Ubunifu + +### Mfumo wa Uwekaji wa Tabaka Mbili + +Huduma za zana zinafuata mfumo wa tabaka mbili, sawa na zana za MCP: + +1. **Huduma ya Zana**: Inaelezea kiolesura cha huduma ya Pulsar (mada, vigezo muhimu vya usanidi) +2. **Zana**: Inarejelea huduma ya zana, hutoa maadili ya usanidi, inaelezea hoja za LLM + +Tofauti hii inaruhusu: +Huduma moja ya zana kutumika na zana nyingi zenye usanidi tofauti +Tofauti wazi kati ya kiolesura cha huduma na usanidi wa zana +Ujuzi wa matumizi wa maelezo ya huduma + +### Ramani ya Ombi: Kupitisha na Kifurushi + +Ombi kwa huduma ya zana ni kifurushi kilicho na muundo, kinachojumuisha: +`user`: Inasambazwa kutoka ombi la wakala kwa ajili ya utumiaji wa pamoja +Maadili ya usanidi: Kutoka kwa maelezo ya zana (k.m., `collection`) +`arguments`: Hoja zilizotolewa na LLM, zinazopitishwa kama kamusi + +Kidhibiti cha wakala huchanganua jibu la LLM kuwa `act.arguments` kama kamusi (`agent_manager.py:117-154`). Kamusi hii inajumuishwa katika kifurushi cha ombi. + +### Usimamizi wa Mpango: Bila Aina + +Maombi na majibu hutumia kamusi zisizo na aina. Hakuna uthibitishaji wa mpango katika ngazi ya wakala - huduma ya zana inawajibika kwa uthibitishaji wa pembejeo zake. Hii hutoa uwezo mkubwa wa kufafanua huduma mpya. + +### Kiolesura cha Mteja: Mada za Moja kwa Moja za Pulsar + +Huduma za zana hutumia mada za moja kwa moja za Pulsar bila kuhitaji usanidi wa mtiririko. Maelezo ya huduma-ya-zana yanaelezea majina kamili ya folyo: + +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [...] +} +``` + +Hii inaruhusu huduma kuwa zimepakwa kwenye nafasi yoyote. + +### Usimamizi wa Makosa: Mfumo wa Makosa wa Kawaida + +Majibu ya huduma ya zana yanafuata mfumo wa sasa wa muundo na sehemu ya `error`: + +```python +@dataclass +class Error: + type: str = "" + message: str = "" +``` + +Muundo wa majibu: +Mafanikio: `error` ni `None`, majibu yana matokeo +Kosa: `error` imejaa na `type` na `message` + +Hii inafanana na muundo uliotumika katika huduma zingine (e.g., `PromptResponse`, `QueryResponse`, `AgentResponse`). + +### Uhusiano wa Ombi/Jibu + +Maombi na majibu yanahusishwa kwa kutumia `id` katika vipengele vya ujumbe wa Pulsar: + +Ombi linajumuisha `id` katika vipengele: `properties={"id": id}` +Majibu (mengi) yanajumuisha `id` sawa: `properties={"id": id}` + +Hii inafuata muundo uliopo katika codebase (e.g., `agent_service.py`, `llm_service.py`). + +### Usaidizi wa Uhamaji (Streaming) + +Huduma za zana zinaweza kurejesha majibu ya uhamaji: + +Ujumbe mwingi wa majibu wenye `id` sawa katika vipengele +Kila jibu linajumuisha `end_of_stream: bool` +Jibu la mwisho lina `end_of_stream: True` + +Hii inafanana na muundo uliotumika katika `AgentResponse` na huduma zingine za uhamaji. + +### Usimamizi wa Majibu: Kurudisha Kamba (String) + +Zana zote zilizopo zinafuata muundo huo: **kupokea hoja kama orodha, kurejesha matokeo kama kamba**. + +| Zana | Usimamizi wa Majibu | +|------|------------------| +| `KnowledgeQueryImpl` | Inarejea `client.rag()` moja kwa moja (kamba) | +| `TextCompletionImpl` | Inarejea `client.question()` moja kwa moja (kamba) | +| `McpToolImpl` | Inarejea kamba, au `json.dumps(output)` ikiwa si kamba | +| `StructuredQueryImpl` | Inaweka matokeo katika kamba | +| `PromptImpl` | Inarejea `client.prompt()` moja kwa moja (kamba) | + +Huduma za zana zinafuata mkataba huo: +Huduma inarejea jibu la kamba (matokeo) +Ikiwa jibu si kamba, linabadilishwa kupitia `json.dumps()` +Hakuna usanidi wa uondoaji unaohitajika katika maelezo + +Hii huweka maelezo kuwa rahisi na kuweka jukumu kwa huduma kurejesha jibu la maandishi linalofaa kwa wakala. + +## Mwongozo wa Usanidi + +Ili kuongeza huduma mpya ya zana, vipengele viwili vya usanidi vinahitajika: + +### 1. Usanidi wa Huduma ya Zana + +Inahifadhiwa chini ya ufunguo wa usanidi `tool-service`. Inaelezea folyo za Pulsar na vigezo vinavyopatikana vya usanidi. + +| Uwanja | Inahitajika | Maelezo | +|-------|----------|-------------| +| `id` | Ndiyo | Kitambulisho cha kipekee kwa huduma ya zana | +| `request-queue` | Ndiyo | Mada kamili ya Pulsar kwa maombi (e.g., `non-persistent://tg/request/joke`) | +| `response-queue` | Ndiyo | Mada kamili ya Pulsar kwa majibu (e.g., `non-persistent://tg/response/joke`) | +| `config-params` | Hapana | Safu ya vigezo vya usanidi ambavyo huduma inakubali | + +Kila kiparamu cha usanidi kinaweza kuainisha: +`name`: Jina la kiparamu (inahitajika) +`required`: Ikiwa kiparamu lazima kipewe na zana (cha kawaida: bandia) + +Mfano: +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [ + {"name": "style", "required": false} + ] +} +``` + +### 2. Usanidi wa Zana + +Hifadhiwa chini ya ufunguo wa `tool`. Inaelezea zana ambayo wakala anaweza kutumia. + +| Sehemu | Inahitajika | Maelezo | +|-------|----------|-------------| +| `type` | Ndiyo | Lazima iwe `"tool-service"` | +| `name` | Ndiyo | Jina la zana linaloonyeshwa kwa LLM | +| `description` | Ndiyo | Maelezo ya kile ambacho zana inafanya (yanaonyeshwa kwa LLM) | +| `service` | Ndiyo | Kitambulisho cha huduma ya zana inayotumiwa | +| `arguments` | Hapana | Safu ya maelezo ya hoja kwa ajili ya LLM | +| *(vigezo vya usanidi)* | Hubadilika | Vigezo vyovyote vya usanidi vilivyobainishwa na huduma | + +Kila hoja inaweza kubainisha: +`name`: Jina la hoja (inahitajika) +`type`: Aina ya data, kwa mfano, `"string"` (inahitajika) +`description`: Maelezo yanayoonyeshwa kwa LLM (inahitajika) + +Mfano: +```json +{ + "type": "tool-service", + "name": "tell-joke", + "description": "Tell a joke on a given topic", + "service": "joke-service", + "style": "pun", + "arguments": [ + { + "name": "topic", + "type": "string", + "description": "The topic for the joke (e.g., programming, animals, food)" + } + ] +} +``` + +### Upakiaji wa Mipangilio + +Tumia `tg-put-config-item` ili kupakia mipangilio: + +```bash +# Load tool-service config +tg-put-config-item tool-service/joke-service < joke-service.json + +# Load tool config +tg-put-config-item tool/tell-joke < tell-joke.json +``` + +Wakala-mtawala lazima uanzishwe tena ili kuchukua usanidi mpya. + +## Maelezo ya Utendaji + +### Mpango + +Aina za ombi na majibu katika `trustgraph-base/trustgraph/schema/services/tool_service.py`: + +```python +@dataclass +class ToolServiceRequest: + user: str = "" # User context for multi-tenancy + config: str = "" # JSON-encoded config values from tool descriptor + arguments: str = "" # JSON-encoded arguments from LLM + +@dataclass +class ToolServiceResponse: + error: Error | None = None + response: str = "" # String response (the observation) + end_of_stream: bool = False +``` + +### Upande wa Server: Huduma ya DynamicToolService + +Darasa la msingi katika `trustgraph-base/trustgraph/base/dynamic_tool_service.py`: + +```python +class DynamicToolService(AsyncProcessor): + """Base class for implementing tool services.""" + + def __init__(self, **params): + topic = params.get("topic", default_topic) + # Constructs topics: non-persistent://tg/request/{topic}, non-persistent://tg/response/{topic} + # Sets up Consumer and Producer + + async def invoke(self, user, config, arguments): + """Override this method to implement the tool's logic.""" + raise NotImplementedError() +``` + +### Upande wa Mteja: Huduma ya ToolServiceImpl + +Utendaji katika `trustgraph-flow/trustgraph/agent/react/tools.py`: + +```python +class ToolServiceImpl: + def __init__(self, context, request_queue, response_queue, config_values, arguments, processor): + # Uses the provided queue paths directly + # Creates ToolServiceClient on first use + + async def invoke(self, **arguments): + client = await self._get_or_create_client() + response = await client.call(user, config_values, arguments) + return response if isinstance(response, str) else json.dumps(response) +``` + +### Faili + +| Faili | Madhumuni | +|------|---------| +| `trustgraph-base/trustgraph/schema/services/tool_service.py` | Mifumo ya ombi/jibu | +| `trustgraph-base/trustgraph/base/tool_service_client.py` | Mteja wa kutumia huduma | +| `trustgraph-base/trustgraph/base/dynamic_tool_service.py` | Darasa la msingi kwa utekelezaji wa huduma | +| `trustgraph-flow/trustgraph/agent/react/tools.py` | Darasa la `ToolServiceImpl` | +| `trustgraph-flow/trustgraph/agent/react/service.py` | Kupakia usanidi | + +### Mifano: Huduma ya Utani + +Mfano wa huduma katika `trustgraph-flow/trustgraph/tool_service/joke/`: + +```python +class Processor(DynamicToolService): + async def invoke(self, user, config, arguments): + style = config.get("style", "pun") + topic = arguments.get("topic", "") + joke = pick_joke(topic, style) + return f"Hey {user}! Here's a {style} for you:\n\n{joke}" +``` + +Usanidi wa huduma za zana: +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [{"name": "style", "required": false}] +} +``` + +Usanidi wa zana: +```json +{ + "type": "tool-service", + "name": "tell-joke", + "description": "Tell a joke on a given topic", + "service": "joke-service", + "style": "pun", + "arguments": [ + {"name": "topic", "type": "string", "description": "The topic for the joke"} + ] +} +``` + +### Ulinganishi na Matoleo ya Zamani + +Aina za zana zilizopo zilizojumuishwa zinaendelea kufanya kazi bila kubadilishwa. +`tool-service` ni aina mpya ya zana pamoja na aina zilizopo (`knowledge-query`, `mcp-tool`, n.k.). + +## Mambo ya Kuzingatia Baadaye + +### Huduma Zinajitangaza Zenyewe + +Uboreshaji wa siku zijazo unaweza kuruhusu huduma kuchapisha maelezo yao wenyewe: + +Huduma huchapisha kwenye mada iliyojulikana ya `tool-descriptors` wakati wa kuanza. +Wakala husajili na kusajili zana kwa njia ya moja kwa moja. +Inaruhusu uunganishaji halisi wa "plug-and-play" bila mabadiliko ya usanidi. + +Hii ni nje ya upeo wa utekelezaji wa awali. + +## Marejeleo + +Utaratibu wa sasa wa zana: `trustgraph-flow/trustgraph/agent/react/tools.py` +Usajili wa zana: `trustgraph-flow/trustgraph/agent/react/service.py:105-214` +Schemas za wakala: `trustgraph-base/trustgraph/schema/services/agent.py` diff --git a/docs/tech-specs/tool-services.tr.md b/docs/tech-specs/tool-services.tr.md new file mode 100644 index 00000000..7a2c6cba --- /dev/null +++ b/docs/tech-specs/tool-services.tr.md @@ -0,0 +1,471 @@ +# Araç Hizmetleri: Dinamik Olarak Eklenebilen Ajan Araçları + +## Durum + +Uygulandı + +## Genel Bakış + +Bu özellik, "araç hizmetleri" olarak adlandırılan, dinamik olarak eklenebilen ajan araçları için bir mekanizma tanımlar. Mevcut, yerleşik araç türlerinin (`KnowledgeQueryImpl`, `McpToolImpl`, vb.) aksine, araç hizmetleri, aşağıdaki yöntemlerle yeni araçların eklenmesine olanak tanır: + +1. Yeni bir Pulsar tabanlı hizmetin dağıtılması +2. Ajanın hizmeti nasıl çağıracağını belirten bir yapılandırma açıklamasının eklenmesi + +Bu, çekirdek ajan-yanıt çerçevesini değiştirmeden genişletilebilirlik sağlar. + +## Terminoloji + +| Terim | Tanım | +|------|------------| +| **Yerleşik Araç** | `tools.py` içinde sabit kodlanmış uygulamalara sahip mevcut araç türleri | +| **Araç Hizmeti** | Bir hizmet açıklamasıyla tanımlanan ve bir ajan aracı olarak çağrılabilecek bir Pulsar hizmeti | +| **Araç** | Bir hizmet aracını referans alan ve ajana/LLM'ye sunulan yapılandırılmış bir örnek | + +Bu, MCP araçlarına benzer iki katmanlı bir modeldir: +MCP: MCP sunucusu araç arayüzünü tanımlar → Araç yapılandırması buna başvurur +Araç Hizmetleri: Araç hizmeti Pulsar arayüzünü tanımlar → Araç yapılandırması buna başvurur + +## Arka Plan: Mevcut Araçlar + +### Yerleşik Araç Uygulaması + +Araçlar şu anda `trustgraph-flow/trustgraph/agent/react/tools.py` içinde, türlenmiş uygulamalarla tanımlanmıştır: + +```python +class KnowledgeQueryImpl: + async def invoke(self, question): + client = self.context("graph-rag-request") + return await client.rag(question, self.collection) +``` + +Her araç türü: +Çağırdığı sabit kodlu bir Pulsar servisine sahiptir (örneğin, `graph-rag-request`) +İstemci üzerinde çağrılacak kesin yöntemi bilir (örneğin, `client.rag()`) +Uygulamada tanımlanmış türlü argümanlara sahiptir + +### Araç Kaydı (service.py:105-214) + +Araçlar, bir uygulamaya eşleyen `type` alanıyla yapılandırmadan yüklenir: + +```python +if impl_id == "knowledge-query": + impl = functools.partial(KnowledgeQueryImpl, collection=data.get("collection")) +elif impl_id == "text-completion": + impl = TextCompletionImpl +# ... etc +``` + +## Mimari + +### İki Katmanlı Model + +#### 1. Katman: Araç Hizmeti Tanımlayıcısı + +Bir araç hizmeti, bir Pulsar hizmeti arayüzünü tanımlar. Aşağıdakileri belirtir: +İstek/yanıt için kullanılan Pulsar kuyrukları +Onu kullanan araçlardan gerektirdiği yapılandırma parametreleri + +```json +{ + "id": "custom-rag", + "request-queue": "non-persistent://tg/request/custom-rag", + "response-queue": "non-persistent://tg/response/custom-rag", + "config-params": [ + {"name": "collection", "required": true} + ] +} +``` + +Herhangi bir yapılandırma parametresine ihtiyaç duymayan bir araç hizmeti: + +```json +{ + "id": "calculator", + "request-queue": "non-persistent://tg/request/calc", + "response-queue": "non-persistent://tg/response/calc", + "config-params": [] +} +``` + +#### 2. Seviye: Araç Açıklaması + +Bir araç, bir araç hizmetine başvurur ve şunları sağlar: +Yapılandırma parametre değerleri (hizmetin gereksinimlerini karşılar) +Aracının ajana yönelik meta verileri (ad, açıklama) +LLM için argüman tanımları + +```json +{ + "type": "tool-service", + "name": "query-customers", + "description": "Query the customer knowledge base", + "service": "custom-rag", + "collection": "customers", + "arguments": [ + { + "name": "question", + "type": "string", + "description": "The question to ask about customers" + } + ] +} +``` + +Birden fazla aracın, farklı yapılandırmalarla aynı hizmete başvurabileceğini unutmayın: + +```json +{ + "type": "tool-service", + "name": "query-products", + "description": "Query the product knowledge base", + "service": "custom-rag", + "collection": "products", + "arguments": [ + { + "name": "question", + "type": "string", + "description": "The question to ask about products" + } + ] +} +``` + +### İstek Formatı + +Bir araç çağrıldığında, araca yapılan istek, aşağıdaki bilgileri içerir: +`user`: Aracının isteğinden (çoklu kiracılık) +`config`: Araç açıklamasından alınan, JSON formatında kodlanmış yapılandırma değerleri +`arguments`: LLM'den alınan, JSON formatında kodlanmış argümanlar + +```json +{ + "user": "alice", + "config": "{\"collection\": \"customers\"}", + "arguments": "{\"question\": \"What are the top customer complaints?\"}" +} +``` + +Araç hizmeti, bunları `invoke` yönteminde ayrıştırılmış sözlükler olarak alır. + +### Genel Araç Hizmeti Uygulaması + +Bir `ToolServiceImpl` sınıfı, yapılandırmaya göre araç hizmetlerini çağırır: + +```python +class ToolServiceImpl: + def __init__(self, context, request_queue, response_queue, config_values, arguments, processor): + self.request_queue = request_queue + self.response_queue = response_queue + self.config_values = config_values # e.g., {"collection": "customers"} + # ... + + async def invoke(self, **arguments): + client = await self._get_or_create_client() + response = await client.call(user, self.config_values, arguments) + if isinstance(response, str): + return response + else: + return json.dumps(response) +``` + +## Tasarım Kararları + +### İki Katmanlı Konfigürasyon Modeli + +Araç hizmetleri, MCP araçlarına benzer bir iki katmanlı model izler: + +1. **Araç Hizmeti**: Pulsar hizmet arayüzünü (konu, gerekli yapılandırma parametreleri) tanımlar. +2. **Araç**: Bir araç hizmetine başvurur, yapılandırma değerlerini sağlar, LLM argümanlarını tanımlar. + +Bu ayrım şunları sağlar: +Farklı yapılandırmalara sahip birden fazla aracın aynı araç hizmetini kullanabilmesi +Hizmet arayüzü ve araç yapılandırması arasındaki net ayrım +Hizmet tanımlarının yeniden kullanılabilirliği + +### İstek Eşleme: Zarf ile Doğrudan İletim + +Bir araç hizmetine yapılan istek, şunları içeren yapılandırılmış bir zarf içerir: +`user`: Çoklu kiracılık için aracıdan gelen istekten aktarılır. +Yapılandırma değerleri: Araç açıklamasından (örneğin, `collection`). +`arguments`: LLM tarafından sağlanan argümanlar, bir sözlük olarak iletilir. + +Aracı yöneticisi, LLM'nin yanıtını `act.arguments` olarak bir sözlükte (`agent_manager.py:117-154`) ayrıştırır. Bu sözlük, istek zarfında bulunur. + +### Şema İşleme: Türsüz + +İstekler ve yanıtlar, tür tanımlaması olmayan sözlükler kullanır. Aracılar seviyesinde herhangi bir şema doğrulaması yapılmaz; araç hizmeti, girişlerini doğrulamaktan sorumludur. Bu, yeni hizmetler tanımlamak için maksimum esneklik sağlar. + +### İstemci Arayüzü: Doğrudan Pulsar Konuları + +Araç hizmetleri, akış yapılandırması gerektirmeden doğrudan Pulsar konularını kullanır. Araç hizmeti tanımında, tam kuyruk adları belirtilir: + +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [...] +} +``` + +Bu, hizmetlerin herhangi bir ad alanında barındırılmasını sağlar. + +### Hata Yönetimi: Standart Hata Kuralı + +Ara hizmet yanıtları, `error` alanı ile mevcut şema kuralını takip eder: + +```python +@dataclass +class Error: + type: str = "" + message: str = "" +``` + +Yanıt yapısı: +Başarı: `error`, `None` ise, yanıt sonuç içerir. +Hata: `error`, `type` ve `message` ile doldurulur. + +Bu, mevcut hizmet şemalarında kullanılan kalıpla eşleşir (örneğin, `PromptResponse`, `QueryResponse`, `AgentResponse`). + +### İstek/Yanıt İlişkilendirmesi + +İstekler ve yanıtlar, Pulsar mesaj özelliklerindeki bir `id` kullanılarak ilişkilendirilir: + +İstek, özelliklerde `id` içerir: `properties={"id": id}` +Yanıt(lar), aynı `id`'ı içerir: `properties={"id": id}` + +Bu, kod tabanında kullanılan mevcut kalıpla uyumludur (örneğin, `agent_service.py`, `llm_service.py`). + +### Akış Desteği + +Araç hizmetleri, akış yanıtları döndürebilir: + +Aynı `id`'a sahip çoklu yanıt mesajı +Her yanıt, `end_of_stream: bool` alanını içerir +Son yanıt, `end_of_stream: True`'a sahiptir + +Bu, `AgentResponse` ve diğer akış hizmetlerinde kullanılan kalıpla eşleşir. + +### Yanıt İşleme: String Dönüşü + +Tüm mevcut araçlar aynı kalıbı izler: **argümanları bir sözlük olarak alın, gözlemi bir dize olarak döndürün**. + +| Araç | Yanıt İşleme | +|------|------------------| +| `KnowledgeQueryImpl` | `client.rag()`'i doğrudan döndürür (dize) | +| `TextCompletionImpl` | `client.question()`'i doğrudan döndürür (dize) | +| `McpToolImpl` | Bir dize döndürür veya dize değilse `json.dumps(output)` döndürür | +| `StructuredQueryImpl` | Sonucu bir dizeye dönüştürür | +| `PromptImpl` | `client.prompt()`'i doğrudan döndürür (dize) | + +Araç hizmetleri aynı sözleşmeyi izler: +Hizmet, bir dize yanıtı (gözlem) döndürür +Yanıt bir dize değilse, `json.dumps()` aracılığıyla dönüştürülür +Tanımlayıcıda herhangi bir çıkarma yapılandırması gerekmez + +Bu, tanımlayıcıyı basit tutar ve aracın uygun bir metin yanıtı döndürme sorumluluğunu hizmete bırakır. + +## Yapılandırma Kılavuzu + +Yeni bir araç hizmeti eklemek için, iki yapılandırma öğesi gereklidir: + +### 1. Araç Hizmeti Yapılandırması + +`tool-service` yapılandırma anahtarı altında saklanır. Pulsar kuyruklarını ve mevcut yapılandırma parametrelerini tanımlar. + +| Alan | Gerekli | Açıklama | +|-------|----------|-------------| +| `id` | Evet | Araç hizmeti için benzersiz tanımlayıcı | +| `request-queue` | Evet | İstekler için tam Pulsar konusu (örneğin, `non-persistent://tg/request/joke`) | +| `response-queue` | Evet | Yanıtlar için tam Pulsar konusu (örneğin, `non-persistent://tg/response/joke`) | +| `config-params` | Hayır | Hizmetin kabul ettiği yapılandırma parametrelerinin dizisi | + +Her yapılandırma parametresi şunları belirtebilir: +`name`: Parametre adı (gerekli) +`required`: Parametrenin araçlar tarafından sağlanması gerekip gerekmediği (varsayılan: false) + +Örnek: +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [ + {"name": "style", "required": false} + ] +} +``` + +### 2. Araç Yapılandırması + +`tool` anahtarının altında saklanır. Aracının kullanabileceği bir aracı tanımlar. + +| Alan | Gerekli | Açıklama | +|-------|----------|-------------| +| `type` | Evet | `"tool-service"` olmalıdır | +| `name` | Evet | LLM'ye sunulan araç adı | +| `description` | Evet | Aracın ne yaptığına dair açıklama (LLM'ye gösterilir) | +| `service` | Evet | Çağrılacak araç hizmetinin kimliği | +| `arguments` | Hayır | LLM için argüman tanımları dizisi | +| *(yapılandırma parametreleri)* | Değişken | Hizmet tarafından tanımlanan herhangi bir yapılandırma parametresi | + +Her argüman aşağıdaki gibi bir şeye sahip olabilir: +`name`: Argüman adı (gerekli) +`type`: Veri türü, örneğin `"string"` (gerekli) +`description`: LLM'ye gösterilen açıklama (gerekli) + +Örnek: +```json +{ + "type": "tool-service", + "name": "tell-joke", + "description": "Tell a joke on a given topic", + "service": "joke-service", + "style": "pun", + "arguments": [ + { + "name": "topic", + "type": "string", + "description": "The topic for the joke (e.g., programming, animals, food)" + } + ] +} +``` + +### Yapılandırmayı Yükleme + +Yapılandırmaları yüklemek için `tg-put-config-item`'ı kullanın: + +```bash +# Load tool-service config +tg-put-config-item tool-service/joke-service < joke-service.json + +# Load tool config +tg-put-config-item tool/tell-joke < tell-joke.json +``` + +Aracının ve yöneticinin, yeni yapılandırmaları alabilmesi için yeniden başlatılması gerekir. + +## Uygulama Detayları + +### Şema + +`trustgraph-base/trustgraph/schema/services/tool_service.py` içindeki istek ve yanıt türleri: + +```python +@dataclass +class ToolServiceRequest: + user: str = "" # User context for multi-tenancy + config: str = "" # JSON-encoded config values from tool descriptor + arguments: str = "" # JSON-encoded arguments from LLM + +@dataclass +class ToolServiceResponse: + error: Error | None = None + response: str = "" # String response (the observation) + end_of_stream: bool = False +``` + +### Sunucu Tarafı: DynamicToolService + +`trustgraph-base/trustgraph/base/dynamic_tool_service.py` içindeki temel sınıf: + +```python +class DynamicToolService(AsyncProcessor): + """Base class for implementing tool services.""" + + def __init__(self, **params): + topic = params.get("topic", default_topic) + # Constructs topics: non-persistent://tg/request/{topic}, non-persistent://tg/response/{topic} + # Sets up Consumer and Producer + + async def invoke(self, user, config, arguments): + """Override this method to implement the tool's logic.""" + raise NotImplementedError() +``` + +### İstemci Tarafı: ToolServiceImpl + +`trustgraph-flow/trustgraph/agent/react/tools.py` içindeki uygulama: + +```python +class ToolServiceImpl: + def __init__(self, context, request_queue, response_queue, config_values, arguments, processor): + # Uses the provided queue paths directly + # Creates ToolServiceClient on first use + + async def invoke(self, **arguments): + client = await self._get_or_create_client() + response = await client.call(user, config_values, arguments) + return response if isinstance(response, str) else json.dumps(response) +``` + +### Dosyalar + +| Dosya | Amaç | +|------|---------| +| `trustgraph-base/trustgraph/schema/services/tool_service.py` | İstek/yanıt şemaları | +| `trustgraph-base/trustgraph/base/tool_service_client.py` | Hizmetleri çağırmak için istemci | +| `trustgraph-base/trustgraph/base/dynamic_tool_service.py` | Hizmet uygulamasının temel sınıfı | +| `trustgraph-flow/trustgraph/agent/react/tools.py` | `ToolServiceImpl` sınıfı | +| `trustgraph-flow/trustgraph/agent/react/service.py` | Yapılandırma yükleme | + +### Örnek: Şaka Hizmeti + +`trustgraph-flow/trustgraph/tool_service/joke/`'da bir örnek hizmet: + +```python +class Processor(DynamicToolService): + async def invoke(self, user, config, arguments): + style = config.get("style", "pun") + topic = arguments.get("topic", "") + joke = pick_joke(topic, style) + return f"Hey {user}! Here's a {style} for you:\n\n{joke}" +``` + +Araç hizmeti yapılandırması: +```json +{ + "id": "joke-service", + "request-queue": "non-persistent://tg/request/joke", + "response-queue": "non-persistent://tg/response/joke", + "config-params": [{"name": "style", "required": false}] +} +``` + +Araç yapılandırması: +```json +{ + "type": "tool-service", + "name": "tell-joke", + "description": "Tell a joke on a given topic", + "service": "joke-service", + "style": "pun", + "arguments": [ + {"name": "topic", "type": "string", "description": "The topic for the joke"} + ] +} +``` + +### Geriye Dönük Uyumluluk + +Mevcut, yerleşik araç türleri, herhangi bir değişiklik olmadan çalışmaya devam etmektedir. +`tool-service`, mevcut türlerin (`knowledge-query`, `mcp-tool`, vb.) yanı sıra yeni bir araç türüdür. + +## Gelecek Planları + +### Kendini Tanımlayan Hizmetler + +Gelecekteki bir geliştirmede, hizmetlerin kendi tanımlarını yayınlamasına izin verilebilir: + +Hizmetler, başlatıldığında, bilinen bir `tool-descriptors` konusuna yayın yapar. +Aracılar abone olur ve araçları dinamik olarak kaydeder. +Yapılandırma değişiklikleri olmadan gerçek bir tak ve çalıştır imkanı sağlar. + +Bu, ilk uygulamada kapsam dışındadır. + +## Referanslar + +Mevcut araç uygulaması: `trustgraph-flow/trustgraph/agent/react/tools.py` +Araç kaydı: `trustgraph-flow/trustgraph/agent/react/service.py:105-214` +Aracı şemaları: `trustgraph-base/trustgraph/schema/services/agent.py`