Complete System Design — 13 Agents · 18 Tools · LangGraph State Machine

Insurance KG-RAG
Orchestrator & Agent Architecture

A production-grade multi-agent system using LangGraph with FIBO-ontology-driven GraphRAG, purpose-built for 100K+ insurance and wealth planning documents. Every agent, tool, task, and state transition — fully specified.

01 / ARCHITECTURE

Orchestrator Design Overview

The system comprises 13 specialized agents organized into 5 functional layers, coordinated by a central LangGraph state machine. Each agent owns a narrow responsibility and communicates through a typed shared state.

Multi-Agent Orchestrator — 5 Layers · 13 Agents · 18 Tools
LAYER 1 — INGESTION & INTAKE LAYER 2 — QUERY UNDERSTANDING LAYER 3 — RETRIEVAL & SEARCH LAYER 4 — REASONING & VALIDATION LAYER 5 — SYNTHESIS & DELIVERY PDF Ingestion Agent Chunk & Embed Agent TTL Generator Agent Cluster Manager Agent Query Classifier Agent Entity Extractor Agent Route Planner Agent Vector Retriever Agent Graph Retriever Agent PathRAG Traverser Agent (Multi-Hop) Hallucination Guard Agent Contradiction Detector Agent Answer Synthesizer Agent (LLM) Provenance Citer Agent LangGraph Orchestrator StateGraph with TypedDict Conditional Routing Parallel Execution Human-in-the-Loop User Query Natural Language Cited Answer + PDF Pages

Why 13 Agents?

Each agent follows the Single Responsibility Principle. The PDF Ingestion Agent only extracts text and bounding boxes — it doesn't embed, it doesn't build triples. This means you can swap out the embedding model without touching ingestion logic, upgrade the SPARQL generator without affecting vector search, or add a new validation layer without rewriting synthesis. In a regulated domain like insurance, this separation also gives you auditability: you can trace exactly which agent produced which piece of the final answer.

Why LangGraph over CrewAI?

LangGraph provides explicit state management through TypedDict, conditional routing via edges, and native support for parallel execution and human-in-the-loop checkpoints. For a financial services system where every state transition must be auditable and the orchestration logic must handle 5 distinct retrieval patterns with branching, LangGraph's graph-based state machine is the right choice. CrewAI YAML configs are also provided (Section 8) for teams preferring role-based setup.

02 / ALL 13 AGENTS

Agent Registry — Complete Specifications

Each agent has a defined role, goal, backstory, tools, input/output schema, and the LangGraph node it occupies. Organized by the 5 functional layers.

LAYER 1 — INGESTION & INTAKE (Offline Pipeline)

01

PDF Ingestion Agent

Role: Extract raw text, tables, and bounding box coordinates from insurance PDFs using pdfplumber. Assign hierarchical document IDs ({CATEGORY}_{SUBCATEGORY}_{ORG}_{YEAR}_{SEQ}). Detect document type (policy, rider, endorsement, claim form).

Input: Raw PDF file path  →  Output: Structured pages with text + bbox metadata

PDFExtractorTool DocumentClassifierTool IDGeneratorTool
02

Chunk & Embed Agent

Role: Split extracted pages into semantically coherent chunks (target: 512 tokens with 50-token overlap). Generate embeddings via text-embedding-3-large. Store each chunk with full metadata: chunk_id, pdf_id, page_number, chunk_sequence, bbox, embedding vector.

Input: Extracted pages  →  Output: Embedded chunks in Pinecone + metadata in PostgreSQL

SemanticChunkerTool EmbeddingTool PineconeUpsertTool PostgresWriteTool
03

TTL Generator Agent

Role: Convert chunks into FIBO-aligned RDF triples in Turtle format. Use ontology-guided NER to identify policy clauses, coverage terms, exclusions, waiting periods, and premium structures. Each triple carries prov:wasDerivedFrom linking back to the source chunk ID. Uses LLM-assisted triple extraction for complex clauses.

Input: Embedded chunks  →  Output: Individual .ttl files per PDF in GraphDB

OntologyMapperTool TripleExtractorTool GraphDBLoaderTool
04

Cluster Manager Agent

