Skip to content

RAG Studio

Purple8 RAG Studio is a configuration, tuning, and evaluation surface for the built-in RAG pipeline. Every parameter — chunking strategy, embedding model, retrieval behaviour, generation settings, and quality metrics — is configurable per tenant via REST API and Python SDK.

Since v0.27.2, RAG Studio includes a 39-model LLM registry across 9 providers, a 21-model embedding registry, 8 chunking strategies (including Late Chunking and Syntactic), and a 3-model reranker registry — all discoverable via GET /rag/models and swappable at runtime with PUT /rag/config (no restart required). v0.31.0 added Multi-Index Routing (RouterAgent), RRF Fusion, and Late Chunking. v0.32.0 added Agentic Chunking Intelligence (ChunkingAgent) with per-doc-type embedding model selection and per-label query re-embedding.

No other graph database ships a built-in RAG pipeline, let alone the tooling to tune and evaluate it.

Headless engine — build any UI you want

Purple8 Hyper Graph is headless by design. pip install purple8-hyper-graph gives you the full engine. The RAG pipeline is consumed via REST APIs — wire POST /rag/query into your own chatbot, MCP agent, backend service, CLI, or any interface that speaks HTTP. The optional web dashboard (port 3000) is a low-code convenience layer that calls the same endpoints.

Install evaluation metrics

bash
pip install "purple8-hyper-graph[eval]"   # adds DeepEval (faithfulness, relevancy, hallucination, context recall)

Architecture

┌─────────────────────────────────────────────────────────────┐
│                        RAG Studio                           │
│                                                             │
│  ┌──────────┐  ┌───────────┐  ┌──────────┐  ┌───────────┐  │
│  │ Chunking │  │ Retrieval │  │Generation│  │ Evaluation│  │
│  │ Strategy │  │  Tuning   │  │  Params  │  │  Metrics  │  │
│  └────┬─────┘  └─────┬─────┘  └────┬─────┘  └─────┬─────┘  │
│       │              │              │              │        │
│       ▼              ▼              ▼              ▼        │
│  ┌─────────────────────────────────────────────────────┐    │
│  │              POST /rag/query                        │    │
│  │  Embed → Retrieve → (Rerank) → Assemble → Generate │    │
│  └─────────────────────────────────────────────────────┘    │
│                          │                                  │
│                          ▼                                  │
│  ┌─────────────────────────────────────────────────────┐    │
│  │              POST /rag/evaluate                     │    │
│  │  Faithfulness · Relevancy · Recall · Hallucination  │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘

Configuration

Every tenant has an independent RAG configuration stored as rag_config.json in the tenant data directory. Read and write it via the REST API.

Read current config

bash
curl /rag/config \
  -H "Authorization: Bearer $TOKEN"

Update config

bash
curl -X PUT /rag/config \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "chunking_strategy": "semantic",
    "retrieval_k": 10,
    "embedding_model": "text-embedding-3-large",
    "min_similarity": 0.75,
    "hybrid_weight": 0.8,
    "temperature": 0.1,
    "max_tokens": 1024,
    "system_prompt": "You are a compliance expert. Answer using ONLY the provided context. Cite section numbers."
  }'

Only the fields you include are updated — everything else is preserved.


Chunking Strategies

Control how documents are split before embedding. Set via chunking_strategy in the RAG config. Each strategy serves a different document type and query style — pick the one that matches your data.

How to choose

Not sure which to pick? Start with Recursive Character (recursive) — it handles most document types well and is the industry default in LangChain / LlamaIndex. Switch to a specialised strategy only when evaluation scores plateau.

