diff --git a/docs/tech-specs/agent-explainability.md b/docs/tech-specs/agent-explainability.md index cb3a1816..f02a95b1 100644 --- a/docs/tech-specs/agent-explainability.md +++ b/docs/tech-specs/agent-explainability.md @@ -15,29 +15,41 @@ Add provenance recording to the React agent loop so agent sessions can be traced Both GraphRAG and Agent use PROV-O as the base ontology with TrustGraph-specific subtypes: ### GraphRAG Types -| Entity | PROV-O Type | TG Type | Description | -|--------|-------------|---------|-------------| -| Question | `prov:Activity` | `tg:Question` | The user's query | +| Entity | PROV-O Type | TG Types | Description | +|--------|-------------|----------|-------------| +| Question | `prov:Activity` | `tg:Question`, `tg:GraphRagQuestion` | The user's query | | Exploration | `prov:Entity` | `tg:Exploration` | Edges retrieved from knowledge graph | | Focus | `prov:Entity` | `tg:Focus` | Selected edges with reasoning | | Synthesis | `prov:Entity` | `tg:Synthesis` | Final answer | ### Agent Types -| Entity | PROV-O Type | TG Type | Description | -|--------|-------------|---------|-------------| -| Question | `prov:Activity` | `tg:Question` | The user's query (same as GraphRAG) | +| Entity | PROV-O Type | TG Types | Description | +|--------|-------------|----------|-------------| +| Question | `prov:Activity` | `tg:Question`, `tg:AgentQuestion` | The user's query | | Analysis | `prov:Entity` | `tg:Analysis` | Each think/act/observe cycle | | Conclusion | `prov:Entity` | `tg:Conclusion` | Final answer | ### Document RAG Types -| Entity | PROV-O Type | TG Type | Description | -|--------|-------------|---------|-------------| -| Question | `prov:Activity` | `tg:Question` | The user's query (same as GraphRAG) | +| Entity | PROV-O Type | TG Types | Description | +|--------|-------------|----------|-------------| +| Question | `prov:Activity` | `tg:Question`, `tg:DocRagQuestion` | The user's query | | Exploration | `prov:Entity` | `tg:Exploration` | Chunks retrieved from document store | | Synthesis | `prov:Entity` | `tg:Synthesis` | Final answer | **Note:** Document RAG uses a subset of GraphRAG's types (no Focus step since there's no edge selection/reasoning phase). +### Question Subtypes + +All Question entities share `tg:Question` as a base type but have a specific subtype to identify the retrieval mechanism: + +| Subtype | URI Pattern | Mechanism | +|---------|-------------|-----------| +| `tg:GraphRagQuestion` | `urn:trustgraph:question:{uuid}` | Knowledge graph RAG | +| `tg:DocRagQuestion` | `urn:trustgraph:docrag:{uuid}` | Document/chunk RAG | +| `tg:AgentQuestion` | `urn:trustgraph:agent:{uuid}` | ReAct agent | + +This allows querying all questions via `tg:Question` while filtering by specific mechanism via the subtype. + ## Provenance Model ``` diff --git a/trustgraph-base/trustgraph/provenance/__init__.py b/trustgraph-base/trustgraph/provenance/__init__.py index 5a2f04b0..c1cb522a 100644 --- a/trustgraph-base/trustgraph/provenance/__init__.py +++ b/trustgraph-base/trustgraph/provenance/__init__.py @@ -78,6 +78,8 @@ from . namespaces import ( # Explainability entity types TG_QUESTION, TG_EXPLORATION, TG_FOCUS, TG_SYNTHESIS, TG_ANALYSIS, TG_CONCLUSION, + # Question subtypes (to distinguish retrieval mechanism) + TG_GRAPH_RAG_QUESTION, TG_DOC_RAG_QUESTION, TG_AGENT_QUESTION, # Agent provenance predicates TG_THOUGHT, TG_ACTION, TG_ARGUMENTS, TG_OBSERVATION, TG_ANSWER, # Named graphs @@ -159,6 +161,8 @@ __all__ = [ # Explainability entity types "TG_QUESTION", "TG_EXPLORATION", "TG_FOCUS", "TG_SYNTHESIS", "TG_ANALYSIS", "TG_CONCLUSION", + # Question subtypes + "TG_GRAPH_RAG_QUESTION", "TG_DOC_RAG_QUESTION", "TG_AGENT_QUESTION", # Agent provenance predicates "TG_THOUGHT", "TG_ACTION", "TG_ARGUMENTS", "TG_OBSERVATION", "TG_ANSWER", # Named graphs diff --git a/trustgraph-base/trustgraph/provenance/agent.py b/trustgraph-base/trustgraph/provenance/agent.py index a62059c8..1f108795 100644 --- a/trustgraph-base/trustgraph/provenance/agent.py +++ b/trustgraph-base/trustgraph/provenance/agent.py @@ -18,6 +18,7 @@ from . namespaces import ( PROV_ACTIVITY, PROV_ENTITY, PROV_WAS_DERIVED_FROM, PROV_STARTED_AT_TIME, TG_QUERY, TG_THOUGHT, TG_ACTION, TG_ARGUMENTS, TG_OBSERVATION, TG_ANSWER, TG_QUESTION, TG_ANALYSIS, TG_CONCLUSION, + TG_AGENT_QUESTION, ) @@ -62,6 +63,7 @@ def agent_session_triples( return [ _triple(session_uri, RDF_TYPE, _iri(PROV_ACTIVITY)), _triple(session_uri, RDF_TYPE, _iri(TG_QUESTION)), + _triple(session_uri, RDF_TYPE, _iri(TG_AGENT_QUESTION)), _triple(session_uri, RDFS_LABEL, _literal("Agent Question")), _triple(session_uri, PROV_STARTED_AT_TIME, _literal(timestamp)), _triple(session_uri, TG_QUERY, _literal(query)), diff --git a/trustgraph-base/trustgraph/provenance/namespaces.py b/trustgraph-base/trustgraph/provenance/namespaces.py index 1375de94..15f1b7d3 100644 --- a/trustgraph-base/trustgraph/provenance/namespaces.py +++ b/trustgraph-base/trustgraph/provenance/namespaces.py @@ -72,7 +72,7 @@ TG_DOCUMENT = TG + "document" # Reference to document in librarian TG_CHUNK_COUNT = TG + "chunkCount" TG_SELECTED_CHUNK = TG + "selectedChunk" -# Explainability entity types (used by both GraphRAG and Agent) +# Explainability entity types (shared) TG_QUESTION = TG + "Question" TG_EXPLORATION = TG + "Exploration" TG_FOCUS = TG + "Focus" @@ -80,6 +80,11 @@ TG_SYNTHESIS = TG + "Synthesis" TG_ANALYSIS = TG + "Analysis" TG_CONCLUSION = TG + "Conclusion" +# Question subtypes (to distinguish retrieval mechanism) +TG_GRAPH_RAG_QUESTION = TG + "GraphRagQuestion" +TG_DOC_RAG_QUESTION = TG + "DocRagQuestion" +TG_AGENT_QUESTION = TG + "AgentQuestion" + # Agent provenance predicates TG_THOUGHT = TG + "thought" TG_ACTION = TG + "action" diff --git a/trustgraph-base/trustgraph/provenance/triples.py b/trustgraph-base/trustgraph/provenance/triples.py index 8c21614e..14581c6f 100644 --- a/trustgraph-base/trustgraph/provenance/triples.py +++ b/trustgraph-base/trustgraph/provenance/triples.py @@ -24,6 +24,8 @@ from . namespaces import ( TG_CHUNK_COUNT, TG_SELECTED_CHUNK, # Explainability entity types TG_QUESTION, TG_EXPLORATION, TG_FOCUS, TG_SYNTHESIS, + # Question subtypes + TG_GRAPH_RAG_QUESTION, TG_DOC_RAG_QUESTION, ) from . uris import activity_uri, agent_uri, edge_selection_uri @@ -315,6 +317,7 @@ def question_triples( return [ _triple(question_uri, RDF_TYPE, _iri(PROV_ACTIVITY)), _triple(question_uri, RDF_TYPE, _iri(TG_QUESTION)), + _triple(question_uri, RDF_TYPE, _iri(TG_GRAPH_RAG_QUESTION)), _triple(question_uri, RDFS_LABEL, _literal("GraphRAG Question")), _triple(question_uri, PROV_STARTED_AT_TIME, _literal(timestamp)), _triple(question_uri, TG_QUERY, _literal(query)), @@ -498,6 +501,7 @@ def docrag_question_triples( return [ _triple(question_uri, RDF_TYPE, _iri(PROV_ACTIVITY)), _triple(question_uri, RDF_TYPE, _iri(TG_QUESTION)), + _triple(question_uri, RDF_TYPE, _iri(TG_DOC_RAG_QUESTION)), _triple(question_uri, RDFS_LABEL, _literal("DocumentRAG Question")), _triple(question_uri, PROV_STARTED_AT_TIME, _literal(timestamp)), _triple(question_uri, TG_QUERY, _literal(query)),