Graffold — Architecture Diagrams¶
1. Knowledge Graph Ingestion Pipeline¶
flowchart TB
%% ── Entry Points ───────────────────────────────────────────
subgraph ENTRY["Entry Points"]
PM["pipeline_main.py<br/>Full automated pipeline"]
EM["enrichment_main.py<br/>CSV / Parquet / TXT"]
IM["ingest_main.py<br/>PubMed abstracts"]
end
PM --> STEP1 & STEP2 & STEP3 & STEP4 & STEP5 & STEP6
%% ── Pipeline Steps ─────────────────────────────────────────
subgraph PIPELINE["PipelineExecutor — 6 Steps"]
direction TB
subgraph STEP1["Step 1 · CSV Foundation"]
direction TB
S1A["1a — OBO ontology files<br/>(MONDO disease hierarchy)"]
S1B["1b — Disease ontology CSVs"]
S1C["1c — Protein dictionaries<br/>(UniProt IDs)"]
S1D["1d — Cell type data"]
S1E["1e — Other CSVs"]
end
subgraph STEP2["Step 2 · PubMed Ingestion"]
direction TB
FETCH["Fetch abstracts<br/>via Entrez API"]
CHUNK["Chunk text<br/>(overlapping windows)"]
EXTRACT["LLM entity/relationship<br/>extraction per chunk"]
STORE_KG["Store nodes + rels<br/>in graph"]
end
subgraph STEP3["Step 3 · Entity Consolidation"]
direction TB
EC_UNI["UniProt ID merging"]
EC_SYN["Synonym / name-feature<br/>deduplication"]
EC_FUZZY["Fuzzy name matching"]
end
subgraph STEP4["Step 4 · Relationship Consolidation"]
direction TB
RC_DUP["Merge duplicate rels"]
RC_FREQ["Aggregate frequency,<br/>PMIDs, confidence"]
end
subgraph STEP5["Step 5 · Embeddings"]
direction TB
EMB_NODE["Node embeddings<br/>(all-distilroberta-v1)"]
EMB_CHUNK["Chunk embeddings<br/>(all-distilroberta-v1)"]
IDX["Create vector + fulltext<br/>indexes"]
end
subgraph STEP6["Step 6 · Validation"]
VALIDATE["Node/rel counts,<br/>index health,<br/>quality report"]
end
STEP1 --> STEP2 --> STEP3 --> STEP4 --> STEP5 --> STEP6
end
%% ── Supporting Components ──────────────────────────────────
subgraph PROCESSORS["Processors"]
direction LR
ENR_ORCH["EnrichmentOrchestrator<br/>CSV column analysis +<br/>auto-handler routing"]
OBO_PROC["OBOStructureProcessor<br/>ontology → graph"]
BIO_ENR["BiologicalEnrichment<br/>GO terms, pathways,<br/>subcellular location"]
ONT_FILT["OntologyFilter<br/>MONDO / UniProt<br/>standardization"]
end
subgraph KG_PIPE["KGPipeline (LangGraph)"]
direction TB
KG_LLM["LLM extraction<br/>(Ollama / Bedrock / OpenAI)"]
KG_UNIPROT["UniProt ID resolution"]
KG_STORE["Cypher MERGE<br/>nodes + relationships"]
end
subgraph ENTITY_RES["EntityResolver"]
direction LR
ER_FULL["run_full_entity_resolution()"]
end
subgraph REL_COUNT["RelationshipCounter"]
direction LR
RC_FULL["consolidate_comprehensive<br/>_relationships()"]
end
subgraph EMB_PIPE["EmbeddingPipeline"]
direction LR
EP_ADD["add_embeddings_to_kg()"]
EP_IDX["create vector + fulltext<br/>indexes"]
end
%% ── Database ───────────────────────────────────────────────
NEO4J[("Graph Database<br/>(Neo4j / Memgraph)")]
%% ── Connections ────────────────────────────────────────────
EM --> ENR_ORCH
IM --> KG_PIPE
S1A --> OBO_PROC
S1B & S1C & S1D & S1E --> ENR_ORCH
ENR_ORCH --> KG_PIPE
OBO_PROC --> NEO4J
STEP2 -.-> KG_PIPE
FETCH --> CHUNK --> EXTRACT --> STORE_KG
KG_LLM --> KG_UNIPROT --> KG_STORE
KG_STORE --> NEO4J
STEP3 -.-> ENTITY_RES
EC_UNI & EC_SYN & EC_FUZZY -.-> ER_FULL
ER_FULL --> NEO4J
STEP4 -.-> REL_COUNT
RC_DUP & RC_FREQ -.-> RC_FULL
RC_FULL --> NEO4J
STEP5 -.-> EMB_PIPE
EMB_NODE & EMB_CHUNK -.-> EP_ADD
IDX -.-> EP_IDX
EP_ADD & EP_IDX --> NEO4J
STEP6 --> NEO4J
BIO_ENR & ONT_FILT -.-> KG_PIPE
%% ── Factories ──────────────────────────────────────────────
subgraph FACTORIES["Factories"]
direction LR
LLM_F["LLMFactory<br/>Ollama / Bedrock /<br/>SageMaker / OpenAI"]
EMB_F["EmbeddingFactory<br/>sentence-transformers"]
end
LLM_F -.-> KG_LLM & EXTRACT
EMB_F -.-> EMB_PIPE
%% ── Styling ────────────────────────────────────────────────
classDef entryStyle fill:#4A90D9,stroke:#2C5F8A,color:#fff
classDef stepStyle fill:#50C878,stroke:#3A9D5C,color:#fff
classDef procStyle fill:#7B68EE,stroke:#5A4FCF,color:#fff
classDef dbStyle fill:#FF8C42,stroke:#CC6F35,color:#fff
classDef factoryStyle fill:#A0A0A0,stroke:#707070,color:#fff
class PM,EM,IM entryStyle
class S1A,S1B,S1C,S1D,S1E,FETCH,CHUNK,EXTRACT,STORE_KG stepStyle
class EC_UNI,EC_SYN,EC_FUZZY,RC_DUP,RC_FREQ stepStyle
class EMB_NODE,EMB_CHUNK,IDX,VALIDATE stepStyle
class ENR_ORCH,OBO_PROC,BIO_ENR,ONT_FILT,KG_LLM,KG_UNIPROT,KG_STORE procStyle
class ER_FULL,RC_FULL,EP_ADD,EP_IDX procStyle
class NEO4J dbStyle
class LLM_F,EMB_F factoryStyle
2. API + Query Agents¶
flowchart TB
%% ── Client ─────────────────────────────────────────────────
CLIENT(["Client<br/>(Streamlit UI / REST)"])
%% ── API Layer ──────────────────────────────────────────────
subgraph API["FastAPI"]
direction TB
EP_CREATE["POST /v1/sessions<br/>→ create session + agent"]
EP_QUERY["POST /v1/sessions/{id}/query<br/>→ execute query"]
EP_KNN["POST /v1/sessions/{id}/expand-knn"]
GUARDS["SecurityGuardrails<br/>PII detection · injection check"]
end
%% ── Session Manager ────────────────────────────────────────
subgraph SM["SessionManager"]
SM_CREATE["create_session(config)<br/>→ QueryService.create_agent()"]
SM_EXEC["execute_query()<br/>→ restore history<br/>→ QueryService.execute_query()"]
SM_HIST["QuerySession<br/>agent + config + history"]
end
%% ── Query Service ──────────────────────────────────────────
subgraph QS["QueryService (Orchestrator)"]
QS_AGENT["create_agent(config)<br/>routes by agent_type"]
QS_EXEC["execute_query()<br/>→ agent.sync_query()"]
QS_REFRAG["REFRAG compression<br/>(optional)"]
QS_SAN["sanitize_result()"]
end
%% ── Agent Selection ────────────────────────────────────────
subgraph AGENTS["Agent Layer"]
direction LR
NEO4J_A["Neo4jQueryAgent<br/>(Standard / Hybrid)"]
DYN_A["DynamicQueryAgent<br/>(Dynamic)"]
LANG_A["LangGraphAgent<br/>(Agentic)"]
end
%% ── Neo4jQueryAgent detail ─────────────────────────────────
subgraph NEO4J_DETAIL["Neo4jQueryAgent (extends Dynamic)"]
direction TB
N_HYBRID["HybridRetriever<br/>vector + fulltext seed search"]
N_NEIGH["Neighborhood retrieval<br/>Cypher graph traversal"]
N_GRAPHRAG["GraphRAG<br/>retriever + LLM generation"]
N_KNN["APOC KNN expansion"]
end
%% ── DynamicQueryAgent detail ───────────────────────────────
subgraph DYN_DETAIL["DynamicQueryAgent Pipeline"]
direction TB
D_QP["QueryProcessor<br/>rewrite + expand query"]
D_ED["EntityDiscovery<br/>regex extraction"]
D_SS["6 Search Strategies"]
D_RP["ResultProcessor<br/>CrossEncoder re-ranking"]
D_LLM["LLM answer synthesis"]
end
subgraph STRATEGIES["Search Strategies (parallel)"]
direction LR
S1["Vector<br/>similarity"]
S2["Fulltext<br/>search"]
S3["Schema-guided<br/>expansion"]
S4["Literature<br/>search"]
S5["Text2Cypher<br/>(LLM → Cypher)"]
S6["Dynamic<br/>expansion"]
end
%% ── LangGraphAgent detail ──────────────────────────────────
subgraph LANG_DETAIL["LangGraphAgent (ReAct)"]
direction TB
L_REACT["create_react_agent<br/>+ MemorySaver"]
subgraph TOOLS["Tools (called iteratively)"]
direction LR
T1["count_nodes"]
T2["lookup_entity"]
T3["search_knowledge_graph"]
end
L_CONF["_assess_confidence()"]
end
%% ── REFRAG ─────────────────────────────────────────────────
subgraph REFRAG["REFRAG Processor"]
direction LR
R_ENC["ChunkEncoder<br/>16-token → dense embedding"]
R_SEL["CriticalitySelector<br/>preserve key chunks"]
end
%% ── Core Layer ─────────────────────────────────────────────
subgraph CORE["Core Layer"]
direction LR
DB["DatabaseInterface<br/>(Neo4j / Memgraph)"]
VR["VectorRetriever<br/>chunk_embeddings"]
HR["HybridRetriever<br/>node_embeddings +<br/>node_fulltext"]
T2CR["Text2CypherRetriever"]
end
NEO4J[("Neo4j<br/>Knowledge Graph")]
%% ── Factories ──────────────────────────────────────────────
subgraph FACTORIES["Factories"]
direction LR
LLM_F["LLMFactory<br/>Ollama / Bedrock /<br/>SageMaker / OpenAI"]
EMB_F["EmbeddingFactory<br/>sentence-transformers"]
end
%% ── Connections ────────────────────────────────────────────
CLIENT --> EP_CREATE & EP_QUERY & EP_KNN
EP_CREATE & EP_QUERY --> GUARDS
GUARDS --> SM_CREATE & SM_EXEC
SM_CREATE --> QS_AGENT
SM_EXEC --> QS_EXEC
QS_EXEC --> QS_REFRAG --> QS_SAN
QS_AGENT -->|"Standard / Hybrid"| NEO4J_A
QS_AGENT -->|"Dynamic"| DYN_A
QS_AGENT -->|"Agentic"| LANG_A
NEO4J_A -.->|extends| DYN_A
%% Neo4j agent flow
NEO4J_A --> NEO4J_DETAIL
N_HYBRID --> N_NEIGH --> N_GRAPHRAG
N_KNN -.->|"optional"| N_NEIGH
%% Dynamic agent flow
DYN_A --> DYN_DETAIL
D_QP --> D_ED --> D_SS
D_SS --> STRATEGIES
S1 & S2 & S3 & S4 & S5 & S6 --> D_RP --> D_LLM
%% LangGraph agent flow
LANG_A --> LANG_DETAIL
L_REACT --> TOOLS
TOOLS --> L_CONF
%% REFRAG
QS_REFRAG -.-> REFRAG
R_ENC --> R_SEL
%% All agents → core → DB
NEO4J_DETAIL --> VR & HR & T2CR
STRATEGIES --> VR & HR & T2CR
T1 & T2 & T3 --> DB
VR & HR & T2CR --> DB
DB --> NEO4J
%% Factories
LLM_F -.-> DYN_A & LANG_A & NEO4J_A
EMB_F -.-> DYN_A & LANG_A & NEO4J_A
%% ── Styling ────────────────────────────────────────────────
classDef clientStyle fill:#E8E8E8,stroke:#999,color:#333
classDef apiStyle fill:#4A90D9,stroke:#2C5F8A,color:#fff
classDef serviceStyle fill:#7B68EE,stroke:#5A4FCF,color:#fff
classDef agentStyle fill:#50C878,stroke:#3A9D5C,color:#fff
classDef toolStyle fill:#FFD700,stroke:#B8A000,color:#333
classDef coreStyle fill:#FF8C42,stroke:#CC6F35,color:#fff
classDef dbStyle fill:#FF8C42,stroke:#CC6F35,color:#fff
classDef factoryStyle fill:#A0A0A0,stroke:#707070,color:#fff
class CLIENT clientStyle
class EP_CREATE,EP_QUERY,EP_KNN,GUARDS apiStyle
class SM_CREATE,SM_EXEC,SM_HIST,QS_AGENT,QS_EXEC,QS_REFRAG,QS_SAN serviceStyle
class NEO4J_A,DYN_A,LANG_A agentStyle
class T1,T2,T3,L_REACT,L_CONF toolStyle
class N_HYBRID,N_NEIGH,N_GRAPHRAG,N_KNN coreStyle
class D_QP,D_ED,D_SS,D_RP,D_LLM coreStyle
class S1,S2,S3,S4,S5,S6 coreStyle
class R_ENC,R_SEL coreStyle
class DB,VR,HR,T2CR coreStyle
class NEO4J dbStyle
class LLM_F,EMB_F factoryStyle
Agent Selection¶
Database Abstraction: All components access the graph database through a
DatabaseInterfaceabstraction layer. The concrete backend (Neo4j, Memgraph, or FalkorDB) is selected at runtime via theDATABASE_TYPEenvironment variable. This makes backends fully swappable without code changes.
| agent_type | Agent Class | Approach |
|---|---|---|
| Standard (default) | Neo4jQueryAgent |
GraphRAG + hybrid retrieval + KNN expansion |
| Hybrid | Neo4jQueryAgent |
Same as Standard |
| Dynamic | DynamicQueryAgent |
6-strategy parallel search + CrossEncoder re-ranking |
| Agentic | LangGraphAgent |
ReAct loop with iterative tool calling |
Note: Despite the
Neo4jprefix in class names, all agents work with Neo4j, Memgraph, and FalkorDB backends via theDatabaseInterfaceabstraction. The backend is selected via theDATABASE_TYPEenvironment variable.