StrategyKeyHow it worksBest forTradeoff
Fixed-SizefixedSplit every chunk_size tokens with chunk_overlap overlapGeneral purpose, predictable chunk countMay split mid-sentence — increase overlap to mitigate
Recursive CharacterrecursiveSplit by paragraphs → sentences → words, recursively falling back until chunks fit target sizeSemi-structured text (Markdown, HTML, code) — most popular strategySlightly variable chunk sizes
SemanticsemanticEmbed each sentence, split at embedding-similarity drop-off points (topic boundaries)Long-form prose, articles, research papers — any doc with topic shiftsRequires per-sentence embedding at ingest — slower and costlier
Sentence Windowsentence_windowEach chunk is a single sentence; retrieval returns the sentence + N surrounding sentencesPrecise Q&A — legal clauses, medical records, complianceMany small chunks = larger index; best combined with a reranker
Parent–Childparent_childLarge parent chunks (e.g. 2048 tokens) + small child chunks (e.g. 256 tokens). Retrieve by child, return parent as contextTechnical manuals, legal contracts, specifications~2× index size; more complex configuration
Markdown / Headermarkdown_headerSplit at Markdown headers (# / ## / ###), preserving header hierarchy as metadata on each chunkDocumentation, READMEs, wikis, knowledge basesOnly works for structured markup; falls back to recursive for headerless sections
Late ChunkinglateEmbed the entire document first with a long-context model (voyage-4-large, 32 K ctx), then pool token embeddings into context-aware chunk vectorsLegal contracts, research papers, financial reports — any doc where cross-sentence context mattersRequires a long-context model; slower and costlier at ingest; dramatically better retrieval quality
SyntacticsyntacticSplit at syntactic boundaries (function/class/block definitions) using AST-aware parsingSource code, notebooks, structured programsRequires language detection; not suitable for prose

When to use each — decision tree

Is your content source code?
  └─ Yes → syntactic
Is your content Markdown / HTML with headings?
  └─ Yes → markdown_header
  └─ No
     ├─ Long doc (legal / research / financial) needing cross-sentence context?
     │   └─ Yes → late  (voyage-4-large, 32 K context)
     ├─ Do you need surgical single-sentence Q&A?
     │   └─ Yes → sentence_window (+ reranker)
     ├─ Are documents very long with clear topic shifts?
     │   └─ Yes → semantic
     ├─ Do answers require both local detail AND broader context?
     │   └─ Yes → parent_child
     └─ Default → recursive (best all-rounder)
         or → fixed (simplest, fastest)

Let ChunkingAgent decide automatically (v0.32.0)

Enable chunking_agent_enabled: true in PUT /rag/config and Purple8 will automatically classify each document at ingest time and select the right chunking strategy + embedding model combination. See ChunkingAgent below.

Example: Switch to semantic chunking

bash
curl -X PUT /rag/config \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"chunking_strategy": "semantic"}'
bash
curl -X PUT /rag/config \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "chunking_strategy": "late",
    "late_chunking_model": "voyage-4-large",
    "late_chunking_max_tokens": 28000
  }'
Late Chunking parameterDefaultDescription
late_chunking_modelvoyage-4-largeLong-context embedding model used for whole-document embedding before pooling
late_chunking_max_tokens32000Document token limit before late chunking falls back to recursive splitting

Supported models for late chunking:

ModelContextProvider
voyage-4-large32 K tokensVoyage AI (recommended)
jina-embeddings-v38 K tokensJina AI
text-embedding-3-large8 K tokensOpenAI (fallback)

Example: Syntactic chunking for source code (v0.32.0)

bash
curl -X PUT /rag/config \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"chunking_strategy": "syntactic"}'

Syntactic chunking uses AST-aware splitting to keep function and class definitions intact — critical for code retrieval quality. Works with Python, JavaScript, TypeScript, Go, Rust, and more.


ChunkingAgent — Automatic Strategy Selection (v0.32.0)

ChunkingAgent classifies each document at ingest time and automatically selects the optimal (chunking_strategy, embedding_model) combination for that document type. Enable it with a single config flag:

bash
curl -X PUT /rag/config \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"chunking_agent_enabled": true}'

When enabled, every POST /ingest/commit call runs classification and stores the result as node metadata:

json
{
  "doc_type": "legal_contract",
  "chunking_strategy": "late",
  "embedding_model": "voyage-4-large",
  "chunking_confidence": 0.95,
  "classification_source": "heuristic"
}

Default doc-type → strategy mapping:

Doc TypeChunking StrategyEmbedding Model
legal_contractlatevoyage-4-large
research_paperlatevoyage-4-large
documentsemanticvoyage-4-large
codesyntacticvoyage-code-3
financial_reportsemanticvoyage-finance-2
clinical_notesentence_windowvoyage-3
transcriptsentence_windowvoyage-3
markdownmarkdown_headertext-embedding-3-small
* (catch-all)fixedtext-embedding-3-small