Role: Maintain semantic clusters of TTL files for efficient cross-policy SPARQL queries. Generate clustered TTL files by insurance type/provider/year. Track cluster membership and staleness in cluster_manifest.json. Trigger quarterly re-clustering via Louvain community detection on query co-occurrence graphs.

Input: Individual TTLs + query logs  →  Output: Cluster TTLs + manifest

ClusterBuilderTool ManifestTrackerTool LouvainClusterTool

LAYER 2 — QUERY UNDERSTANDING (Real-Time)

05

Query Classifier Agent

Role: Analyze incoming query using lightweight LLM (Claude Haiku) to determine: entity density, comparison indicators, reasoning depth (single vs multi-hop), precision requirements. Outputs a classification label matching one of the 5 retrieval patterns.

Input: Raw query string  →  Output: QueryClassification object

LLMClassifierTool QueryExampleDBTool
06

Entity Extractor Agent

Role: Extract named entities from the query — policy IDs, provider names, disease names, clause types, financial terms — and resolve them to ontology URIs. Uses both regex patterns (for known formats like LIFE_TERM_PRUDENTIAL_*) and LLM-based NER (for natural language entity mentions).

Input: Raw query  →  Output: List of EntityMention with ontology URIs

NERTool OntologyResolverTool
07

Route Planner Agent

Role: Based on the QueryClassification and extracted entities, select the retrieval pattern (1–5) and plan the execution sequence. For Pattern 3 (Vector→Graph), it specifies: "first search vectors for critical illness chunks in {providers}, then extract structured attributes via SPARQL." Generates an execution DAG.

Input: Classification + entities  →  Output: ExecutionPlan (ordered agent calls)

PatternSelectorTool DAGBuilderTool

LAYER 3 — RETRIEVAL & SEARCH (Real-Time)

08

Vector Retriever Agent

Role: Execute semantic similarity search against Pinecone. Embed the query, retrieve top-k chunks (default k=20), apply cross-encoder re-ranking (ms-marco-MiniLM), deduplicate overlapping chunks, and return ranked results with full metadata (pdf_id, page_number, bbox).

Input: Query + filter params  →  Output: Ranked chunk list with scores

PineconeSearchTool CrossEncoderTool EmbeddingTool
09

Graph Retriever Agent

Role: Generate and execute SPARQL queries against GraphDB. For structural queries, traverses from entity nodes to related clauses. For comparison queries, extracts structured attributes (coverage amounts, waiting periods, exclusion lists) into a tabular format. Respects cluster boundaries — queries individual TTLs for specific policies, cluster TTLs for cross-policy aggregation.

Input: Entities + query type  →  Output: Structured results + graph paths

SPARQLGeneratorTool GraphDBQueryTool ClusterSelectorTool
10

PathRAG Traverser Agent

Role: Handle multi-hop reasoning queries (Pattern 5). Traces relationship paths through the knowledge graph: pre-existing condition → waiting period → subsequent condition → causal chain → coverage determination. At each hop, optionally invokes vector search for clause interpretation context. Uses Reciprocal Rank Fusion (RRF) to merge graph paths with vector results.

Input: Multi-hop query plan  →  Output: Fused path+vector results

GraphPathTracerTool RRFMergerTool HeatDiffusionTool

LAYER 4 — REASONING & VALIDATION (Real-Time)

11

Hallucination Guard Agent

Role: Validate every factual claim in the draft answer against the retrieved context. For each claim, check: (1) Is it directly supported by at least one retrieved chunk? (2) Does the graph path confirm the relationship? (3) Is the numerical value (amounts, durations) exactly quoted? Flag unsupported claims for removal or re-retrieval. Enforces "no fact without a source" policy.

Input: Draft answer + context  →  Output: Validated answer with confidence scores

ClaimVerifierTool GraphPathValidatorTool
12

Contradiction Detector Agent

Role: Before synthesis, scan all retrieved chunks and graph results for contradictions. Run SPARQL contradiction-detection queries (same condition, different values). When contradictions are found, flag them explicitly in the answer ("Note: Policy X states 90 days while Policy Y states 60 days for the same condition") rather than letting the LLM silently average them.

Input: Retrieved results set  →  Output: Contradiction report + cleaned context

SPARQLContradictionTool SemanticDiffTool

LAYER 5 — SYNTHESIS & DELIVERY (Real-Time)

13a

Answer Synthesizer Agent

