From e5a60f783598ec84cd64e34fafc6ce0791f6305f Mon Sep 17 00:00:00 2001 From: Victor Sotero Date: Mon, 22 Jun 2026 11:12:04 +0200 Subject: [PATCH] feat(graphrag): add experimental skill Signed-off-by: Victor Sotero --- experimental/README.md | 1 + experimental/databricks-graphrag/SKILL.md | 89 +++++++++++++++++ .../databricks-graphrag/agents/openai.yaml | 7 ++ .../databricks-graphrag/assets/databricks.png | Bin 0 -> 15366 bytes .../databricks-graphrag/assets/databricks.svg | 3 + .../references/architecture-decisions.md | 58 +++++++++++ .../references/evaluation-and-operations.md | 76 +++++++++++++++ .../references/retrieval-patterns.md | 91 ++++++++++++++++++ manifest.json | 14 +++ tests/graphrag_content_test.py | 43 +++++++++ 10 files changed, 382 insertions(+) create mode 100644 experimental/databricks-graphrag/SKILL.md create mode 100644 experimental/databricks-graphrag/agents/openai.yaml create mode 100644 experimental/databricks-graphrag/assets/databricks.png create mode 100644 experimental/databricks-graphrag/assets/databricks.svg create mode 100644 experimental/databricks-graphrag/references/architecture-decisions.md create mode 100644 experimental/databricks-graphrag/references/evaluation-and-operations.md create mode 100644 experimental/databricks-graphrag/references/retrieval-patterns.md create mode 100644 tests/graphrag_content_test.py diff --git a/experimental/README.md b/experimental/README.md index b4e9802b..9329e097 100644 --- a/experimental/README.md +++ b/experimental/README.md @@ -41,6 +41,7 @@ See the root [README](../README.md) for details on the stable install path. ### 🤖 AI & Agents - **databricks-ai-functions** - Built-in AI Functions (ai_classify, ai_extract, ai_summarize, ai_query, ai_forecast, ai_parse_document, and more) with SQL and PySpark patterns, function selection guidance, document processing pipelines, and custom RAG (parse → chunk → index → query) - **databricks-agent-bricks** - Knowledge Assistants, Genie Spaces, Supervisor Agents +- **databricks-graphrag** - GraphRAG and knowledge-graph augmented retrieval architecture: compare GraphRAG vs traditional RAG, combine AI Search with graph traversal, and evaluate relationship-aware retrieval - **databricks-mlflow-evaluation** - End-to-end agent evaluation workflow - **databricks-unstructured-pdf-generation** - Generate synthetic PDFs for RAG diff --git a/experimental/databricks-graphrag/SKILL.md b/experimental/databricks-graphrag/SKILL.md new file mode 100644 index 00000000..349ae7c9 --- /dev/null +++ b/experimental/databricks-graphrag/SKILL.md @@ -0,0 +1,89 @@ +--- +name: databricks-graphrag +description: "Design GraphRAG and knowledge-graph augmented retrieval on Databricks. Use when comparing GraphRAG vs traditional RAG, combining AI Search with graph traversal, designing entity/relationship models, evaluating hybrid retrieval quality, or integrating Neo4j/Text2Cypher patterns with Unity Catalog, Databricks Apps, Model Serving, and MLflow." +compatibility: Requires databricks CLI (>= v1.0.0) +metadata: + version: "0.1.0" +parent: databricks-core +--- + +# GraphRAG on Databricks + +GraphRAG augments retrieval with explicit entities and relationships. Use it when +answers require multi-hop reasoning, exact relationship paths, explainable +provenance, or structured graph constraints that plain chunk retrieval misses. + +This skill is an architecture and evaluation guide. Databricks provides the +governed platform spine — Unity Catalog, AI Search, Databricks Apps, Model +Serving, and MLflow evaluation — while graph stores and Text2Cypher libraries are +integration choices, not Databricks-native APIs. + +## Critical Rules + +- **Start with AI Search hybrid retrieval first.** Establish a measured baseline + with keyword + vector retrieval, filters, and reranking before adding graph + complexity. +- **Use GraphRAG only when relationships matter.** If the query only needs + semantically similar passages, use `databricks-vector-search` / AI Search. +- **Keep graph queries read-only.** Text2Cypher and generated graph traversals + must run against allow-listed labels, relationship types, and result limits. +- **Evaluate before promoting.** Compare ANN, hybrid, reranker, graph traversal, + and Text2Cypher with MLflow metrics and groundedness judges. +- **Govern inputs and outputs in Unity Catalog.** Source Delta tables, derived + entity/relationship tables, AI Search indexes, and model/agent registrations + should have UC ownership, permissions, lineage, and auditability. + +## When to Use + +| User asks for | Use this skill? | Why | +|---|---:|---| +| "Should I use GraphRAG or normal RAG?" | Yes | Architecture decisioning and trade-offs | +| "Find related policies, owners, systems, and exceptions" | Yes | Relationship traversal is part of the answer | +| "Build document Q&A over PDFs" | Usually no | Start with Knowledge Assistant or AI Search RAG | +| "Improve retrieval precision for SKUs/error codes" | Maybe | Try AI Search hybrid + filters + reranker first | +| "Generate Cypher from questions" | Yes | Requires Text2Cypher safety guidance | + +## Workflow + +1. **Define answer shape.** Identify whether the answer needs passages, + entities, paths, summaries, or calculations. +2. **Build the baseline.** Use AI Search hybrid retrieval with metadata filters + and optional reranker; measure recall and groundedness. +3. **Model the graph.** If the baseline misses relationships, design entity and + relationship tables in Unity Catalog before loading an external graph store. +4. **Choose retrieval pattern.** Pick vector-to-graph expansion, full-text to + graph, Text2Cypher, or a router that chooses among them. +5. **Assemble the app/agent.** Prefer Databricks Apps for custom UX/API agents; + use Model Serving when deploying custom models, embeddings, or agent endpoints. +6. **Evaluate and operate.** Use MLflow traces, retrieval metrics, groundedness, + sufficiency, and latency budgets before recommending GraphRAG over simpler RAG. + +## Reference Files + +| File | Purpose | +|---|---| +| [references/architecture-decisions.md](references/architecture-decisions.md) | Decide when GraphRAG is worth the added complexity | +| [references/retrieval-patterns.md](references/retrieval-patterns.md) | Retrieval patterns for AI Search, Neo4j, Text2Cypher, and routers | +| [references/evaluation-and-operations.md](references/evaluation-and-operations.md) | MLflow evaluation, safety checks, observability, and operations | + +## Related Skills + +- **databricks-vector-search** — AI Search / Vector Search indexes, hybrid + search, filters, reranking, and baseline RAG. +- **databricks-apps** — Databricks Apps for custom GraphRAG UX and APIs. +- **databricks-model-serving** — serving LLMs, embeddings, custom rerankers, and + model/agent endpoints. +- **[databricks-mlflow-evaluation](../databricks-mlflow-evaluation/SKILL.md)** — + MLflow GenAI traces, datasets, scorers, and production monitoring. +- **[databricks-unity-catalog](../databricks-unity-catalog/SKILL.md)** — source + tables, governance, access control, lineage, and system tables. +- **[databricks-agent-bricks](../databricks-agent-bricks/SKILL.md)** — managed + Knowledge Assistant baseline and supervisor-agent routing comparison. + +## Official References + +- AI Search: https://docs.databricks.com/aws/en/ai-search/ai-search +- AI Search retrieval quality: https://docs.databricks.com/aws/en/ai-search/retrieval-quality +- Databricks Apps resources: https://docs.databricks.com/aws/en/dev-tools/databricks-apps/resources +- Model Serving: https://docs.databricks.com/aws/en/machine-learning/model-serving/ +- MLflow GenAI evaluation: https://docs.databricks.com/aws/en/mlflow3/genai/eval-monitor/ diff --git a/experimental/databricks-graphrag/agents/openai.yaml b/experimental/databricks-graphrag/agents/openai.yaml new file mode 100644 index 00000000..0edc7df6 --- /dev/null +++ b/experimental/databricks-graphrag/agents/openai.yaml @@ -0,0 +1,7 @@ +interface: + display_name: "Databricks Graphrag" + short_description: "Design GraphRAG and knowledge-graph augmented retrieval on Databricks." + icon_small: "./assets/databricks.svg" + icon_large: "./assets/databricks.png" + brand_color: "#FF3621" + default_prompt: "Use $databricks-graphrag for design graphrag and knowledge-graph augmented retrieval on databricks." diff --git a/experimental/databricks-graphrag/assets/databricks.png b/experimental/databricks-graphrag/assets/databricks.png new file mode 100644 index 0000000000000000000000000000000000000000..263fe98b84e8ff3516edc93e7c99230fb8fb3113 GIT binary patch literal 15366 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 + + \ No newline at end of file diff --git a/experimental/databricks-graphrag/references/architecture-decisions.md b/experimental/databricks-graphrag/references/architecture-decisions.md new file mode 100644 index 00000000..4c4b25dd --- /dev/null +++ b/experimental/databricks-graphrag/references/architecture-decisions.md @@ -0,0 +1,58 @@ +# GraphRAG Architecture Decisions + +Use GraphRAG when explicit relationships are part of the answer, not because it +sounds more advanced than RAG. The safest Databricks path is to start with a +measured AI Search baseline, then add graph retrieval only when evaluation shows +relationship context improves quality enough to justify the extra operational +cost. + +## Decision Tree + +1. **Can AI Search answer it with hybrid retrieval?** + - Use AI Search hybrid when questions need both semantic recall and exact + identifiers such as SKUs, policy IDs, entity names, error codes, or product + names. + - Add metadata filters and a reranker before introducing graph traversal. +2. **Does the user need relationship paths?** + - Use GraphRAG when answers depend on graph facts: ownership chains, + dependency paths, customer-product-symptom links, policy exceptions, or + multi-hop relationships. +3. **Is the graph schema stable enough?** + - GraphRAG works best with curated labels, relationship types, primary keys, + and provenance columns. If the schema changes every week, keep the graph as + a derived index built from governed Unity Catalog tables. +4. **Can the question be routed safely?** + - Use a router that chooses among AI Search, graph traversal, Text2Cypher, + SQL/Genie, or a managed Knowledge Assistant. + +## Architecture Options + +| Pattern | Use when | Databricks spine | Graph component | +|---|---|---|---| +| Databricks-native RAG | Documents and metadata are enough | Unity Catalog -> AI Search -> Databricks Apps or Model Serving -> MLflow | None | +| Vector-to-graph expansion | Similar chunks identify seed entities, then relationships add context | AI Search for seeds; UC for source/provenance; MLflow for eval | Neo4j or graph DB traversal | +| Full-text + graph traversal | Entity names and exact identifiers dominate | UC source tables; App/API orchestration | Full-text index plus graph relationships | +| Text2Cypher | Users ask graph-schema questions directly | Databricks App or serving endpoint with prompt safety | Read-only Cypher generation | +| Router / supervisor | Different question types need different retrievers | Databricks Apps or Agent Bricks supervisor; MLflow traces | Optional retriever tools | + +## Databricks Integration Spine + +- **Unity Catalog** governs source Delta tables, entity and relationship tables, + AI Search indexes, registered models, permissions, lineage, and auditability. +- **AI Search** is the default retrieval baseline. Use hybrid search, filters, + and reranking before graph traversal. +- **Databricks Apps** are the preferred place to host custom GraphRAG UX, query + routers, and API endpoints because app resources avoid hardcoded credentials. +- **Model Serving** is appropriate when serving custom models, embeddings, + rerankers, or an agent endpoint outside an App. +- **MLflow** records traces, retrieval spans, scorer output, and versioned + comparisons across ANN, hybrid, reranker, graph traversal, and Text2Cypher. + +## Anti-Patterns + +- Building a graph before defining answer shapes and evaluation metrics. +- Using Text2Cypher on an unconstrained schema or allowing write/delete Cypher. +- Treating Neo4j or a LangChain GraphRAG demo as a Databricks-native API. +- Skipping the AI Search baseline; most retrieval quality issues are fixed with + parsing, chunking, metadata filters, hybrid search, or a reranker. +- Returning graph facts without source documents, entity IDs, or provenance. diff --git a/experimental/databricks-graphrag/references/evaluation-and-operations.md b/experimental/databricks-graphrag/references/evaluation-and-operations.md new file mode 100644 index 00000000..dc8ebaaf --- /dev/null +++ b/experimental/databricks-graphrag/references/evaluation-and-operations.md @@ -0,0 +1,76 @@ +# GraphRAG Evaluation and Operations + +Do not recommend GraphRAG unless it beats a simpler AI Search baseline on +measured quality, latency, cost, or explainability. GraphRAG adds pipelines, +schemas, indexes, graph-store operations, and prompt-safety risk. + +## Evaluation Protocol + +1. **Create an evaluation set** with representative questions, expected answer + notes, expected entities/relationships, and source documents. +2. **Run retrieval variants**: ANN, AI Search hybrid, hybrid + reranker, graph + traversal, Text2Cypher, and router combinations. +3. **Score retrieval** with Recall@k, Precision@k, MRR, DCG@10, entity/path + recall, and latency p95. +4. **Score answer quality** with MLflow judges for groundedness, context + relevance, context sufficiency, safety, and task-specific correctness. +5. **Inspect traces** for missed entities, bad graph paths, hallucinated Cypher, + stale edges, and over-broad graph expansion. + +## MLflow Trace Tags + +Record enough metadata to debug retrieval choices: + +```python +with mlflow.start_span(name="graphrag_retrieve") as span: + span.set_attribute("retriever", "hybrid_plus_graph") + span.set_attribute("query_type", query_type) + span.set_attribute("candidate_count", len(candidates)) + span.set_attribute("graph_hops", max_hops) + span.set_attribute("reranker", reranker_name) +``` + +Track at least: + +- retriever selected by the router +- AI Search index name and query type +- graph store and schema version +- Text2Cypher prompt version and generated Cypher +- candidate counts before/after reranker +- answer citations, entity IDs, and relationship IDs + +## Operational Checklist + +- **Govern source data in Unity Catalog.** Keep entity and relationship source + tables in UC, with owners and lineage back to raw documents or structured + systems. +- **Version graph schemas.** Changes to labels, relationship names, or primary + keys can break Text2Cypher and traversal prompts. +- **Rebuild derived indexes safely.** Rebuild AI Search indexes, graph indexes, + and reranker datasets after source schema changes. +- **Use Databricks Apps resources for credentials.** Do not hardcode graph store, + AI Search, Model Serving, or SQL credentials in app code. +- **Prefer read-only graph access.** Graph write pipelines should be separate + jobs with tests, not agent runtime actions. +- **Monitor drift.** Track entity-linking quality, orphan nodes, stale edges, + retrieval failure categories, and latency/cost by retriever. + +## Failure Modes + +| Symptom | Likely cause | Fix | +|---|---|---| +| Correct document found, wrong relationship answer | Graph expansion too broad or stale edge | Add edge provenance, tighter hop limits, and relationship filters | +| Graph answer is correct but uncited | Missing source_doc_id or chunk IDs on graph nodes | Store provenance on every entity and relationship | +| Text2Cypher times out | Unbounded path or missing indexes | Validate query, add limits, index common properties | +| Hybrid beats GraphRAG | Relationships are not needed | Keep AI Search hybrid; do not ship graph complexity | +| Reranker improves quality but misses SLA | Candidate set too large or model too slow | Lower k, cache, or move reranker to Model Serving with clear p95 budget | + +## Promotion Bar + +Ship GraphRAG only when it has evidence over baseline: + +- Better groundedness or context sufficiency in MLflow evaluation. +- Better relationship/path recall on graph-specific questions. +- Acceptable latency and cost at p95. +- Clear provenance from answer to documents, entities, and relationships. +- Safe Text2Cypher validation or no generated graph query path at all. diff --git a/experimental/databricks-graphrag/references/retrieval-patterns.md b/experimental/databricks-graphrag/references/retrieval-patterns.md new file mode 100644 index 00000000..569bd6b5 --- /dev/null +++ b/experimental/databricks-graphrag/references/retrieval-patterns.md @@ -0,0 +1,91 @@ +# GraphRAG Retrieval Patterns + +GraphRAG retrieval should be explicit about the entrypoint, expansion strategy, +ranking, and provenance. Keep each retriever small and measurable; combine them +through a router rather than one large prompt. + +## Pattern 1: AI Search Baseline + +Start with AI Search hybrid retrieval. It combines semantic similarity with +keyword matching and is the default baseline for Databricks RAG. + +```python +results = w.vector_search_indexes.query_index( + index_name="catalog.schema.support_docs_index", + columns=["doc_id", "chunk_id", "text", "product", "updated_at"], + query_text=user_query, + query_type="HYBRID", + num_results=20, + filters_json='{"status": "active"}', +) +``` + +Use this before GraphRAG. Add metadata filters for tenant, region, product, +classification, or document status. Add a reranker when the candidate set is +large enough and latency budget allows. + +## Pattern 2: Vector-to-Graph Expansion + +Use AI Search to find seed chunks or entities, then expand through graph +relationships for context. + +1. Query AI Search for candidate chunks/entities. +2. Extract seed entity IDs from metadata or an entity-linking table. +3. Traverse bounded graph neighborhoods in Neo4j or another graph store. +4. Return passages plus graph facts with provenance. + +```cypher +MATCH (seed:Entity {entity_id: $entity_id})-[r:RELATED_TO*1..2]-(neighbor:Entity) +RETURN seed.name, type(r[0]) AS relationship, neighbor.name, neighbor.source_doc_id +LIMIT 50 +``` + +Use when semantically similar text points to the right area, but the answer needs +relationships such as "owned by", "depends on", "contraindicated with", or +"part of". + +## Pattern 3: Full-Text + Graph Traversal + +Use a full-text graph index when exact entity names, SKUs, contract IDs, or +technical identifiers drive recall. Then expand from matched nodes. + +```cypher +CALL db.index.fulltext.queryNodes('entityText', $query, {limit: 20}) +YIELD node, score +MATCH (node)-[r:MENTIONS|CAUSES|OWNS*1..2]-(related) +RETURN node.name, score, collect(DISTINCT related.name)[0..20] AS related_entities +``` + +This is often better than pure vector search for canonical entity names and +controlled vocabularies. + +## Pattern 4: Text2Cypher + +Text2Cypher turns a user question into a read-only Cypher query. Use it only when +the graph schema is curated and the question asks for graph facts or paths. + +Safety requirements: + +- Provide the model a compact schema: labels, relationship types, allowed + properties, examples, and forbidden operations. +- Reject or rewrite generated Cypher containing `CREATE`, `MERGE`, `DELETE`, + `SET`, `CALL dbms`, file access, or unbounded path expansion. +- Add `LIMIT` and timeout controls. +- Return the generated Cypher in traces for review. + +## Pattern 5: Router / Supervisor + +Use a router when query types differ: + +| Query type | Retriever | +|---|---| +| Semantic document lookup | AI Search hybrid | +| Exact entity relationship | Full-text + graph traversal | +| Path/multi-hop graph question | Text2Cypher or bounded traversal | +| SQL aggregate over governed tables | Genie or SQL tool | +| Managed document Q&A baseline | Knowledge Assistant | + +Databricks Apps can host the router and tool calls. Model Serving can host an +agent endpoint when the application needs a served API. MLflow traces should tag +the chosen retriever, candidate count, latency, token count, and final answer +groundedness. diff --git a/manifest.json b/manifest.json index 4a5a4be6..6f80a085 100644 --- a/manifest.json +++ b/manifest.json @@ -189,6 +189,20 @@ "repo_dir": "experimental", "version": "0.0.1" }, + "databricks-graphrag": { + "description": "Design GraphRAG and knowledge-graph augmented retrieval on Databricks. Use when comparing GraphRAG vs traditional RAG, combining AI Search with graph traversal, designing entity/relationship models, evaluating hybrid retrieval quality, or integrating Neo4j/Text2Cypher patterns with Unity Catalog, Databricks Apps, Model Serving, and MLflow.", + "files": [ + "SKILL.md", + "agents/openai.yaml", + "assets/databricks.png", + "assets/databricks.svg", + "references/architecture-decisions.md", + "references/evaluation-and-operations.md", + "references/retrieval-patterns.md" + ], + "repo_dir": "experimental", + "version": "0.1.0" + }, "databricks-iceberg": { "description": "Apache Iceberg tables on Databricks \u2014 Managed Iceberg tables, External Iceberg Reads (fka Uniform), Compatibility Mode, Iceberg REST Catalog (IRC), Iceberg v3, Snowflake interop, PyIceberg, OSS Spark, external engine access and credential vending. Use when creating Iceberg tables, enabling External Iceberg Reads (uniform) on Delta tables (including Streaming Tables and Materialized Views via compatibility mode), configuring external engines to read Databricks tables via Unity Catalog IRC, integrating with Snowflake catalog to read Foreign Iceberg tables", "files": [ diff --git a/tests/graphrag_content_test.py b/tests/graphrag_content_test.py new file mode 100644 index 00000000..7ea390c8 --- /dev/null +++ b/tests/graphrag_content_test.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +"""Content guardrails for the experimental GraphRAG skill.""" + +import unittest +from pathlib import Path + + +_REPO = Path(__file__).resolve().parent.parent +_GRAPHRAG_DIR = _REPO / "experimental" / "databricks-graphrag" + + +class GraphRAGContentTest(unittest.TestCase): + def test_graphrag_skill_has_required_guidance(self): + required_files = [ + _GRAPHRAG_DIR / "SKILL.md", + _GRAPHRAG_DIR / "references" / "architecture-decisions.md", + _GRAPHRAG_DIR / "references" / "retrieval-patterns.md", + _GRAPHRAG_DIR / "references" / "evaluation-and-operations.md", + ] + for path in required_files: + self.assertTrue(path.exists(), path) + + text = "\n".join(path.read_text() for path in required_files) + for phrase in ( + "GraphRAG", + "AI Search", + "Unity Catalog", + "Databricks Apps", + "Model Serving", + "MLflow", + "Neo4j", + "Text2Cypher", + "hybrid", + "reranker", + "groundedness", + ): + self.assertIn(phrase, text) + + self.assertIn("Start with AI Search", text) + + +if __name__ == "__main__": + unittest.main()