DocIntel fast-path: If you're using Purple8 DocIntel to extract documents, pass the doc_type, chunking_hint, and suggested_embedding_model fields from job_to_preview() into /ingest/commit. The ChunkingAgent will use DocIntel's classification directly — no heuristic re-classification:

bash
curl -X POST /ingest/commit \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "source_name": "contract_q1_2026.pdf",
    "doc_type": "legal_contract",
    "chunking_hint": "late",
    "suggested_embedding_model": "voyage-4-large",
    "entities": [...]
  }'

The registry is fully customisable — save a chunking_registry.json and load it via the Python SDK:

python
from purple8_graph.chunking_agent import ChunkingStrategyRegistry

registry = ChunkingStrategyRegistry.from_file("chunking_registry.json")
# or build programmatically:
from purple8_graph.chunking_agent import ChunkingRule
registry.rules["my_doc_type"] = ChunkingRule(
    chunking_strategy="semantic",
    embedding_model="voyage-4-large",
    chunk_size=1024,
    chunk_overlap=128,
)
registry.save("chunking_registry.json")
ParameterDefaultRangeDescription
chunk_size51264–4096Target tokens per chunk. Larger = more context per retrieval, less precision. Smaller = more precise, less context. 256–1024 is the sweet spot.
chunk_overlap640–512Overlapping tokens between consecutive chunks (absolute value).
chunk_overlap_percent0–50Overlap as a percentage of chunk size. Overrides chunk_overlap when set. Recommended: 10–15%.

How overlap works

Overlap creates a "stitching" region between adjacent chunks so the LLM doesn't miss information at boundaries.

Chunk 1: [tokens 0–512]
Chunk 2: [tokens 448–960]    ← 64 tokens (12.5%) shared
Chunk 3: [tokens 896–1408]
  • Too little overlap (< 5%) → context lost at split boundaries, lower faithfulness scores.
  • Too much overlap (> 30%) → redundant embeddings waste index space and retrieval budget.
  • Sweet spot: 10–15% — enough stitching without waste.

Use the chunk_overlap_percent field to set overlap as a percentage — the backend auto-computes the absolute value. This is recommended for frontend / low-code users who shouldn't need to know chunk sizes in tokens.

Example: 15% overlap on 1024-token chunks

bash
curl -X PUT /rag/config \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"chunk_size": 1024, "chunk_overlap_percent": 15}'
# → backend computes chunk_overlap = 153 tokens

Retrieval Tuning

Fine-tune how the RAG pipeline retrieves context from the graph.

ParameterDefaultRangeDescription
retrieval_k51–100Number of graph nodes retrieved per query
embedding_modeltext-embedding-3-smallAny supported modelEmbedding model for query encoding. Swap without reindexing.
min_similarity0.70.0–1.0Cosine similarity floor. Raise for precision, lower for recall.
hybrid_weight0.70.0–1.0Balance between BM25 (0.0) and vector (1.0) in hybrid retrieval
mmr_diversity0.00.0–1.0Maximal Marginal Relevance — higher values reduce redundancy in retrieved context
rerankernullProvider nameOptional reranker (e.g. "cohere") applied after initial retrieval
fusion_strategyweightedweighted | rrfFusion method for hybrid retrieval. rrf = Reciprocal Rank Fusion (rank-position–based, no weight tuning needed). (v0.31.0)
rrf_k601–200RRF constant k in score = 1/(k + rank). 60 is the empirically optimal value (Cormack et al. 2009). (v0.31.0)
routing_enabledfalseboolEnable RouterAgent — per-label strategy dispatch via rag_routing.json. (v0.31.0)

Embedding Models

Purple8 Hyper Graph supports any OpenAI-compatible embedding model. The following are pre-configured and returned by GET /rag/models:

Listing available models

