Multi-agent orchestration layer for the Knowledge Graph Lab project.
LangGraph StateGraph with a Supervisor + Specialists pattern: an Orchestrator classifies the intent and delegates to 6 specialised agents that interact with the backend via HTTP.
Full project documentation in the root README.
- Architecture
- Stack
- Prerequisites
- Local setup
- Configuration
- Running
- Agent API
- Agents
- LangGraph orchestration
- Memory
- Testing
- Docker
- Directory structure
User request
|
v
┌─────────────────┐
│ ORCHESTRATOR │ classifies intent (regex, 8 intents)
│ Router+Planner │ builds an execution plan
└────────┬────────┘
│ LangGraph conditional edges
┌─────┴──────────────────────────┐
│ │
┌──▼──────┐ ┌─────────┐ ┌────────▼────┐
│INGESTION│ │ ANALYST │ │ SYNTHESIS │
│ AGENT │ │ AGENT │ │ AGENT │
└──┬──────┘ └────┬────┘ └──────┬──────┘
│ │ │
┌──▼──────┐ ┌────▼────┐ ┌──────▼──────┐
│VALIDATOR│ │ KGC │ │ MONITOR │
│ AGENT │ │ AGENT │ │ AGENT │
└─────────┘ └─────────┘ └─────────────┘
│ HTTP REST
┌────────▼─────────┐
│ knowledge-graph │
│ -api │
│ Neo4j + Redis │
└──────────────────┘
| Component | Technology |
|---|---|
| Orchestration | LangGraph 0.2+ (StateGraph + conditional routing) |
| Agent framework | LangChain 0.3+ |
| REST API | FastAPI 0.115+ + uvicorn |
| HTTP client | httpx 0.27+ (calls to knowledge-graph-api) |
| Data models | Pydantic v2 |
| LLM | Ollama (llama3, via direct httpx) |
| Testing | pytest + pytest-asyncio |
| Linting | ruff |
- Python 3.11+
knowledge-graph-apirunning athttp://localhost:8000- Ollama reachable at
http://localhost:11434
Start infrastructure + API (from the repo root):
make up-infra # Neo4j + Redis + Ollama
make run # knowledge-graph-api on port 8000cd knowledge-graph-agents
# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate # Linux / macOS
# venv\Scripts\activate # Windows
# Install dependencies
pip install -r requirements.txt
# Or from the repo root
make agents-install| Variable | Default | Description |
|---|---|---|
KG_API_URL |
http://localhost:8000 |
FastAPI backend URL |
OLLAMA_BASE_URL |
http://localhost:11434 |
Ollama base URL |
OLLAMA_LLM_MODEL |
llama3 |
LLM model for generation |
KG_API_TIMEOUT |
60 |
HTTP timeout in seconds |
cp .env.example .env # then edit as needed# With hot-reload (port 8001)
uvicorn api.agent_api:app --reload --port 8001
# Or from the repo root
make agents-run- Agent API:
http://localhost:8001 - Swagger UI:
http://localhost:8001/docs
In Docker the internal port 8001 is mapped to host port 8002 to avoid a conflict with RedisInsight.
Execute the multi-agent workflow for a natural-language request.
curl -X POST http://localhost:8001/agents/run \
-H "Content-Type: application/json" \
-d '{"request": "What do you know about Neo4j?", "thread_id": "default"}'Request body:
| Field | Type | Default | Description |
|---|---|---|---|
request |
string | required | Natural-language request |
thread_id |
string | default |
KG namespace to operate on |
context |
dict | {} |
Extra params (e.g. file_path, topic) |
Response (AgentRunResponse):
{
"run_id": "uuid",
"intent": "query",
"output": "Neo4j is a graph database...",
"plan": [{"agent": "analyst", "action": "hybrid_search", "status": "done"}],
"quality": {"overall_health": 0.85},
"duration_ms": 2340,
"error": null
}Retrieve the record of a previous run.
List the last N runs (default 20), ordered by date descending.
{ "status": "ok", "kg_api": true, "kg_api_url": "http://localhost:8000" }| Agent | Activated intents | Responsibility |
|---|---|---|
| Orchestrator | all | Classifies intent, builds plan — never calls tools directly |
| Ingestion | ingest |
Health check, dedup, kg_ingest, report |
| Analyst | query, analyze |
Vector / graph / hybrid search (3 strategies) |
| Validator | validate |
4 Cypher queries, KGQualityReport with overall_health |
| KGC | kgc |
Transitive closure + similarity, proposes missing relations |
| Synthesis | synthesize |
RAG context + Ollama, Markdown report (optional auto-ingest) |
| Monitor | monitor, health |
Health check + quality alert summary |
| Keywords in request | Intent | Agent |
|---|---|---|
| ingest, upload, load | ingest |
Ingestion |
| what do you know, describe, tell me | query |
Analyst |
| analyse, count, statistics | analyze |
Analyst |
| report, generate, summarise | synthesize |
Synthesis |
| validate, quality check | validate |
Validator |
| missing relations, gap | kgc |
KGC |
| health, status, monitor | monitor |
Monitor |
The StateGraph is defined in orchestration/graph.py:
START → orchestrator → [route_by_intent] → specialised_agent → END
Conditional routing:
ingest→ingestion→validatorkgc→kgc→synthesis- all others →
END
Shared state (AgentState) flows through all nodes as a TypedDict:
class AgentState(TypedDict):
request: str
thread_id: str
intent: Intent
plan: list[AgentStep]
context: dict
output: str
error: str | None
quality: dictEach run produces an AgentRunRecord (Pydantic) saved in two places:
- In-process store (
dict) — always available, reset on restart - Neo4j (best-effort) —
AgentRunnode viaPOST /graph/cypher/write
MATCH (r:AgentRun {run_id: $run_id})
RETURN r.agent_name, r.intent, r.status, r.duration_mscd knowledge-graph-agents
pytest tests/ -v
# Or from the repo root
make agents-test8 tests with mocked httpx — no live services needed.
Coverage: intent classification, planner, async agents, error handling.
# Start via compose (prod profile) — host port 8002
docker compose --profile prod up agents -d
# Follow logs
docker compose logs -f agents
# Health check
curl http://localhost:8002/agents/healthknowledge-graph-agents/
├── agents/
│ ├── orchestrator.py # Router + Planner (intent → plan)
│ ├── ingestion.py # Ingestion Agent
│ ├── analyst.py # Analyst Agent (3 strategies)
│ ├── validator.py # Validator Agent (KGQualityReport)
│ ├── kgc.py # KGC Agent (missing relations)
│ ├── synthesis.py # Synthesis Agent (Ollama report)
│ └── monitor.py # Monitor Agent (health + alerts)
├── orchestration/
│ ├── state.py # AgentState, Intent, AgentStep
│ ├── router.py # Intent classification (regex)
│ ├── planner.py # build_plan() per intent
│ └── graph.py # StateGraph + conditional routing
├── tools/
│ └── kg_tools.py # 8 async HTTP wrappers for kg-api
├── memory/
│ └── kg_memory.py # AgentRunRecord + in-process store + Neo4j
├── api/
│ └── agent_api.py # FastAPI app (port 8001)
├── tests/
│ ├── conftest.py
│ └── test_agents.py
├── Dockerfile
├── requirements.txt
├── pyproject.toml # asyncio_mode = "auto"
└── .env.example