agentic-graphrag 0.0.2__tar.gz → 0.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/PKG-INFO +41 -16
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/README.md +18 -11
- agentic_graphrag-0.0.4/agrag/agents/__init__.py +19 -0
- agentic_graphrag-0.0.4/agrag/agents/build.py +276 -0
- agentic_graphrag-0.0.4/agrag/agents/errors.py +16 -0
- agentic_graphrag-0.0.4/agrag/agents/harness.py +54 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/agents/ledger.py +25 -4
- agentic_graphrag-0.0.4/agrag/agents/middleware.py +289 -0
- agentic_graphrag-0.0.4/agrag/agents/prompts.py +91 -0
- agentic_graphrag-0.0.4/agrag/agents/result.py +21 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/agents/settings.py +14 -2
- agentic_graphrag-0.0.4/agrag/agents/subagents.py +79 -0
- agentic_graphrag-0.0.4/agrag/agents/tools/__init__.py +91 -0
- agentic_graphrag-0.0.4/agrag/agents/tools/aggregate.py +66 -0
- agentic_graphrag-0.0.4/agrag/agents/tools/search.py +465 -0
- agentic_graphrag-0.0.4/agrag/agents/tools/traversal.py +333 -0
- agentic_graphrag-0.0.4/agrag/agents/tracing.py +134 -0
- agentic_graphrag-0.0.4/agrag/agents/verification.py +92 -0
- agentic_graphrag-0.0.4/agrag/chunking/__init__.py +38 -0
- agentic_graphrag-0.0.4/agrag/chunking/_docling_adapters.py +69 -0
- agentic_graphrag-0.0.4/agrag/chunking/_text.py +159 -0
- agentic_graphrag-0.0.4/agrag/chunking/base.py +239 -0
- agentic_graphrag-0.0.4/agrag/chunking/docling.py +200 -0
- agentic_graphrag-0.0.4/agrag/chunking/extras.py +182 -0
- agentic_graphrag-0.0.4/agrag/chunking/heading.py +137 -0
- agentic_graphrag-0.0.4/agrag/chunking/parent_child.py +105 -0
- agentic_graphrag-0.0.4/agrag/chunking/recursive.py +72 -0
- agentic_graphrag-0.0.4/agrag/chunking/rules.py +119 -0
- agentic_graphrag-0.0.4/agrag/chunking/sentence.py +51 -0
- agentic_graphrag-0.0.4/agrag/chunking/token.py +49 -0
- agentic_graphrag-0.0.4/agrag/chunking/turns.py +115 -0
- agentic_graphrag-0.0.4/agrag/common/__init__.py +1 -0
- agentic_graphrag-0.0.4/agrag/common/data_models/__init__.py +43 -0
- agentic_graphrag-0.0.4/agrag/common/data_models/chunk.py +189 -0
- agentic_graphrag-0.0.4/agrag/common/data_models/community.py +65 -0
- agentic_graphrag-0.0.4/agrag/common/data_models/cutover_job.py +63 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/common/data_models/data_point.py +2 -3
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/common/data_models/document.py +139 -31
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/common/data_models/entity.py +9 -4
- agentic_graphrag-0.0.4/agrag/common/data_models/graph_record.py +148 -0
- agentic_graphrag-0.0.4/agrag/common/data_models/graph_schema.py +183 -0
- agentic_graphrag-0.0.4/agrag/common/data_models/normalization.py +25 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/common/data_models/provenance.py +5 -3
- agentic_graphrag-0.0.4/agrag/common/data_models/query_value.py +13 -0
- agentic_graphrag-0.0.4/agrag/common/data_models/resolved_entity.py +50 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/common/data_models/search_result.py +10 -3
- agentic_graphrag-0.0.4/agrag/common/data_models/stage_failure.py +77 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/common/data_models/vector_record.py +15 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/common/validation.py +6 -0
- agentic_graphrag-0.0.4/agrag/cypher/_pending_filter.py +28 -0
- agentic_graphrag-0.0.4/agrag/cypher/community_read.py +41 -0
- agentic_graphrag-0.0.4/agrag/cypher/community_write.py +19 -0
- agentic_graphrag-0.0.4/agrag/cypher/cutover_job_read.py +32 -0
- agentic_graphrag-0.0.4/agrag/cypher/cutover_job_write.py +319 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/cypher/entities.py +132 -49
- agentic_graphrag-0.0.4/agrag/cypher/relations.py +443 -0
- agentic_graphrag-0.0.4/agrag/cypher/resolution_read.py +141 -0
- agentic_graphrag-0.0.4/agrag/cypher/resolution_write.py +171 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/cypher/schema.py +104 -4
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/embedding/__init__.py +18 -2
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/embedding/fastembed_bm25.py +26 -4
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/embedding/sentence_transformers.py +26 -7
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/embedding/settings.py +4 -1
- agentic_graphrag-0.0.4/agrag/eval/__init__.py +109 -0
- agentic_graphrag-0.0.4/agrag/eval/adapter.py +112 -0
- agentic_graphrag-0.0.4/agrag/eval/answer.py +516 -0
- agentic_graphrag-0.0.4/agrag/eval/extraction.py +421 -0
- agentic_graphrag-0.0.4/agrag/eval/judge.py +108 -0
- agentic_graphrag-0.0.4/agrag/eval/resolution.py +201 -0
- agentic_graphrag-0.0.4/agrag/eval/settings.py +117 -0
- agentic_graphrag-0.0.4/agrag/eval/trajectory.py +708 -0
- agentic_graphrag-0.0.4/agrag/eval/verifier.py +176 -0
- agentic_graphrag-0.0.4/agrag/graphdb/__init__.py +61 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/graphdb/base.py +29 -5
- agentic_graphrag-0.0.4/agrag/graphdb/neo4j.py +1071 -0
- agentic_graphrag-0.0.4/agrag/graphdb/serialize.py +227 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/graphdb/settings.py +1 -1
- agentic_graphrag-0.0.4/agrag/ingestion/__init__.py +34 -0
- agentic_graphrag-0.0.4/agrag/ingestion/_clustering.py +36 -0
- agentic_graphrag-0.0.4/agrag/ingestion/_cutover.py +482 -0
- agentic_graphrag-0.0.4/agrag/ingestion/_document_lifecycle.py +115 -0
- agentic_graphrag-0.0.4/agrag/ingestion/_ingest_pipeline.py +1690 -0
- agentic_graphrag-0.0.4/agrag/ingestion/_lexical_backbone.py +114 -0
- agentic_graphrag-0.0.4/agrag/ingestion/_resume.py +327 -0
- agentic_graphrag-0.0.4/agrag/ingestion/community.py +669 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/ingestion/extract.py +100 -42
- agentic_graphrag-0.0.4/agrag/ingestion/graph.py +2079 -0
- agentic_graphrag-0.0.4/agrag/ingestion/materialize.py +587 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/ingestion/merge.py +193 -158
- agentic_graphrag-0.0.4/agrag/ingestion/reports/__init__.py +20 -0
- agentic_graphrag-0.0.4/agrag/ingestion/reports/add_result.py +67 -0
- agentic_graphrag-0.0.4/agrag/ingestion/reports/community_detection_report.py +25 -0
- agentic_graphrag-0.0.4/agrag/ingestion/reports/consolidation_report.py +26 -0
- agentic_graphrag-0.0.4/agrag/ingestion/reports/reevaluation_report.py +28 -0
- agentic_graphrag-0.0.4/agrag/ingestion/reports/update_result.py +25 -0
- agentic_graphrag-0.0.4/agrag/ingestion/resolve/__init__.py +48 -0
- agentic_graphrag-0.0.4/agrag/ingestion/resolve/batch_validation.py +50 -0
- agentic_graphrag-0.0.4/agrag/ingestion/resolve/candidate_source.py +329 -0
- agentic_graphrag-0.0.4/agrag/ingestion/resolve/comparators.py +23 -0
- agentic_graphrag-0.0.4/agrag/ingestion/resolve/exact_groups.py +33 -0
- agentic_graphrag-0.0.4/agrag/ingestion/resolve/resolver.py +917 -0
- agentic_graphrag-0.0.4/agrag/ingestion/resolve/zone_classifier.py +99 -0
- agentic_graphrag-0.0.4/agrag/ingestion/resolved_embeddings.py +418 -0
- agentic_graphrag-0.0.4/agrag/ingestion/settings.py +24 -0
- agentic_graphrag-0.0.4/agrag/ingestion/stats/__init__.py +26 -0
- agentic_graphrag-0.0.4/agrag/ingestion/stats/chunking.py +77 -0
- agentic_graphrag-0.0.4/agrag/ingestion/stats/extraction.py +27 -0
- agentic_graphrag-0.0.4/agrag/ingestion/stats/ingest.py +17 -0
- agentic_graphrag-0.0.4/agrag/ingestion/stats/merge.py +33 -0
- agentic_graphrag-0.0.4/agrag/ingestion/stats/resolution.py +22 -0
- agentic_graphrag-0.0.4/agrag/ingestion/stats/storage.py +32 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_client/async_client.py +119 -37
- agentic_graphrag-0.0.4/agrag/llm/baml_client/inlinedbaml.py +24 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_client/parser.py +32 -8
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_client/stream_types.py +32 -2
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_client/sync_client.py +117 -37
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_client/type_builder.py +231 -3
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_client/type_map.py +12 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_client/types.py +32 -2
- agentic_graphrag-0.0.4/agrag/llm/baml_src/community.baml +48 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_src/extraction.baml +12 -2
- agentic_graphrag-0.0.4/agrag/llm/baml_src/merge.baml +21 -0
- agentic_graphrag-0.0.4/agrag/llm/baml_src/resolution.baml +37 -0
- agentic_graphrag-0.0.4/agrag/llm/baml_src/retrieval.baml +31 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/client_config.py +3 -1
- agentic_graphrag-0.0.4/agrag/llm/retry.py +126 -0
- agentic_graphrag-0.0.4/agrag/llm/tracing.py +158 -0
- agentic_graphrag-0.0.4/agrag/loaders/__init__.py +52 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/loaders/corpus/__init__.py +3 -1
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/loaders/corpus/_walk.py +106 -17
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/loaders/corpus/decode.py +16 -11
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/loaders/corpus/readers/_common.py +6 -0
- agentic_graphrag-0.0.4/agrag/loaders/corpus/readers/chat.py +168 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/loaders/corpus/types.py +13 -6
- agentic_graphrag-0.0.4/agrag/observability.py +100 -0
- agentic_graphrag-0.0.4/agrag/retrieval/__init__.py +52 -0
- agentic_graphrag-0.0.4/agrag/retrieval/community_context.py +207 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/retrieval/errors.py +12 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/retrieval/filters.py +2 -2
- agentic_graphrag-0.0.4/agrag/retrieval/fusion.py +92 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/retrieval/identity.py +34 -17
- agentic_graphrag-0.0.4/agrag/retrieval/methods/traversal.py +348 -0
- agentic_graphrag-0.0.4/agrag/retrieval/methods/vector.py +131 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/retrieval/recipes.py +19 -2
- agentic_graphrag-0.0.4/agrag/retrieval/rerank/cross_encoder.py +138 -0
- agentic_graphrag-0.0.4/agrag/retrieval/rerank/node_distance.py +105 -0
- agentic_graphrag-0.0.4/agrag/retrieval/resolved_entities.py +97 -0
- agentic_graphrag-0.0.4/agrag/retrieval/retrievers/bfs.py +156 -0
- agentic_graphrag-0.0.4/agrag/retrieval/retrievers/chunk.py +252 -0
- agentic_graphrag-0.0.4/agrag/retrieval/retrievers/community.py +131 -0
- agentic_graphrag-0.0.4/agrag/retrieval/retrievers/entity.py +400 -0
- agentic_graphrag-0.0.4/agrag/retrieval/retrievers/text2cypher.py +737 -0
- agentic_graphrag-0.0.4/agrag/retrieval/search_engine.py +561 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/retrieval/settings.py +25 -4
- agentic_graphrag-0.0.4/agrag/retrieval/tracing.py +182 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/vectordb/__init__.py +25 -9
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/vectordb/milvus.py +264 -90
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/vectordb/qdrant.py +224 -102
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/vectordb/settings.py +6 -3
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/vectordb/weaviate.py +234 -93
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/pyproject.toml +25 -8
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/pyproject.toml.orig +27 -8
- agentic_graphrag-0.0.2/agrag/agents/__init__.py +0 -1
- agentic_graphrag-0.0.2/agrag/agents/build.py +0 -169
- agentic_graphrag-0.0.2/agrag/agents/middleware.py +0 -55
- agentic_graphrag-0.0.2/agrag/agents/prompts.py +0 -28
- agentic_graphrag-0.0.2/agrag/agents/subagents.py +0 -36
- agentic_graphrag-0.0.2/agrag/agents/tools.py +0 -94
- agentic_graphrag-0.0.2/agrag/chunking/__init__.py +0 -24
- agentic_graphrag-0.0.2/agrag/chunking/text.py +0 -120
- agentic_graphrag-0.0.2/agrag/common/data_models/chunk.py +0 -114
- agentic_graphrag-0.0.2/agrag/common/data_models/graph_record.py +0 -48
- agentic_graphrag-0.0.2/agrag/common/data_models/graph_schema.py +0 -94
- agentic_graphrag-0.0.2/agrag/cypher/merge.py +0 -167
- agentic_graphrag-0.0.2/agrag/cypher/relations.py +0 -170
- agentic_graphrag-0.0.2/agrag/graphdb/__init__.py +0 -45
- agentic_graphrag-0.0.2/agrag/graphdb/neo4j.py +0 -618
- agentic_graphrag-0.0.2/agrag/graphdb/serialize.py +0 -58
- agentic_graphrag-0.0.2/agrag/ingestion/__init__.py +0 -6
- agentic_graphrag-0.0.2/agrag/ingestion/graph.py +0 -1722
- agentic_graphrag-0.0.2/agrag/ingestion/resolve.py +0 -323
- agentic_graphrag-0.0.2/agrag/ingestion/types.py +0 -187
- agentic_graphrag-0.0.2/agrag/llm/baml_client/inlinedbaml.py +0 -22
- agentic_graphrag-0.0.2/agrag/llm/baml_src/resolution.baml +0 -37
- agentic_graphrag-0.0.2/agrag/llm/baml_src/retrieval.baml +0 -14
- agentic_graphrag-0.0.2/agrag/llm/retry.py +0 -73
- agentic_graphrag-0.0.2/agrag/loaders/docling/chunking.py +0 -124
- agentic_graphrag-0.0.2/agrag/observability.py +0 -98
- agentic_graphrag-0.0.2/agrag/retrieval/__init__.py +0 -1
- agentic_graphrag-0.0.2/agrag/retrieval/fusion.py +0 -73
- agentic_graphrag-0.0.2/agrag/retrieval/methods/vector.py +0 -92
- agentic_graphrag-0.0.2/agrag/retrieval/rerank/cross_encoder.py +0 -74
- agentic_graphrag-0.0.2/agrag/retrieval/rerank/node_distance.py +0 -67
- agentic_graphrag-0.0.2/agrag/retrieval/retrievers/bfs.py +0 -115
- agentic_graphrag-0.0.2/agrag/retrieval/retrievers/chunk.py +0 -169
- agentic_graphrag-0.0.2/agrag/retrieval/retrievers/entity.py +0 -104
- agentic_graphrag-0.0.2/agrag/retrieval/retrievers/text2cypher.py +0 -451
- agentic_graphrag-0.0.2/agrag/retrieval/search_engine.py +0 -294
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/LICENSE +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/__init__.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/agents/model.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/common/data_models/extraction.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/common/data_models/relation.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/common/text.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/cypher/__init__.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/cypher/safety.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/embedding/base.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/embedding/errors.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/embedding/sparse_base.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/graphdb/errors.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_client/__init__.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_client/config.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_client/globals.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_client/runtime.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_client/tracing.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_client/watchers.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/baml_src/generators.baml +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/llm/client_registry.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/loaders/corpus/base.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/loaders/corpus/errors.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/loaders/corpus/readers/html.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/loaders/corpus/readers/prose.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/loaders/corpus/readers/records.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/loaders/corpus/registry.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/loaders/docling/__init__.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/loaders/docling/loader.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/py.typed +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/retrieval/methods/__init__.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/retrieval/rerank/__init__.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/retrieval/retrievers/__init__.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/retrieval/retrievers/base.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/vectordb/base.py +0 -0
- {agentic_graphrag-0.0.2 → agentic_graphrag-0.0.4}/agrag/vectordb/errors.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-graphrag
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Agentic GraphRAG: graph-based retrieval-augmented generation with agentic reasoning.
|
|
5
5
|
Keywords: graphrag,rag,knowledge-graph,agents,retrieval
|
|
6
6
|
Author: Ashwin Mathur, Varun Mathur
|
|
@@ -14,25 +14,38 @@ Requires-Dist: pydantic-settings>=2.0
|
|
|
14
14
|
Requires-Dist: python-dotenv>=1.0
|
|
15
15
|
Requires-Dist: chonkie>=1.7
|
|
16
16
|
Requires-Dist: opentelemetry-api>=1.20
|
|
17
|
+
Requires-Dist: openinference-semantic-conventions
|
|
17
18
|
Requires-Dist: charset-normalizer>=3.4
|
|
18
19
|
Requires-Dist: markdown-it-py>=3.0
|
|
19
20
|
Requires-Dist: selectolax>=0.3.21
|
|
20
21
|
Requires-Dist: rapidfuzz>=3.0
|
|
22
|
+
Requires-Dist: scipy>=1.14
|
|
21
23
|
Requires-Dist: langgraph>=1.2 ; extra == 'agents'
|
|
22
|
-
Requires-Dist: deepagents>=0.7 ; extra == 'agents'
|
|
24
|
+
Requires-Dist: deepagents>=0.7.15 ; extra == 'agents'
|
|
23
25
|
Requires-Dist: langchain-openai>=1.0 ; extra == 'agents'
|
|
26
|
+
Requires-Dist: chonkie[code]>=1.7 ; extra == 'chunk-code'
|
|
27
|
+
Requires-Dist: chonkie[neural]>=1.7 ; extra == 'chunk-neural'
|
|
28
|
+
Requires-Dist: chonkie[semantic]>=1.7 ; extra == 'chunk-semantic'
|
|
29
|
+
Requires-Dist: graspologic-native>=1.2.5 ; extra == 'community'
|
|
24
30
|
Requires-Dist: docling>=2.0 ; extra == 'docling'
|
|
25
31
|
Requires-Dist: sentence-transformers>=5 ; extra == 'embed-local'
|
|
32
|
+
Requires-Dist: deepeval>=4.2.6 ; extra == 'eval'
|
|
33
|
+
Requires-Dist: agentevals>=0.0.9 ; extra == 'eval'
|
|
34
|
+
Requires-Dist: er-evaluation>=2.3.0 ; extra == 'eval'
|
|
35
|
+
Requires-Dist: scikit-learn>=1.5 ; extra == 'eval'
|
|
36
|
+
Requires-Dist: langchain-openai>=1.0 ; extra == 'eval'
|
|
37
|
+
Requires-Dist: opentelemetry-sdk>=1.20 ; extra == 'eval'
|
|
38
|
+
Requires-Dist: openinference-instrumentation-langchain>=0.1.76,<0.2 ; extra == 'eval'
|
|
26
39
|
Requires-Dist: gliner2[local] ; extra == 'extract'
|
|
27
40
|
Requires-Dist: transformers<4.56 ; extra == 'extract'
|
|
28
41
|
Requires-Dist: protobuf ; extra == 'extract'
|
|
29
42
|
Requires-Dist: baml-py>=0.226.1,<0.227 ; extra == 'llm'
|
|
30
|
-
Requires-Dist: pymilvus>=
|
|
31
|
-
Requires-Dist: neo4j>=5.
|
|
43
|
+
Requires-Dist: pymilvus>=3.0.0,<4 ; extra == 'milvus'
|
|
44
|
+
Requires-Dist: neo4j>=5.22 ; extra == 'neo4j'
|
|
32
45
|
Requires-Dist: opentelemetry-sdk>=1.20 ; extra == 'observability'
|
|
33
46
|
Requires-Dist: opentelemetry-exporter-otlp>=1.20 ; extra == 'observability'
|
|
34
47
|
Requires-Dist: opentelemetry-instrumentation-asyncio ; extra == 'observability'
|
|
35
|
-
Requires-Dist: openinference-
|
|
48
|
+
Requires-Dist: openinference-instrumentation-langchain>=0.1.76,<0.2 ; extra == 'observability'
|
|
36
49
|
Requires-Dist: qdrant-client>=1.12 ; extra == 'qdrant'
|
|
37
50
|
Requires-Dist: fastembed>=0.4 ; extra == 'qdrant'
|
|
38
51
|
Requires-Dist: weaviate-client>=4.9 ; extra == 'weaviate'
|
|
@@ -43,8 +56,13 @@ Project-URL: Documentation, https://ontogr.github.io/agentic-graphrag/
|
|
|
43
56
|
Project-URL: Issues, https://github.com/ontogr/agentic-graphrag/issues
|
|
44
57
|
Project-URL: Source, https://github.com/ontogr/agentic-graphrag
|
|
45
58
|
Provides-Extra: agents
|
|
59
|
+
Provides-Extra: chunk-code
|
|
60
|
+
Provides-Extra: chunk-neural
|
|
61
|
+
Provides-Extra: chunk-semantic
|
|
62
|
+
Provides-Extra: community
|
|
46
63
|
Provides-Extra: docling
|
|
47
64
|
Provides-Extra: embed-local
|
|
65
|
+
Provides-Extra: eval
|
|
48
66
|
Provides-Extra: extract
|
|
49
67
|
Provides-Extra: llm
|
|
50
68
|
Provides-Extra: milvus
|
|
@@ -71,7 +89,7 @@ Description-Content-Type: text/markdown
|
|
|
71
89
|
|
|
72
90
|
</div>
|
|
73
91
|
|
|
74
|
-
Agentic GraphRAG is a modular, schema-driven system
|
|
92
|
+
Agentic GraphRAG is a modular, schema-driven system. It builds knowledge graphs from unstructured and structured data. It retrieves evidence across graph and vector indexes. It answers questions with agentic reasoning.
|
|
75
93
|
|
|
76
94
|
<p align="center">
|
|
77
95
|
<img src="img/agentic_graphrag_pipeline.png" alt="Agentic GraphRAG pipeline from data loading through graph construction, storage, retrieval, and agentic reasoning" width="1200">
|
|
@@ -123,7 +141,7 @@ Documents keep their source URI, format, loader, content hash, and record identi
|
|
|
123
141
|
|
|
124
142
|
Extraction produces mentions first, not graph nodes. Each mention keeps its source chunk, label, text span, confidence, and extractor provenance. Resolution then assigns canonical identities and merges aliases before storage.
|
|
125
143
|
|
|
126
|
-
Relations are directed subject–predicate–object triples. The active schema constrains valid source type, relation type, and target type combinations
|
|
144
|
+
Relations are directed subject–predicate–object triples. The active schema constrains valid source type, relation type, and target type combinations. The validation stage removes invalid triples before they reach the graph.
|
|
127
145
|
|
|
128
146
|
### Communities
|
|
129
147
|
|
|
@@ -153,12 +171,12 @@ Query: question -> plan -> parallel retrieval -> verify -> cited answer
|
|
|
153
171
|
|
|
154
172
|
`Graph.add()` is the single entry point for adding content. The complete pipeline is organized into these stages:
|
|
155
173
|
|
|
156
|
-
1. **Load:** Select a loader by format
|
|
174
|
+
1. **Load:** Select a loader by format. Decode or parse the source. Preserve source metadata. Apply `RAISE`, `SKIP`, or `QUARANTINE` as the error policy for each source.
|
|
157
175
|
2. **Chunk:** Use Docling's layout-aware chunking before flattening rich documents; use Chonkie for text and record documents.
|
|
158
176
|
3. **Extract:** Run GLiNER locally against the active schema. Escalate weak results to a typed BAML extraction function when configured.
|
|
159
177
|
4. **Validate:** Drop entities and triples that do not conform to the schema.
|
|
160
178
|
5. **Resolve:** Apply exact, fuzzy, embedding, and LLM-verified comparison tiers. Ambiguous or failed comparisons do not merge.
|
|
161
|
-
6. **Merge:** Resolve properties field by field
|
|
179
|
+
6. **Merge:** Resolve properties field by field. Combine provenance. Deduplicate repointed relations. Retain an audit trail.
|
|
162
180
|
7. **Store:** Upsert canonical nodes and relations, then populate graph-native or dedicated vector indexes.
|
|
163
181
|
|
|
164
182
|
The extraction cascade replaces a weak local result with the LLM result instead of combining two conflicting outputs. Exact matches use global store-backed lookup; more expensive fuzzy and LLM comparisons are blocked to a smaller candidate set.
|
|
@@ -178,7 +196,7 @@ The async `Embedder`, `GraphStore`, and `VectorStore` interfaces keep model and
|
|
|
178
196
|
|
|
179
197
|
### Graph storage
|
|
180
198
|
|
|
181
|
-
The Neo4j backend supports local Neo4j and Aura over Bolt, managed read/write transactions, node and relation upserts, constraints, indexes, and native dense vector search.
|
|
199
|
+
The Neo4j backend supports local Neo4j and Aura over Bolt, managed read/write transactions, node and relation upserts, constraints, indexes, and native dense vector search. The query builders validate dynamic labels and relation types before they interpolate them into Cypher.
|
|
182
200
|
|
|
183
201
|
### Vector storage
|
|
184
202
|
|
|
@@ -251,6 +269,9 @@ uv pip install "agentic-graphrag[llm,embed-local]"
|
|
|
251
269
|
|
|
252
270
|
# Neo4j with a dedicated Qdrant vector store and OTLP tracing
|
|
253
271
|
uv pip install "agentic-graphrag[neo4j,qdrant,observability]"
|
|
272
|
+
|
|
273
|
+
# Hierarchical community detection
|
|
274
|
+
uv pip install "agentic-graphrag[community]"
|
|
254
275
|
```
|
|
255
276
|
|
|
256
277
|
| Extra | Adds |
|
|
@@ -264,6 +285,7 @@ uv pip install "agentic-graphrag[neo4j,qdrant,observability]"
|
|
|
264
285
|
| `weaviate` | Weaviate dense and hybrid search |
|
|
265
286
|
| `milvus` | Milvus/Zilliz dense and hybrid search |
|
|
266
287
|
| `observability` | OpenTelemetry SDK and OTLP export |
|
|
288
|
+
| `community` | Hierarchical Leiden community detection |
|
|
267
289
|
|
|
268
290
|
## Usage
|
|
269
291
|
|
|
@@ -278,11 +300,14 @@ from agrag.ingestion import Graph
|
|
|
278
300
|
async def main() -> None:
|
|
279
301
|
graph = await Graph.open()
|
|
280
302
|
|
|
281
|
-
files = await graph.add(source="./corpus/**/*.md")
|
|
282
|
-
text = await graph.add(
|
|
303
|
+
files = await graph.add(source="./corpus/**/*.md", return_chunks=True)
|
|
304
|
+
text = await graph.add(
|
|
305
|
+
text="Agentic GraphRAG turns evidence into a graph.",
|
|
306
|
+
return_chunks=True,
|
|
307
|
+
)
|
|
283
308
|
|
|
284
|
-
print(files.documents, len(files.chunks))
|
|
285
|
-
print(text.documents, len(text.chunks))
|
|
309
|
+
print(files.ingestion.documents, len(files.chunks))
|
|
310
|
+
print(text.ingestion.documents, len(text.chunks))
|
|
286
311
|
|
|
287
312
|
|
|
288
313
|
asyncio.run(main())
|
|
@@ -304,8 +329,8 @@ result = await graph.add(
|
|
|
304
329
|
error_policy=ErrorPolicy.QUARANTINE,
|
|
305
330
|
)
|
|
306
331
|
|
|
307
|
-
for
|
|
308
|
-
print(
|
|
332
|
+
for item in result.ingestion.quarantined_items:
|
|
333
|
+
print(item.item_id, item.error_message)
|
|
309
334
|
```
|
|
310
335
|
|
|
311
336
|
See the [documentation](https://ontogr.github.io/agentic-graphrag/) for guides and the generated API reference.
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
</div>
|
|
17
17
|
|
|
18
|
-
Agentic GraphRAG is a modular, schema-driven system
|
|
18
|
+
Agentic GraphRAG is a modular, schema-driven system. It builds knowledge graphs from unstructured and structured data. It retrieves evidence across graph and vector indexes. It answers questions with agentic reasoning.
|
|
19
19
|
|
|
20
20
|
<p align="center">
|
|
21
21
|
<img src="img/agentic_graphrag_pipeline.png" alt="Agentic GraphRAG pipeline from data loading through graph construction, storage, retrieval, and agentic reasoning" width="1200">
|
|
@@ -67,7 +67,7 @@ Documents keep their source URI, format, loader, content hash, and record identi
|
|
|
67
67
|
|
|
68
68
|
Extraction produces mentions first, not graph nodes. Each mention keeps its source chunk, label, text span, confidence, and extractor provenance. Resolution then assigns canonical identities and merges aliases before storage.
|
|
69
69
|
|
|
70
|
-
Relations are directed subject–predicate–object triples. The active schema constrains valid source type, relation type, and target type combinations
|
|
70
|
+
Relations are directed subject–predicate–object triples. The active schema constrains valid source type, relation type, and target type combinations. The validation stage removes invalid triples before they reach the graph.
|
|
71
71
|
|
|
72
72
|
### Communities
|
|
73
73
|
|
|
@@ -97,12 +97,12 @@ Query: question -> plan -> parallel retrieval -> verify -> cited answer
|
|
|
97
97
|
|
|
98
98
|
`Graph.add()` is the single entry point for adding content. The complete pipeline is organized into these stages:
|
|
99
99
|
|
|
100
|
-
1. **Load:** Select a loader by format
|
|
100
|
+
1. **Load:** Select a loader by format. Decode or parse the source. Preserve source metadata. Apply `RAISE`, `SKIP`, or `QUARANTINE` as the error policy for each source.
|
|
101
101
|
2. **Chunk:** Use Docling's layout-aware chunking before flattening rich documents; use Chonkie for text and record documents.
|
|
102
102
|
3. **Extract:** Run GLiNER locally against the active schema. Escalate weak results to a typed BAML extraction function when configured.
|
|
103
103
|
4. **Validate:** Drop entities and triples that do not conform to the schema.
|
|
104
104
|
5. **Resolve:** Apply exact, fuzzy, embedding, and LLM-verified comparison tiers. Ambiguous or failed comparisons do not merge.
|
|
105
|
-
6. **Merge:** Resolve properties field by field
|
|
105
|
+
6. **Merge:** Resolve properties field by field. Combine provenance. Deduplicate repointed relations. Retain an audit trail.
|
|
106
106
|
7. **Store:** Upsert canonical nodes and relations, then populate graph-native or dedicated vector indexes.
|
|
107
107
|
|
|
108
108
|
The extraction cascade replaces a weak local result with the LLM result instead of combining two conflicting outputs. Exact matches use global store-backed lookup; more expensive fuzzy and LLM comparisons are blocked to a smaller candidate set.
|
|
@@ -122,7 +122,7 @@ The async `Embedder`, `GraphStore`, and `VectorStore` interfaces keep model and
|
|
|
122
122
|
|
|
123
123
|
### Graph storage
|
|
124
124
|
|
|
125
|
-
The Neo4j backend supports local Neo4j and Aura over Bolt, managed read/write transactions, node and relation upserts, constraints, indexes, and native dense vector search.
|
|
125
|
+
The Neo4j backend supports local Neo4j and Aura over Bolt, managed read/write transactions, node and relation upserts, constraints, indexes, and native dense vector search. The query builders validate dynamic labels and relation types before they interpolate them into Cypher.
|
|
126
126
|
|
|
127
127
|
### Vector storage
|
|
128
128
|
|
|
@@ -195,6 +195,9 @@ uv pip install "agentic-graphrag[llm,embed-local]"
|
|
|
195
195
|
|
|
196
196
|
# Neo4j with a dedicated Qdrant vector store and OTLP tracing
|
|
197
197
|
uv pip install "agentic-graphrag[neo4j,qdrant,observability]"
|
|
198
|
+
|
|
199
|
+
# Hierarchical community detection
|
|
200
|
+
uv pip install "agentic-graphrag[community]"
|
|
198
201
|
```
|
|
199
202
|
|
|
200
203
|
| Extra | Adds |
|
|
@@ -208,6 +211,7 @@ uv pip install "agentic-graphrag[neo4j,qdrant,observability]"
|
|
|
208
211
|
| `weaviate` | Weaviate dense and hybrid search |
|
|
209
212
|
| `milvus` | Milvus/Zilliz dense and hybrid search |
|
|
210
213
|
| `observability` | OpenTelemetry SDK and OTLP export |
|
|
214
|
+
| `community` | Hierarchical Leiden community detection |
|
|
211
215
|
|
|
212
216
|
## Usage
|
|
213
217
|
|
|
@@ -222,11 +226,14 @@ from agrag.ingestion import Graph
|
|
|
222
226
|
async def main() -> None:
|
|
223
227
|
graph = await Graph.open()
|
|
224
228
|
|
|
225
|
-
files = await graph.add(source="./corpus/**/*.md")
|
|
226
|
-
text = await graph.add(
|
|
229
|
+
files = await graph.add(source="./corpus/**/*.md", return_chunks=True)
|
|
230
|
+
text = await graph.add(
|
|
231
|
+
text="Agentic GraphRAG turns evidence into a graph.",
|
|
232
|
+
return_chunks=True,
|
|
233
|
+
)
|
|
227
234
|
|
|
228
|
-
print(files.documents, len(files.chunks))
|
|
229
|
-
print(text.documents, len(text.chunks))
|
|
235
|
+
print(files.ingestion.documents, len(files.chunks))
|
|
236
|
+
print(text.ingestion.documents, len(text.chunks))
|
|
230
237
|
|
|
231
238
|
|
|
232
239
|
asyncio.run(main())
|
|
@@ -248,8 +255,8 @@ result = await graph.add(
|
|
|
248
255
|
error_policy=ErrorPolicy.QUARANTINE,
|
|
249
256
|
)
|
|
250
257
|
|
|
251
|
-
for
|
|
252
|
-
print(
|
|
258
|
+
for item in result.ingestion.quarantined_items:
|
|
259
|
+
print(item.item_id, item.error_message)
|
|
253
260
|
```
|
|
254
261
|
|
|
255
262
|
See the [documentation](https://ontogr.github.io/agentic-graphrag/) for guides and the generated API reference.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Agentic layer: planner/researcher/verifier over SearchEngine.
|
|
2
|
+
|
|
3
|
+
``build_agent`` lives in ``agrag.agents.build`` and is not re-exported here: it needs
|
|
4
|
+
the ``agents`` extra to import, and this package must import on a base install.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from agrag.agents.errors import AgentMissingExtraError
|
|
8
|
+
from agrag.agents.ledger import Ledger
|
|
9
|
+
from agrag.agents.result import AgentRunResult
|
|
10
|
+
from agrag.agents.settings import AgentLLMSettings, AgentSettings
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"AgentLLMSettings",
|
|
15
|
+
"AgentMissingExtraError",
|
|
16
|
+
"AgentRunResult",
|
|
17
|
+
"AgentSettings",
|
|
18
|
+
"Ledger",
|
|
19
|
+
]
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"""Build the planner/researcher/verifier agent graph."""
|
|
2
|
+
|
|
3
|
+
import importlib.util
|
|
4
|
+
from contextlib import nullcontext
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from opentelemetry.trace import Tracer
|
|
8
|
+
|
|
9
|
+
from agrag.agents.harness import ensure_harness_profile, model_provider_key
|
|
10
|
+
from agrag.agents.ledger import Ledger
|
|
11
|
+
from agrag.agents.middleware import ResearchAttemptLimiter, VerifierEvidenceMiddleware
|
|
12
|
+
from agrag.agents.model import build_chat_model, build_model_middleware
|
|
13
|
+
from agrag.agents.prompts import PLANNER_SYSTEM, SIMPLE_ANSWER_SYSTEM
|
|
14
|
+
from agrag.agents.result import AgentRunResult
|
|
15
|
+
from agrag.agents.settings import AgentLLMSettings, AgentSettings
|
|
16
|
+
from agrag.agents.subagents import make_researcher_spec, make_verifier_spec
|
|
17
|
+
from agrag.agents.tools import make_tools
|
|
18
|
+
from agrag.agents.tracing import require_tracing, run_callbacks
|
|
19
|
+
from agrag.common.data_models.graph_schema import GraphSchema
|
|
20
|
+
from agrag.retrieval.filters import SearchFilters
|
|
21
|
+
from agrag.retrieval.search_engine import SearchEngine
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def build_agent(
|
|
25
|
+
*,
|
|
26
|
+
engine: SearchEngine,
|
|
27
|
+
llm_settings: AgentLLMSettings,
|
|
28
|
+
agent_settings: AgentSettings | None = None,
|
|
29
|
+
filters: SearchFilters | None = None,
|
|
30
|
+
graph_schema: GraphSchema | None = None,
|
|
31
|
+
tracer: Tracer | None = None,
|
|
32
|
+
) -> Any:
|
|
33
|
+
"""Build the planner/researcher/verifier agent graph.
|
|
34
|
+
|
|
35
|
+
Constructs a LangGraph-based agent with three roles:
|
|
36
|
+
planner (decomposes the question), researcher (has tools),
|
|
37
|
+
and verifier (judges evidence sufficiency and returns a
|
|
38
|
+
structured verdict).
|
|
39
|
+
|
|
40
|
+
Each call to ``ainvoke`` creates a fresh ``Ledger`` so
|
|
41
|
+
citation numbering, identity mappings, and retrieved evidence
|
|
42
|
+
do not leak across runs, and a fresh ``ResearchAttemptLimiter``
|
|
43
|
+
so one question's retry budget does not spend another's.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
engine: Retrieval to expose to the researcher subagent's
|
|
47
|
+
tools.
|
|
48
|
+
llm_settings: The model every subagent role calls, via
|
|
49
|
+
build_chat_model. With several clients, the remaining
|
|
50
|
+
ones compose per strategy through agent middleware.
|
|
51
|
+
agent_settings: Loop-level configuration; defaults from
|
|
52
|
+
environment. The recursion limit is enforced as the
|
|
53
|
+
LangGraph ``recursion_limit`` in the invoke config, and
|
|
54
|
+
``max_research_attempts`` bounds how many times the
|
|
55
|
+
planner may re-research after an INSUFFICIENT verdict.
|
|
56
|
+
filters: Retrieval scope applied to every tool search,
|
|
57
|
+
e.g. document or tenant constraints. None searches
|
|
58
|
+
unfiltered. A non-empty scope also removes the
|
|
59
|
+
``query_graph_directly`` tool, since a generated query
|
|
60
|
+
cannot be confined to a scope.
|
|
61
|
+
graph_schema: The schema the researcher prompt and the
|
|
62
|
+
``query_graph_directly`` tool describe. None uses the
|
|
63
|
+
engine's own resolved schema; a value that differs from
|
|
64
|
+
the engine's raises, so the prompt cannot describe a
|
|
65
|
+
graph the engine does not search.
|
|
66
|
+
tracer: Receives OpenInference spans for every ``ainvoke``,
|
|
67
|
+
including the researcher and verifier subagents' tool and
|
|
68
|
+
model calls. None emits no spans. Spans carry the question,
|
|
69
|
+
tool inputs, and evidence text.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
An agent whose ``ainvoke`` returns an ``AgentRunResult``: the
|
|
73
|
+
run's ``messages`` plus its ``ledger``, which maps each
|
|
74
|
+
citation key in the answer back to its evidence. When
|
|
75
|
+
deepagents is not installed, a single-search-plus-synthesis
|
|
76
|
+
fallback with the same result shape.
|
|
77
|
+
|
|
78
|
+
Raises:
|
|
79
|
+
AgentMissingExtraError: ``tracer`` is set but the ``observability``
|
|
80
|
+
extra is not installed.
|
|
81
|
+
ValueError: ``graph_schema`` differs from the engine's schema.
|
|
82
|
+
"""
|
|
83
|
+
if tracer is not None:
|
|
84
|
+
require_tracing()
|
|
85
|
+
settings = agent_settings or AgentSettings()
|
|
86
|
+
model = build_chat_model(llm_settings.clients[0])
|
|
87
|
+
middleware = build_model_middleware(
|
|
88
|
+
llm_settings.clients, strategy=llm_settings.strategy
|
|
89
|
+
)
|
|
90
|
+
schema = engine.graph_schema
|
|
91
|
+
if graph_schema is not None and graph_schema != schema:
|
|
92
|
+
raise ValueError(
|
|
93
|
+
"graph_schema does not match the engine's schema "
|
|
94
|
+
f"('{schema.name}'); the researcher prompt and the engine "
|
|
95
|
+
"must describe the same graph"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
if importlib.util.find_spec("deepagents") is not None:
|
|
99
|
+
return _RunScopedAgent(
|
|
100
|
+
engine=engine,
|
|
101
|
+
model=model,
|
|
102
|
+
settings=settings,
|
|
103
|
+
middleware=middleware,
|
|
104
|
+
filters=filters,
|
|
105
|
+
graph_schema=schema,
|
|
106
|
+
model_provider=model_provider_key(llm_settings.clients[0].provider),
|
|
107
|
+
tracer=tracer,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Fallback: a simple wrapper when deepagents is not installed,
|
|
111
|
+
# useful for unit testing without the full extra. If deepagents
|
|
112
|
+
# is present but broken, ainvoke raises its import error at call
|
|
113
|
+
# time instead of silently degrading here.
|
|
114
|
+
return _SimpleAgent(model=model, engine=engine, filters=filters, tracer=tracer)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class _RunScopedAgent:
|
|
118
|
+
"""Builds the deepagents graph fresh per run.
|
|
119
|
+
|
|
120
|
+
Each ``ainvoke`` call constructs the graph with a new
|
|
121
|
+
``Ledger``, a new tool set, and a new
|
|
122
|
+
``ResearchAttemptLimiter`` so citation state and the retry
|
|
123
|
+
budget do not span runs, and enforces the configured LangGraph
|
|
124
|
+
recursion limit.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
def __init__(
|
|
128
|
+
self,
|
|
129
|
+
*,
|
|
130
|
+
engine: SearchEngine,
|
|
131
|
+
model: Any,
|
|
132
|
+
settings: AgentSettings,
|
|
133
|
+
middleware: list[Any] | None = None,
|
|
134
|
+
filters: SearchFilters | None = None,
|
|
135
|
+
graph_schema: GraphSchema | None = None,
|
|
136
|
+
model_provider: str = "",
|
|
137
|
+
tracer: Tracer | None = None,
|
|
138
|
+
) -> None:
|
|
139
|
+
"""Construct the wrapper."""
|
|
140
|
+
self._engine = engine
|
|
141
|
+
self._model = model
|
|
142
|
+
self._settings = settings
|
|
143
|
+
self._middleware = middleware or []
|
|
144
|
+
self._filters = filters
|
|
145
|
+
self._graph_schema = (
|
|
146
|
+
graph_schema if graph_schema is not None else engine.graph_schema
|
|
147
|
+
)
|
|
148
|
+
self._model_provider = model_provider
|
|
149
|
+
self._tracer = tracer
|
|
150
|
+
|
|
151
|
+
async def ainvoke(self, input_data: dict) -> AgentRunResult:
|
|
152
|
+
"""Delegate to inner agent with a fresh Ledger and limiter.
|
|
153
|
+
|
|
154
|
+
Builds the planner with the researcher and verifier as
|
|
155
|
+
subagents. The planner sees the task tool for delegation and
|
|
156
|
+
carries the attempt limiter; the researcher carries the
|
|
157
|
+
caller's tools and the engine's schema summary; the verifier
|
|
158
|
+
returns a structured verdict.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
input_data: Dict with ``messages`` key.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
The graph's final state with this run's ``ledger`` added.
|
|
165
|
+
"""
|
|
166
|
+
from deepagents import create_deep_agent # noqa: PLC0415
|
|
167
|
+
|
|
168
|
+
ensure_harness_profile(self._model_provider)
|
|
169
|
+
ledger = Ledger()
|
|
170
|
+
tools = make_tools(self._engine, ledger, filters=self._filters)
|
|
171
|
+
researcher = make_researcher_spec(tools, self._middleware, self._graph_schema)
|
|
172
|
+
verifier = make_verifier_spec(self._middleware)
|
|
173
|
+
limiter = ResearchAttemptLimiter(self._settings.max_research_attempts)
|
|
174
|
+
planner_system = PLANNER_SYSTEM.replace(
|
|
175
|
+
"{max_research_attempts}", str(self._settings.max_research_attempts)
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# Annotated, not typed against deepagents' own SubAgent: importing
|
|
179
|
+
# that type here would make this module require the optional
|
|
180
|
+
# dependency at import time. The specs are SubAgent-shaped dicts.
|
|
181
|
+
subagents: list[Any] = [researcher, verifier]
|
|
182
|
+
agent = create_deep_agent(
|
|
183
|
+
model=self._model,
|
|
184
|
+
system_prompt=planner_system,
|
|
185
|
+
subagents=subagents,
|
|
186
|
+
middleware=[*self._middleware, limiter, VerifierEvidenceMiddleware(ledger)],
|
|
187
|
+
)
|
|
188
|
+
result = await agent.ainvoke(
|
|
189
|
+
input_data,
|
|
190
|
+
config={
|
|
191
|
+
"recursion_limit": self._settings.recursion_limit,
|
|
192
|
+
"callbacks": run_callbacks(self._tracer),
|
|
193
|
+
},
|
|
194
|
+
)
|
|
195
|
+
return {**result, "ledger": ledger}
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class _SimpleAgent:
|
|
199
|
+
"""Fallback agent when deepagents is not installed.
|
|
200
|
+
|
|
201
|
+
Performs a single hybrid search per invocation, then one LLM
|
|
202
|
+
call to synthesize a cited answer from the results -- still no
|
|
203
|
+
agent loop, tool calls, or multi-client composition
|
|
204
|
+
(``build_model_middleware``'s fallback/round-robin strategies
|
|
205
|
+
wrap ``create_deep_agent``'s loop, not a bare model call, and
|
|
206
|
+
this class already only receives ``clients[0]``). There is no
|
|
207
|
+
agent loop, so ``AgentSettings.recursion_limit`` does not apply.
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
def __init__(
|
|
211
|
+
self,
|
|
212
|
+
*,
|
|
213
|
+
model: Any,
|
|
214
|
+
engine: SearchEngine,
|
|
215
|
+
filters: SearchFilters | None = None,
|
|
216
|
+
tracer: Tracer | None = None,
|
|
217
|
+
) -> None:
|
|
218
|
+
"""Construct a simple agent wrapper."""
|
|
219
|
+
self._model = model
|
|
220
|
+
self._engine = engine
|
|
221
|
+
self._filters = filters
|
|
222
|
+
self._tracer = tracer
|
|
223
|
+
|
|
224
|
+
async def ainvoke(self, input_data: dict) -> AgentRunResult:
|
|
225
|
+
"""Run the agent with a fresh ledger (simplified path).
|
|
226
|
+
|
|
227
|
+
Creates a new ``Ledger`` and tool set per invocation so
|
|
228
|
+
citation state does not span runs. Runs one search, then one
|
|
229
|
+
LLM call to synthesize a cited answer from the results.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
input_data: Dict with ``messages`` key.
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
Dict with ``messages`` containing the answer and this run's
|
|
236
|
+
``ledger``.
|
|
237
|
+
"""
|
|
238
|
+
span_context = (
|
|
239
|
+
self._tracer.start_as_current_span("agrag.agents.run")
|
|
240
|
+
if self._tracer is not None
|
|
241
|
+
else nullcontext()
|
|
242
|
+
)
|
|
243
|
+
with span_context:
|
|
244
|
+
ledger = Ledger()
|
|
245
|
+
messages = input_data.get("messages", [])
|
|
246
|
+
if not messages:
|
|
247
|
+
return {"messages": [], "ledger": ledger}
|
|
248
|
+
|
|
249
|
+
question = messages[-1].get("content", "")
|
|
250
|
+
from agrag.retrieval.recipes import HYBRID # noqa: PLC0415
|
|
251
|
+
|
|
252
|
+
results = await self._engine.search(question, HYBRID, filters=self._filters)
|
|
253
|
+
evidence = [ledger.render(r) for r in results]
|
|
254
|
+
if not evidence:
|
|
255
|
+
return {
|
|
256
|
+
"messages": [
|
|
257
|
+
{"role": "assistant", "content": "No relevant evidence found."}
|
|
258
|
+
],
|
|
259
|
+
"ledger": ledger,
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
response = await self._model.ainvoke(
|
|
263
|
+
[
|
|
264
|
+
{"role": "system", "content": SIMPLE_ANSWER_SYSTEM},
|
|
265
|
+
{
|
|
266
|
+
"role": "user",
|
|
267
|
+
"content": f"Question: {question}\n\nEvidence:\n"
|
|
268
|
+
+ "\n".join(evidence),
|
|
269
|
+
},
|
|
270
|
+
],
|
|
271
|
+
config={"callbacks": run_callbacks(self._tracer)},
|
|
272
|
+
)
|
|
273
|
+
return {
|
|
274
|
+
"messages": [{"role": "assistant", "content": response.text}],
|
|
275
|
+
"ledger": ledger,
|
|
276
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Errors raised by the agent layer."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class AgentMissingExtraError(Exception):
|
|
5
|
+
"""Agent tracing needs a package extra that is not installed.
|
|
6
|
+
|
|
7
|
+
Attributes:
|
|
8
|
+
extra: The name of the package extra to install.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, extra: str) -> None:
|
|
12
|
+
"""Bind the missing package extra to the error."""
|
|
13
|
+
super().__init__(
|
|
14
|
+
f"needs the {extra!r} extra: pip install 'agentic-graphrag[{extra}]'"
|
|
15
|
+
)
|
|
16
|
+
self.extra = extra
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Process-global DeepAgents harness profile registration.
|
|
2
|
+
|
|
3
|
+
Registers, once per process and per provider, the profile that trims
|
|
4
|
+
DeepAgents' generic tool surface for this project's agent: the execute
|
|
5
|
+
tool is excluded and the general-purpose subagent is disabled. The
|
|
6
|
+
registration is a process-global side effect, so it is guarded against
|
|
7
|
+
re-registration.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
_HARNESS_PROFILE_REGISTERED: set[str] = set()
|
|
11
|
+
_AGENT_PROVIDER_TO_HARNESS_KEY = {
|
|
12
|
+
"anthropic": "anthropic",
|
|
13
|
+
"openai": "openai",
|
|
14
|
+
"openai-generic": "openai",
|
|
15
|
+
"google-ai": "google_genai",
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def model_provider_key(provider: str) -> str:
|
|
20
|
+
"""Return the DeepAgents provider key for a configured agent provider.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
provider: The configured agent provider.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
The provider key used by DeepAgents harness profiles.
|
|
27
|
+
"""
|
|
28
|
+
return _AGENT_PROVIDER_TO_HARNESS_KEY[provider]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def ensure_harness_profile(provider: str) -> None:
|
|
32
|
+
"""Register the harness profile for provider, once per process.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
provider: The provider key DeepAgents resolves profiles by,
|
|
36
|
+
either a provider string such as ``"anthropic"`` or an
|
|
37
|
+
exact ``"provider:model"`` string.
|
|
38
|
+
"""
|
|
39
|
+
if provider in _HARNESS_PROFILE_REGISTERED:
|
|
40
|
+
return
|
|
41
|
+
from deepagents import ( # noqa: PLC0415
|
|
42
|
+
GeneralPurposeSubagentProfile,
|
|
43
|
+
HarnessProfile,
|
|
44
|
+
register_harness_profile,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
register_harness_profile(
|
|
48
|
+
provider,
|
|
49
|
+
HarnessProfile(
|
|
50
|
+
excluded_tools=frozenset({"execute"}),
|
|
51
|
+
general_purpose_subagent=GeneralPurposeSubagentProfile(enabled=False),
|
|
52
|
+
),
|
|
53
|
+
)
|
|
54
|
+
_HARNESS_PROFILE_REGISTERED.add(provider)
|