bash
curl /rag/models -H "Authorization: Bearer $TOKEN" | jq '.embedding_models[] | {id, provider, dimensions}'
ModelProviderDimensionsMax TokensBest for
text-embedding-3-smallOpenAI1,5368,191Default — fast, cheap, strong multilingual
text-embedding-3-largeOpenAI3,0728,191Highest-quality OpenAI. Supports dimension reduction (256–3072).
embed-v4.0Cohere1,536128,000Latest Cohere. Text + image + PDF. 128k context. Flexible dims.
embed-english-v3.0Cohere1,024512English-only. Good quality/speed balance.
embed-multilingual-v3.0Cohere1,024512100+ languages.
voyage-4-largeVoyage AI1,02432,000Best general-purpose retrieval quality. Flexible dims (256–2048).
voyage-4Voyage AI1,02432,000Balanced quality/cost.
voyage-code-3Voyage AI1,02432,000Optimized for code retrieval.
voyage-finance-2Voyage AI1,02432,000Optimized for financial documents.
voyage-law-2Voyage AI1,02416,000Optimized for legal documents.
gemini-embedding-001Google7682,048Google Gemini text embedding.
text-embedding-004Google7682,048Google PaLM. Good for GCP stacks.
amazon.titan-embed-text-v2:0AWS Bedrock1,0248,192AWS-native stacks.
BAAI/bge-large-en-v1.5Self-hosted1,024512Top open-source English (MIT). vLLM / TEI / Ollama.
BAAI/bge-m3Self-hosted1,0248,192Open-source 100+ language multi-granularity.
nomic-ai/nomic-embed-text-v1.5Self-hosted7688,192Apache 2.0. Matryoshka dims (64–768). Budget self-hosted.
mixedbread-ai/mxbai-embed-large-v1Self-hosted1,024512Top MTEB benchmark. Apache 2.0. Binary quantization.

Custom models: set embedding_model to any model ID your provider accepts. If you're using a self-hosted model behind an OpenAI-compatible API (vLLM, TEI, Ollama), just point OPENAI_BASE_URL to your server.

Reranker Models

ModelDescription
cohereCohere Rerank v4 Pro — state-of-the-art multilingual, 32k context, supports semi-structured JSON
cohere-fastCohere Rerank v4 Fast — low-latency variant for high-throughput pipelines
cross-encoderCross-Encoder (self-hosted) — run locally (e.g. ms-marco-MiniLM). No API cost, full privacy.
bash
curl -X PUT /rag/config \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "retrieval_k": 15,
    "min_similarity": 0.85,
    "hybrid_weight": 0.5,
    "mmr_diversity": 0.3,
    "reranker": "cohere"
  }'
bash
curl -X PUT /rag/config \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "retrieval_k": 25,
    "min_similarity": 0.5,
    "hybrid_weight": 0.6,
    "mmr_diversity": 0.0
  }'

RRF Fusion — fusion_strategy: "rrf" (v0.31.0)

Reciprocal Rank Fusion replaces weighted-sum as the hybrid fusion strategy. Because it works on rank positions rather than raw scores, it handles mismatched score distributions (BM25 vs cosine similarity vs graph-hop count) without manual weight tuning.

bash
curl -X PUT /rag/config \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"fusion_strategy": "rrf", "rrf_k": 60}'

RRF score: score(d) = Σ 1 / (k + rank_r(d)) across all retrievers. k=60 is the empirically optimal constant (Cormack et al. 2009). Set k lower to amplify top-rank differences; set it higher to reduce their impact.


Multi-Index Router — RouterAgent (v0.31.0)

RouterAgent dispatches each query to the optimal retrieval strategy based on the matched node label and query confidence. Configure per-label rules in rag_routing.json and enable with one flag:

bash
# Enable routing
curl -X PUT /rag/config \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"routing_enabled": true}'

# Configure per-label routing rules
curl -X PUT /rag/routing \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "Document": [{"strategy": "hybrid",  "min_confidence": 0.0}],
    "Person":   [{"strategy": "graph",   "min_confidence": 0.8, "expand_hops": 2},
                 {"strategy": "vector",  "min_confidence": 0.0}],
    "Code":     [{"strategy": "bm25",    "min_confidence": 0.0, "embedding_model": "voyage-code-3"}],
    "*":        [{"strategy": "hybrid",  "min_confidence": 0.0}]
  }'

The embedding_model field on a routing rule (v0.32.0) triggers per-label query re-embedding — when a query matches the Code label, the router re-embeds the query with voyage-code-3 before searching the code vector sub-space. This ensures the query vector lives in the same domain-specific space as the indexed code chunks.

Each response includes a "retrieval" metadata block:

json
{
  "answer": "...",
  "retrieval": {
    "strategy": "bm25",
    "label_matched": "Code",
    "embedding_model_used": "voyage-code-3",
    "latency_ms": 1.4,
    "fusion": null
  }
}