Role: Generate the final natural-language answer using Claude Sonnet/Opus. Receives validated context chunks, structured graph results, contradiction reports, and the original query. Produces an answer with inline chunk ID citations [C042]. For comparison queries, generates formatted tables. Follows a strict prompt template that demands per-fact attribution.

Input: Validated context + query  →  Output: Answer text with [chunk_id] citations

LLMSynthesisTool ComparisonFormatterTool
13b

Provenance Citer Agent

Role: Parse chunk IDs from the synthesized answer, resolve each to its pdf_id + page_number + bbox coordinates via PostgreSQL metadata lookup. Generate the citation block ("Source: Prudential Term Life 2024, Pages 15, 27–29"). Package the highlight coordinates for the dual-pane PDF viewer UI. This is the final agent before response delivery.

Input: Answer with [C_ids]  →  Output: Final cited response + PDF highlight data

ChunkResolverTool CitationFormatterTool BBoxHighlighterTool
03 / ALL 18 TOOLS

Tool Registry — Complete Specifications

Every tool follows the LangChain BaseTool interface with typed inputs/outputs, error handling, and retry logic. Tools are shared across agents where appropriate.

#Tool NameUsed ByDescriptionExternal Service
1PDFExtractorToolAgent 01Extract text + bounding boxes from PDF using pdfplumber. Returns page-by-page content with (x,y,w,h) coordinates for every text block.pdfplumber lib
2DocumentClassifierToolAgent 01Classify document type (policy, rider, endorsement, claim form, brochure) using a fine-tuned classifier or LLM zero-shot.Claude Haiku
3IDGeneratorToolAgent 01Generate hierarchical IDs: {CAT}_{SUBCAT}_{ORG}_{YEAR}_{SEQ}. Checks PostgreSQL for sequence uniqueness.PostgreSQL
4SemanticChunkerToolAgent 02Split pages into semantically coherent chunks (512 tokens, 50-token overlap). Uses sentence-boundary detection and semantic similarity thresholds.Local (spaCy)
5EmbeddingToolAgents 02, 08Generate 1536-dim embeddings via text-embedding-3-large. Batched processing for ingestion, single-query for real-time.OpenAI API
6PineconeUpsertToolAgent 02Upsert vectors with metadata (pdf_id, page_number, chunk_sequence, category, provider) to Pinecone serverless index.Pinecone
7PostgresWriteToolAgent 02Write chunk metadata (bbox coords, TTL URIs, cluster membership) to PostgreSQL with JSONB indexing.PostgreSQL 15+
8OntologyMapperToolAgent 03Map extracted entities to FIBO ontology classes. Uses a lookup table of 200+ insurance-specific concept → FIBO URI mappings.Local ontology
9TripleExtractorToolAgent 03LLM-assisted RDF triple extraction from text chunks. Outputs subject-predicate-object triples with prov:wasDerivedFrom provenance.Claude Sonnet
10GraphDBLoaderToolAgent 03Load TTL files into Ontotext GraphDB via SPARQL UPDATE. Creates named graphs per document.GraphDB
11LLMClassifierToolAgent 05Lightweight LLM call (Haiku) to classify query intent: entity density, comparison indicators, reasoning depth, precision needs.Claude Haiku
12NERToolAgent 06Named Entity Recognition combining regex patterns (policy IDs, providers) with LLM-based NER (diseases, clause types).Local + LLM
13PineconeSearchToolAgent 08Execute cosine similarity search against Pinecone with metadata filters (provider, category, year range). Returns top-k with scores.Pinecone
14CrossEncoderToolAgent 08Re-rank initial vector results using cross-encoder model (ms-marco-MiniLM-L-12-v2) for higher precision.Local model
15SPARQLGeneratorToolAgents 09, 12Generate SPARQL 1.1 queries from natural language + entity URIs. Supports SELECT, CONSTRUCT, and ASK query forms.LLM + templates
16GraphDBQueryToolAgents 09, 10Execute SPARQL queries against GraphDB endpoint. Handles named graph selection (individual vs cluster).GraphDB
17RRFMergerToolAgent 10Reciprocal Rank Fusion to merge results from vector search and graph traversal into a unified ranked list.Local
18LLMSynthesisToolAgent 13aClaude Opus/Sonnet call with structured prompt template demanding per-fact [chunk_id] attribution.Claude Sonnet
04 / LANGGRAPH STATE MACHINE

