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
ToolRegistrydefinitions into LangChainStructuredToolobjects - 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:
- Greetings ("hello", "help") → naive (direct vector + keyword)
- Both local AND global signals → mix (all strategies in parallel, weighted merge)
- Global keywords ("overview", "trend", "landscape") → global (community summary aggregation)
- Local patterns ("what is X", "tell me about X") → local (entity-focused graph traversal)
- LLM fallback (rarely fires) → classified mode
- 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¶
LLMFactorysupports 5 providers: AWS Bedrock, SageMaker, Ollama, OpenAI-compatible, Cloudflare Workers AI- Factory pattern — swapping providers is a config change, not a code change
TokenTrackingWrapperwraps 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.