Read and write routing rules:

bash
# Read current routing config
curl /rag/routing -H "Authorization: Bearer $TOKEN"

# Replace entire routing config
curl -X PUT /rag/routing \
  -H "Authorization: Bearer $TOKEN" \
  -d @rag_routing.json

Generation Parameters

Control how the LLM generates answers from the retrieved context.

ParameterDefaultRangeDescription
provideropenaiSee providers tableLLM provider — determines which API endpoint is called
modelgpt-5.4-miniAny supported modelLanguage model ID for answer generation
temperature0.00.0–2.0Randomness. 0.0 = deterministic, higher = more creative.
max_tokens5121–4096Maximum tokens in the generated answer
top_p1.00.0–1.0Nucleus sampling. Lower values = more focused.
system_prompt(see below)Any stringSystem instruction sent to the LLM before the context + question

Supported LLM Providers

Provider keyServiceAuth required
openaiOpenAI APIapi_key
azure_openaiAzure OpenAI Serviceazure_endpoint + api_key + azure_deployment
anthropicAnthropic APIapi_key
googleGoogle AI (Gemini API)api_key
vertexGoogle Vertex AIgoogle_project + google_location
bedrockAWS Bedrockaws_region + optional aws_profile
mistralMistral AI (La Plateforme)api_key
cohereCohere APIapi_key
self-hostedAny OpenAI-compatible endpointbase_url + optional api_key

Language Models

All models are pre-configured in the backend registry and returned by GET /rag/models. Use the model id as the model config value.

💡 Tip: Run curl /rag/models -H "Authorization: Bearer $TOKEN" | jq '.llm_models[] | {id, provider, context_window}' to discover all available models.

ModelProviderContext WindowMax OutputBest for
gpt-5.4OpenAI1M128kFlagship — best intelligence for agentic, coding, complex reasoning
gpt-5.4-miniOpenAI400k128kFast, cost-efficient — ideal default for RAG pipelines
gpt-5.4-nanoOpenAI200k64kLowest latency and cost — high-volume extraction
o3OpenAI200k100kAdvanced reasoning with thinking tokens — math, science
o4-miniOpenAI200k100kFast reasoning — STEM tasks
claude-sonnet-4-20250514Anthropic200k64kBest speed/intelligence balance — strong tool use and coding
claude-opus-4-20250514Anthropic200k32kMost intelligent Claude — sustained autonomous performance
claude-3.5-haiku-20241022Anthropic200k8kFastest Claude 3.5 — classification, extraction, high-throughput
claude-haiku-4-20250514Anthropic200k8kUltra-fast Claude 4 — real-time classification, routing, high-volume extraction
gemini-3.1-pro-previewGoogle1M65kMost advanced Gemini — deep reasoning, agentic coding
gemini-3-flashGoogle1M65kFrontier-class performance at fraction of the cost
gemini-2.5-flashGoogle1M65kBest price-performance — low-latency reasoning
gemini-2.5-proGoogle1M65kDeep reasoning + coding with 1M token context
gemini-2.5-flash-liteGoogle1M65kFastest and most budget-friendly Gemini
mistral-large-latestMistral128k32kState-of-the-art open-weight multimodal
mistral-medium-latestMistral128k32kFrontier-class multimodal — strong tool use
mistral-small-latestMistral128k32kHybrid instruct/reasoning/coding — open-weight
magistral-medium-latestMistral128k32kMultimodal reasoning model
magistral-small-latestMistral128k32kFast, cost-efficient reasoning with multilingual support
codestral-latestMistral256k32kCutting-edge code generation — 256k context
command-a-03-2025Cohere256k8kMost performant Cohere — RAG, agents, multilingual
command-a-reasoning-08-2025Cohere256k32kFirst Cohere reasoning model — 23 languages
command-r7b-12-2024Cohere128k4kSmall, fast — excels at RAG and tool use
amazon.nova-pro-v1:0AWS Bedrock300k5kMultimodal — strong for AWS-native stacks
amazon.nova-lite-v1:0AWS Bedrock300k5kFast, budget-friendly multimodal
amazon.nova-micro-v1:0AWS Bedrock128k5kText-only, lowest latency and cost
llama-4-maverick-17b-128eSelf-hosted1M32kLlama 4 Maverick — 17B active (128 experts MoE), 1M context, multimodal
llama-4-scout-17b-16eSelf-hosted512k32kLlama 4 Scout — 17B active (16 experts MoE), 512k context, efficient
llama-3.3-70bSelf-hosted128k32kOpen-weight via vLLM / Ollama — strong general-purpose
deepseek-r1Self-hosted128k32kOpen reasoning model — math, code, logic