Shared State Schema & Graph Definition

The entire orchestration is defined as a LangGraph StateGraph with a TypedDict shared state. Every agent reads from and writes to this state, and conditional edges route between agents based on the retrieval pattern selected.

GraphState — TypedDict Definition

state.py
from typing import TypedDict, List, Optional, Literal
from dataclasses import dataclass, field
from enum import Enum

class RetrievalPattern(Enum):
    VECTOR_ONLY       = "vector_only"
    GRAPH_ONLY        = "graph_only"
    VECTOR_THEN_GRAPH = "vector_then_graph"
    GRAPH_THEN_VECTOR = "graph_then_vector"
    PATHRAG_HYBRID    = "pathrag_hybrid"

class GraphState(TypedDict):
    # ── Layer 2: Query Understanding ──
    query:              str                        # Original user query
    classification:     dict                       # {entity_density, has_comparison, reasoning_hops, precision}
    entities:           List[dict]                 # [{text, type, ontology_uri, confidence}]
    retrieval_pattern:  RetrievalPattern           # Selected pattern (1-5)
    execution_plan:     List[str]                  # Ordered list of agent node names to invoke

    # ── Layer 3: Retrieval Results ──
    vector_results:     List[dict]                 # [{chunk_id, text, score, pdf_id, page, bbox}]
    graph_results:      List[dict]                 # [{subject, predicate, object, source_chunk}]
    pathrag_results:    List[dict]                 # [{path, hops, vector_context, fused_score}]
    merged_context:     List[dict]                 # RRF-merged final context

    # ── Layer 4: Validation ──
    contradictions:     List[dict]                 # [{clause1, clause2, value1, value2, condition}]
    validated_context:  List[dict]                 # Filtered context after hallucination guard
    confidence_scores:  dict                       # Per-claim confidence

    # ── Layer 5: Synthesis ──
    draft_answer:       str                        # LLM-generated answer with [C_id] citations
    final_answer:       str                        # Validated answer after hallucination guard
    citations:          List[dict]                 # [{chunk_id, pdf_id, page, bbox, text_snippet}]
    pdf_highlights:     List[dict]                 # [{pdf_id, page, x, y, width, height, color}]

    # ── Metadata ──
    error:              Optional[str]              # Error message if any step fails
    iteration_count:    int                        # Re-retrieval loop counter (max 2)
    human_review:       bool                       # Flag for human-in-the-loop checkpoint

LangGraph Builder — Complete Graph Definition

orchestrator.py
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.memory import MemorySaver

def build_orchestrator() -> StateGraph:
    graph = StateGraph(GraphState)

    # ═══ Register all 13 agent nodes ═══
    # Layer 2: Query Understanding
    graph.add_node("classify_query",   query_classifier_agent)
    graph.add_node("extract_entities", entity_extractor_agent)
    graph.add_node("plan_route",       route_planner_agent)

    # Layer 3: Retrieval
    graph.add_node("vector_retrieve",  vector_retriever_agent)
    graph.add_node("graph_retrieve",   graph_retriever_agent)
    graph.add_node("pathrag_traverse", pathrag_traverser_agent)

    # Layer 4: Validation
    graph.add_node("detect_contradictions", contradiction_detector_agent)
    graph.add_node("guard_hallucination",   hallucination_guard_agent)

    # Layer 5: Synthesis
    graph.add_node("synthesize_answer", answer_synthesizer_agent)
    graph.add_node("cite_provenance",   provenance_citer_agent)

    # ═══ Define edges ═══
    # Sequential: classify → extract → plan → (conditional routing)
    graph.set_entry_point("classify_query")
    graph.add_edge("classify_query",   "extract_entities")
    graph.add_edge("extract_entities", "plan_route")

    # ═══ Conditional routing based on retrieval pattern ═══
    graph.add_conditional_edges(
        "plan_route",
        route_to_retriever,   # Router function (below)
        {
            "vector_only":       "vector_retrieve",
            "graph_only":        "graph_retrieve",
            "vector_then_graph": "vector_retrieve",   # Start with vector
            "graph_then_vector": "graph_retrieve",    # Start with graph
            "pathrag_hybrid":    "pathrag_traverse",
        }
    )

    # ═══ Pattern-specific chaining ═══
    # After vector retrieval, check if we need graph refinement
    graph.add_conditional_edges(
        "vector_retrieve",
        needs_graph_refinement,
        {
            "refine":    "graph_retrieve",     # Pattern 3: Vec→Graph
            "validate":  "detect_contradictions", # Pattern 1: Vec only
        }
    )

    # After graph retrieval, check if we need vector expansion
    graph.add_conditional_edges(
        "graph_retrieve",
        needs_vector_expansion,
        {
            "expand":    "vector_retrieve",     # Pattern 4: Graph→Vec
            "validate":  "detect_contradictions", # Pattern 2 or 3 done
        }
    )

    # PathRAG always goes to validation
    graph.add_edge("pathrag_traverse",      "detect_contradictions")

    # Validation → Synthesis → Citation → END
    graph.add_edge("detect_contradictions",  "guard_hallucination")

    # Hallucination guard can trigger re-retrieval (max 2 loops)
    graph.add_conditional_edges(
        "guard_hallucination",
        check_confidence,
        {
            "sufficient":   "synthesize_answer",
            "re_retrieve":  "plan_route",     # Loop back with refined query
            "human_review": "synthesize_answer", # Flag for HITL
        }
    )

    graph.add_edge("synthesize_answer",  "cite_provenance")
    graph.add_edge("cite_provenance",   END)

    # ═══ Compile with checkpointing ═══
    memory = MemorySaver()
    return graph.compile(checkpointer=memory)


