Skip to content

Orchestration & Agent Patterns

How Graffold orchestrates LLM calls, manages agent lifecycles, and routes queries through multiple retrieval strategies.


Agent Architectures

Graffold implements four agent architectures, each with different tradeoffs:

1. LangGraph ReAct Agent (LangGraphAgent)

The standard agentic loop using create_react_agent from langgraph.prebuilt: - LLM decides which tool to call, observes results, decides next step - MemorySaver checkpointing for conversation persistence across turns - Kept as a fallback in the QueryService fallback chain: TwoPhase → LangGraph → basic Neo4j agent - Limitation: unpredictable in production — can loop, call irrelevant tools, produce non-deterministic results

2. TwoPhaseAgent — Deterministic Pipeline (production default)

Replaced the ReAct loop for production use: - 4-phase pipeline: Discovery → Expansion → Relevance Filtering → LLM Synthesis - The LLM only synthesizes — it never decides what to search or which tools to call - All retrieval decisions are code-driven, deterministic, and fully traced via ExecutionContext - Same query = same retrieval path = same results - See Architecture Diagrams for visual flow

3. DynamicQueryAgent

Adaptive multi-strategy agent that adjusts approach based on query complexity and available context.

4. GFQLQueryAgent

Graph Foundation Query Language agent for structured graph queries. See GFQL Patterns.


LangChain Tool Ecosystem

The agent_adapter.py module bridges the custom tool registry into LangChain's ecosystem:

  • Converts ToolRegistry definitions into LangChain StructuredTool objects
  • Pre-binds the database connection so the LLM never sees connection details
  • Group-based filtering: 15+ tools organized into 6 groups:
Group Tools Activated When
biomarker get_top_biomarkers, get_disease_proteins, get_evidence_for_association, search_entities Intent matches "biomarker", "marker", "associated with"
protein get_protein_details, get_protein_interactions, get_protein_pathways, get_shared_diseases, search_entities Intent matches "protein", "gene", "receptor", "kinase"
disease get_disease_hierarchy, get_disease_proteins, get_shared_proteins, search_entities Intent matches "disease", "disorder", "cancer"
pathway get_protein_pathways, get_pathway_members, search_entities Intent matches "pathway", "signaling", "cascade"
evidence get_evidence_for_association, get_relationship_evidence_depth, search_entities Intent matches "evidence", "pmid", "pubmed"
exploration search_entities, get_entity_disambiguation, get_graph_statistics, get_community_summary, run_cypher_query Default fallback / "overview", "how many"

Tools work with both the agentic LangGraph path and the deterministic TwoPhase path.


MCP Server (Model Context Protocol)

The same KG tools are exposed via FastMCP (src/mcp_server/server.py): - External AI assistants (Claude, Kiro, VS Code agents) can query the knowledge graph - DomainToolRegistry loads tool definitions from domain config — tools are configurable per-dataset - Three consumers share the same tool infrastructure: ReAct agent, deterministic pipeline, external AI tools


Query Classification — Three Layers

All deterministic, zero LLM calls in the hot path:

Layer 1: Query Mode Router (QueryModeRouter)

Decides which retrieval strategy to use. Priority cascade:

  1. Greetings ("hello", "help") → naive (direct vector + keyword)
  2. Both local AND global signals → mix (all strategies in parallel, weighted merge)
  3. Global keywords ("overview", "trend", "landscape") → global (community summary aggregation)
  4. Local patterns ("what is X", "tell me about X") → local (entity-focused graph traversal)
  5. LLM fallback (rarely fires) → classified mode
  6. Default → hybrid (local + global combined)

Layer 2: Intent Classifier (query_intent.classify_query)

Decides which KG tools to activate. Pure regex, six intent groups. A query can match multiple groups — "what biomarkers are associated with Alzheimer's" activates both biomarker and disease_focus.

Layer 3: Entity Type Classifier (TwoPhaseAgent._classify_query)

Decides which entity type to prioritize during graph expansion. Counts disease-signal words vs protein-signal words; whichever scores higher determines expansion direction.


Multi-Provider LLM Orchestration

  • LLMFactory supports 5 providers: AWS Bedrock, SageMaker, Ollama, OpenAI-compatible, Cloudflare Workers AI
  • Factory pattern — swapping providers is a config change, not a code change
  • TokenTrackingWrapper wraps every LLM call with token counting and cost estimation
  • Search depth tiers (fast/balanced/deep) control pipeline aggressiveness — cost optimization built into orchestration

Agent Evaluation

  • Glicko rating system — borrowed from chess, ranks agents statistically with uncertainty intervals
  • Golden dataset evaluation — YAML test queries with expected modes, keywords, and reference answers
  • Property-based testing — Hypothesis generates random inputs to test correctness invariants

See Architecture Diagrams for evaluation framework visualization.