Custom models: set provider and model to any combination your deployment supports. For self-hosted models, point base_url to your OpenAI-compatible server (vLLM, Ollama, TGI, etc.).

Choosing a model for RAG

                            ┌─────────────────────┐
                            │ What's your priority?│
                            └──────┬──────────────┘
                       ┌───────────┼───────────┐
                       ▼           ▼           ▼
                   Quality      Speed       Cost
                       │           │           │
                       ▼           ▼           ▼
              gpt-5.4 / opus   gpt-5.4-nano  gpt-5.4-mini
              gemini-2.5-pro   haiku         gemini-2.5-flash
              gemini-3.1-pro   nova-micro    command-a

💡 RAG best practice: Start with gpt-5.4-mini or gemini-2.5-flash (fast, cheap, strong). Upgrade to gpt-5.4 or claude-sonnet-4 only if answer quality on your domain needs it. For privacy-first deployments, use llama-3.3-70b self-hosted via vLLM.

Default system prompt

You are a knowledge assistant. Answer the question using ONLY the graph context provided.
Cite entity names when relevant. If the context doesn't contain the answer, say so.

Example: Custom system prompt for compliance

bash
curl -X PUT /rag/config \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "provider": "anthropic",
    "model": "claude-sonnet-4-20250514",
    "temperature": 0.0,
    "max_tokens": 1024,
    "system_prompt": "You are a regulatory compliance assistant for a financial institution. Answer using ONLY the graph context. Cite regulation section numbers. If the context is insufficient, explicitly state what is missing."
  }'

Evaluation

RAG Studio includes built-in evaluation using DeepEval metrics. Run a test set through your pipeline and get quality scores — no external tooling required.

Install

bash
pip install "purple8-hyper-graph[eval]"

Available metrics

MetricWhat it measuresScore range
FaithfulnessIs the answer supported by the retrieved context? (no hallucinated facts)0.0–1.0
Answer RelevancyDoes the answer address the question?0.0–1.0
Context RecallDid the retriever find the right context nodes?0.0–1.0
HallucinationDoes the answer contain claims not in the context? (lower is better)0.0–1.0

Run an evaluation

bash
curl -X POST /rag/evaluate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "test_cases": [
      {
        "question": "Who authored the most papers on neural scaling laws?",
        "expected_answer": "Dr. Emily Chen authored 12 papers on neural scaling laws."
      },
      {
        "question": "What is the current compliance status of Project Alpha?",
        "expected_answer": "Project Alpha has 2 outstanding audit findings."
      },
      {
        "question": "Which building has the highest seismic risk?",
        "expected_answer": "Building C-7 has the highest seismic risk score of 0.89."
      }
    ],
    "metrics": ["faithfulness", "answer_relevancy", "context_recall", "hallucination"]
  }'

Response

json
{
  "test_cases": 3,
  "results": [
    {
      "question": "Who authored the most papers on neural scaling laws?",
      "answer": "Based on the graph, Dr. Emily Chen authored 12 papers...",
      "context_nodes": ["n_42", "n_87", "n_103"],
      "scores": {
        "faithfulness": 0.95,
        "answer_relevancy": 0.92,
        "context_recall": 0.88,
        "hallucination": 0.05
      }
    }
  ],
  "aggregates": {
    "faithfulness": 0.91,
    "answer_relevancy": 0.89,
    "context_recall": 0.85,
    "hallucination": 0.08
  },
  "config": {
    "retrieval_k": 10,
    "embedding_model": "text-embedding-3-large",
    "min_similarity": 0.75,
    "chunking_strategy": "semantic",
    "temperature": 0.0
  }
}

Prometheus metrics

When evaluation_enabled: true is set in the RAG config, evaluation scores are automatically exported as Prometheus gauges:

MetricLabelsDescription
purple8_rag_faithfulnesstenant_idRolling average faithfulness score
purple8_rag_answer_relevancytenant_idRolling average answer relevancy
purple8_rag_context_recalltenant_idRolling average context recall
purple8_rag_hallucination_ratetenant_idRolling average hallucination rate