# ═══ Router Functions ═══
def route_to_retriever(state: GraphState) -> str:
    return state["retrieval_pattern"].value

def needs_graph_refinement(state: GraphState) -> str:
    if state["retrieval_pattern"] == RetrievalPattern.VECTOR_THEN_GRAPH:
        return "refine"
    return "validate"

def needs_vector_expansion(state: GraphState) -> str:
    if state["retrieval_pattern"] == RetrievalPattern.GRAPH_THEN_VECTOR:
        return "expand"
    return "validate"

def check_confidence(state: GraphState) -> str:
    if state["iteration_count"] >= 2:
        return "human_review"     # Max retries exceeded
    avg_conf = sum(state["confidence_scores"].values()) / max(len(state["confidence_scores"]), 1)
    if avg_conf >= 0.8:
        return "sufficient"
    return "re_retrieve"
05 / AGENT EXECUTION FLOWS

How Agents Collaborate Per Pattern

Each of the 5 retrieval patterns activates a different subset and ordering of agents. Here's the exact execution sequence for each.

PatternTriggerAgent Execution SequenceExample Query
P1: Vector-Only Fuzzy / exploratory, no specific entities Classifier → Entity Extractor → Route Planner → Vector Retriever → Contradiction Detector → Hallucination Guard → Synthesizer → Provenance Citer "What policies cover chronic kidney disease?"
P2: Graph-Only Structural, known entities, precise Classifier → Entity Extractor → Route Planner → Graph Retriever → Contradiction Detector → Hallucination Guard → Synthesizer → Provenance Citer "List all exclusions in LIFE_TERM_PRUDENTIAL_2024_00127"
P3: Vec → Graph Comparison queries Classifier → Entity Extractor → Route Planner → Vector RetrieverGraph Retriever → Contradiction Detector → Hallucination Guard → Synthesizer → Provenance Citer "Compare CI coverage across Prudential, HDFC, LIC"
P4: Graph → Vec Claim validation Classifier → Entity Extractor → Route Planner → Graph RetrieverVector Retriever → Contradiction Detector → Hallucination Guard → Synthesizer → Provenance Citer "Can this diabetes claim be approved under policy X?"
P5: PathRAG Multi-hop reasoning, causal chains Classifier → Entity Extractor → Route Planner → PathRAG Traverser (graph hops + vector at each hop) → Contradiction Detector → Hallucination Guard → Synthesizer → Provenance Citer "Pre-existing hypertension → diabetes → heart attack claim?"

Re-Retrieval Loop (Hallucination Guard Feedback)

When the Hallucination Guard finds claims with confidence below 0.8, it triggers a re-retrieval loop. The state's iteration_count increments, the Route Planner is re-invoked with a refined query (adding specificity based on what was missing), and the retrieval agents run again with adjusted parameters (higher k, different filters). Maximum 2 loops before escalating to human review. This closed-loop design ensures answer quality meets financial services regulatory standards.