These metrics are scrapeable at GET /metrics alongside all existing Purple8 Prometheus metrics. See Observability for Grafana dashboard setup.


A/B Testing Workflow

RAG Studio configs are per-tenant — use this to A/B test different configurations:

1. Baseline

bash
# Save baseline config
curl -X PUT /rag/config -H "Authorization: Bearer $TENANT_A_TOKEN" \
  -d '{"retrieval_k": 5, "embedding_model": "text-embedding-3-small", "chunking_strategy": "fixed"}'

# Run evaluation
curl -X POST /rag/evaluate -H "Authorization: Bearer $TENANT_A_TOKEN" \
  -d '{"test_cases": [...], "metrics": ["faithfulness", "answer_relevancy", "context_recall"]}'
# → aggregates: {faithfulness: 0.82, answer_relevancy: 0.78, context_recall: 0.71}

2. Candidate

bash
# Save candidate config
curl -X PUT /rag/config -H "Authorization: Bearer $TENANT_B_TOKEN" \
  -d '{"retrieval_k": 15, "embedding_model": "text-embedding-3-large", "chunking_strategy": "semantic", "reranker": "cohere"}'

# Run same evaluation
curl -X POST /rag/evaluate -H "Authorization: Bearer $TENANT_B_TOKEN" \
  -d '{"test_cases": [...], "metrics": ["faithfulness", "answer_relevancy", "context_recall"]}'
# → aggregates: {faithfulness: 0.91, answer_relevancy: 0.89, context_recall: 0.85}

3. Compare

MetricBaseline (A)Candidate (B)Delta
Faithfulness0.820.91+11%
Answer Relevancy0.780.89+14%
Context Recall0.710.85+20%

Promote the winner by copying the config to your production tenant.


Python SDK

All RAG Studio features are available programmatically:

python
from purple8_graph.genai import AIGraphBuilder, OpenAIProvider

provider = OpenAIProvider(api_key="sk-...")
builder = AIGraphBuilder(engine=engine, provider=provider)

# Natural language query — uses the full RAG pipeline
result = await builder.query("Who are the key stakeholders for Project Alpha?")

# The /rag/config, /rag/query, and /rag/evaluate endpoints are also
# available via the REST API client:
from httpx import AsyncClient

async with AsyncClient(base_url="http://localhost:8000") as client:
    # Update config
    await client.put("/rag/config", json={
        "chunking_strategy": "semantic",
        "retrieval_k": 15,
        "temperature": 0.1,
    }, headers={"Authorization": f"Bearer {token}"})

    # Query
    resp = await client.post("/rag/query", json={
        "question": "What is the compliance status of Building C-7?",
    }, headers={"Authorization": f"Bearer {token}"})

    # Evaluate
    resp = await client.post("/rag/evaluate", json={
        "test_cases": [
            {"question": "...", "expected_answer": "..."},
        ],
        "metrics": ["faithfulness", "answer_relevancy"],
    }, headers={"Authorization": f"Bearer {token}"})

Consuming the RAG Pipeline

Purple8 Hyper Graph is headless — the generation endpoint POST /rag/query is designed to be consumed from any interface. Here are the four common patterns:

1. MCP (AI Agents)

The RAG pipeline is exposed as an MCP tool (rag_query), so any MCP-compatible AI agent (Claude Desktop, Cursor, VS Code Copilot) can query your knowledge graph with natural language — zero custom code:

bash
pip install "purple8-hyper-graph[mcp]"
purple8-hyper-graph mcp serve
Tool: rag_query
Input: {"question": "What compliance violations were flagged last quarter?"}
→ Returns grounded answer + source nodes

The MCP tool inherits the tenant's RAG Studio configuration — all tuning applies automatically.

2. Chatbot / Custom UI

Wire POST /rag/query into any conversational interface — Streamlit, Gradio, React chat widget, Slack bot, Teams integration, or a custom app:

python
# Streamlit chatbot (5 lines)
import streamlit as st, httpx

question = st.chat_input("Ask your knowledge graph…")
if question:
    r = httpx.post("http://localhost:8000/rag/query",
        json={"question": question},
        headers={"Authorization": f"Bearer {TOKEN}"})
    st.chat_message("assistant").write(r.json()["answer"])