06 / LIVE SIMULATOR

Multi-Agent Flow Simulator

Watch all 13 agents collaborate in real time. Select a query to see which agents activate, in what order, and what each contributes to the final answer.

Agent Execution Trace

Interactive
Select a query to visualize the full 13-agent execution trace.
07 / IMPLEMENTATION

Project Structure & Setup

Complete production project layout with all agent implementations, tool definitions, and configuration.

Project Directory

insurance_kg_rag/
insurance_kg_rag/
├── agents/
│   ├── __init__.py
│   ├── layer1_ingestion/
│   │   ├── pdf_ingestion_agent.py       # Agent 01
│   │   ├── chunk_embed_agent.py         # Agent 02
│   │   ├── ttl_generator_agent.py       # Agent 03
│   │   └── cluster_manager_agent.py     # Agent 04
│   ├── layer2_understanding/
│   │   ├── query_classifier_agent.py    # Agent 05
│   │   ├── entity_extractor_agent.py    # Agent 06
│   │   └── route_planner_agent.py       # Agent 07
│   ├── layer3_retrieval/
│   │   ├── vector_retriever_agent.py    # Agent 08
│   │   ├── graph_retriever_agent.py     # Agent 09
│   │   └── pathrag_traverser_agent.py   # Agent 10
│   ├── layer4_validation/
│   │   ├── hallucination_guard_agent.py # Agent 11
│   │   └── contradiction_detector_agent.py # Agent 12
│   └── layer5_synthesis/
│       ├── answer_synthesizer_agent.py  # Agent 13a
│       └── provenance_citer_agent.py    # Agent 13b
├── tools/
│   ├── __init__.py
│   ├── pdf_tools.py                     # Tools 1-3
│   ├── embedding_tools.py              # Tools 4-7
│   ├── ontology_tools.py               # Tools 8-10
│   ├── classification_tools.py         # Tools 11-12
│   ├── search_tools.py                 # Tools 13-14
│   ├── graph_tools.py                  # Tools 15-16
│   ├── fusion_tools.py                 # Tool 17
│   └── synthesis_tools.py              # Tool 18
├── state/
│   ├── __init__.py
│   └── graph_state.py                  # GraphState TypedDict
├── orchestrator/
│   ├── __init__.py
│   ├── graph_builder.py                # LangGraph StateGraph definition
│   └── router_functions.py             # Conditional edge functions
├── ontology/
│   ├── insurance_fibo.ttl              # FIBO-aligned insurance ontology
│   ├── namespaces.py                   # URI namespace bindings
│   └── concept_mappings.json           # 200+ concept → FIBO URI mappings
├── config/
│   ├── config.yaml                     # All service endpoints, model names
│   └── .env                            # API keys (Pinecone, OpenAI, Anthropic)
├── api/
│   └── server.py                       # FastAPI serving layer
├── ui/
│   └── dual_pane_viewer.html           # Bloomberg-style answer + PDF viewer
├── crewai_config/                      # Alternative CrewAI YAML configs
│   ├── agents.yaml
│   └── tasks.yaml
├── docker-compose.yml
├── requirements.txt
├── main.py                             # Entry point
└── README.md

requirements.txt

requirements.txt
# Core Orchestration
langgraph==0.2.60
langchain==0.3.12
langchain-anthropic==0.3.5
langchain-openai==0.2.14

# Vector Store
pinecone-client==5.0.1

# Graph Store
SPARQLWrapper==2.0.0
rdflib==7.1.1

# Document Processing
pdfplumber==0.11.4
spacy==3.8.3

# Embeddings & Re-ranking
sentence-transformers==3.3.1
openai==1.58.1

# Database
psycopg2-binary==2.9.10
redis==5.2.1
sqlalchemy==2.0.36

# API Server
fastapi==0.115.6
uvicorn==0.34.0

# Utilities
pydantic==2.10.3
python-dotenv==1.0.1
httpx==0.28.1
08 / CREWAI YAML CONFIGS

Alternative: CrewAI Role-Based Configuration

For teams preferring CrewAI's declarative YAML approach over LangGraph's programmatic graph definition. These configs mirror the same 13 agents and their tasks.