typescript
// React / Next.js — fetch from any frontend
const res = await fetch('/api/rag/query', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ question }),
});
const { answer, context_nodes } = await res.json();

3. Backend Service

Another microservice calls the REST API — no SDK required, just HTTP:

python
async def answer_customer_query(question: str) -> str:
    async with httpx.AsyncClient() as client:
        r = await client.post("http://purple8-hyper-graph-api:8000/rag/query",
            json={"question": question},
            headers={"Authorization": f"Bearer {SERVICE_TOKEN}"})
        return r.json()["answer"]

4. CLI / Scripts / CI

bash
curl -s -X POST http://localhost:8000/rag/query \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"question": "Who are the key stakeholders?"}' | jq -r .answer

The optional web UI

The bundled web UI (purple8-hyper-graph-ui, port 3000) is a fifth option — a point-and-click dashboard for teams who prefer a low-code experience. It calls the same POST /rag/query endpoint under the hood. Developers who have built their own interface don't need it.


Complete Configuration Reference

json
{
  "retrieval_k": 5,
  "embedding_model": "text-embedding-3-small",
  "min_similarity": 0.7,
  "reranker": null,
  "hybrid_weight": 0.7,
  "mmr_diversity": 0.0,
  "fusion_strategy": "weighted",
  "rrf_k": 60,
  "routing_enabled": false,

  "chunking_strategy": "fixed",
  "chunk_size": 512,
  "chunk_overlap": 64,
  "chunk_overlap_percent": null,
  "late_chunking_model": "voyage-4-large",
  "late_chunking_max_tokens": 32000,
  "chunking_agent_enabled": false,

  "provider": "openai",
  "model": "gpt-5.4-mini",
  "temperature": 0.0,
  "max_tokens": 512,
  "top_p": 1.0,
  "system_prompt": "You are a knowledge assistant. Answer the question using ONLY the graph context provided. Cite entity names when relevant. If the context doesn't contain the answer, say so.",

  "evaluation_enabled": false
}

All fields are optional in PUT /rag/config — only the fields you include are updated.

Supported values

FieldTypeValues
providerstringopenai, azure_openai, anthropic, google, vertex, bedrock, mistral, cohere, self-hosted
modelstringAny model from GET /rag/models .llm_models or a custom ID
chunking_strategystringfixed, recursive, semantic, sentence_window, parent_child, markdown_header, late, syntactic
embedding_modelstringAny model from GET /rag/models .embedding_models or a custom ID
rerankerstring | nullnull, cohere, cohere-fast, cross-encoder
chunk_overlap_percentfloat | nullnull (use absolute chunk_overlap) or 0–50 (auto-computes chunk_overlap)
fusion_strategystringweighted (default), rrf (v0.31.0)
rrf_kint1–200, default 60 (v0.31.0)
routing_enabledboolfalse (default), true — enables RouterAgent (v0.31.0)
late_chunking_modelstringAny long-context embedding model ID, default voyage-4-large (v0.31.0)
late_chunking_max_tokensintToken limit before fallback to recursive, default 32000 (v0.31.0)
chunking_agent_enabledboolfalse (default), true — enables ChunkingAgent at ingest (v0.32.0)

Model & strategy discovery

bash
# List all supported embedding models, LLM models, chunking strategies, and rerankers
curl /rag/models -H "Authorization: Bearer $TOKEN"

Response:

json
{
  "embedding_models": [
    {"id": "text-embedding-3-small", "provider": "openai", "dimensions": 1536, "max_tokens": 8191, "description": "..."},
    ...
  ],
  "llm_models": [
    {"id": "gpt-5.4-mini", "provider": "openai", "context_window": 400000, "max_output": 128000, "description": "..."},
    {"id": "claude-sonnet-4-20250514", "provider": "anthropic", "context_window": 200000, "max_output": 64000, "description": "..."},
    ...
  ],
  "chunking_strategies": [
    {"id": "recursive", "label": "Recursive Character", "description": "...", "when": "...", "why": "...", "tradeoff": "..."},
    ...
  ],
  "reranker_models": [
    {"id": "cohere", "label": "Cohere Rerank v4 Pro", "description": "..."},
    ...
  ]
}

Purple8 Graph is proprietary software. All rights reserved.