agents.yaml (excerpt — 5 of 13)

crewai_config/agents.yaml
query_classifier:
  role: Insurance Query Classifier
  goal: >
    Classify user queries by intent, entity density,
    comparison indicators, and reasoning depth to
    select the optimal retrieval pattern (1-5).
  backstory: >
    Expert in insurance domain query understanding
    with deep knowledge of policy terminology,
    claim workflows, and regulatory language.
  tools:
    - LLMClassifierTool
    - QueryExampleDBTool
  llm: claude-haiku-4-5-20251001
  verbose: true

entity_extractor:
  role: Insurance Entity Extractor
  goal: >
    Extract policy IDs, provider names, disease names,
    clause types, and financial terms from queries and
    resolve them to FIBO ontology URIs.
  backstory: >
    NER specialist trained on 100K+ insurance documents
    with expertise in FIBO, ICD-10, and insurance
    regulatory terminology.
  tools:
    - NERTool
    - OntologyResolverTool

vector_retriever:
  role: Semantic Search Specialist
  goal: >
    Execute cosine similarity search, re-rank results,
    deduplicate overlapping chunks, and return the
    top-k most relevant context with full provenance.
  backstory: >
    Search engineer specializing in dense retrieval
    with cross-encoder re-ranking for financial docs.
  tools:
    - PineconeSearchTool
    - CrossEncoderTool
    - EmbeddingTool

hallucination_guard:
  role: Financial Accuracy Validator
  goal: >
    Verify every factual claim against retrieved context.
    No fact without a source. Flag unsupported claims
    for removal or re-retrieval.
  backstory: >
    Regulatory compliance auditor who has reviewed
    thousands of insurance documents and knows that
    in financial services, accuracy is non-negotiable.
  tools:
    - ClaimVerifierTool
    - GraphPathValidatorTool

answer_synthesizer:
  role: Insurance Answer Synthesizer
  goal: >
    Generate clear, accurate, fully-cited answers from
    validated context. Every fact must include a [C_id]
    citation. Comparison queries produce formatted tables.
  backstory: >
    Senior insurance analyst who can translate complex
    policy language into clear, actionable answers
    while maintaining regulatory-grade attribution.
  tools:
    - LLMSynthesisTool
    - ComparisonFormatterTool
  llm: claude-sonnet-4-20250514

tasks.yaml (excerpt)

crewai_config/tasks.yaml
classify_query_task:
  description: >
    Analyze the query: "{query}"
    Determine entity density (count), comparison
    indicators, reasoning hops (single/multi),
    and precision requirements. Output the
    RetrievalPattern (1-5).
  expected_output: >
    JSON: {pattern, entity_density, has_comparison,
    reasoning_hops, precision_needed, confidence}
  agent: query_classifier

extract_entities_task:
  description: >
    From query "{query}", extract all named entities:
    policy IDs, providers, diseases, clause types.
    Resolve each to its FIBO ontology URI.
  expected_output: >
    List of {text, type, ontology_uri, confidence}
  agent: entity_extractor
  context:
    - classify_query_task

vector_search_task:
  description: >
    Search Pinecone for top-20 chunks matching
    the query. Apply filters from extracted entities.
    Re-rank with cross-encoder. Return with full
    metadata (pdf_id, page, bbox).
  expected_output: >
    Ranked list of {chunk_id, text, score, pdf_id,
    page_number, bbox}
  agent: vector_retriever
  context:
    - extract_entities_task

validate_answer_task:
  description: >
    Verify every claim in the draft answer against
    retrieved context. For each claim: check chunk
    support, graph path confirmation, and numerical
    accuracy. Output confidence scores.
  expected_output: >
    Validated answer with per-claim confidence scores.
    Unsupported claims flagged for removal.
  agent: hallucination_guard
  context:
    - synthesize_answer_task

cite_provenance_task:
  description: >
    Parse [C_id] citations from the validated answer.
    Resolve each chunk_id to pdf_id, page_number,
    and bbox coordinates. Generate citation block
    and PDF highlight data for dual-pane viewer.
  expected_output: >
    Final answer with human-readable citations and
    highlight coordinates for PDF viewer overlay.
  agent: provenance_citer
  context:
    - validate_answer_task