Graph-native framework for building AI agents with persistent execution state.
Every agent's execution is a directed graph—GOAL → TASK → ACTION → SYNTHESIS. Persistence is backed by FalkorDB, so you can inspect the full state of every agent at http://localhost:3000.
- 🚀 Built-in tool pipeline — agents don't hallucinate; they mutate graphs explicitly
- 🔄 Multi-turn chat — sessions preserve full context across turns
- 🤝 Multi-agent patterns — subagents, skills, handoffs, routers all share the parent graph
- 💾 Persistent execution — every node, edge, and message is queryable in FalkorDB
- 🧠 Semantic memory — cross-turn reasoning with embeddings
pip install agentic-graphsuvx agentic-graphs # or
uv add agentic-graphs# Use other LLM providers
pip install agentic-graphs[anthropic,gemini,groq] # or [all]
# Development
pip install agentic-graphs[dev]docker run -d -p 6379:6379 -p 3000:3000 --name falkordb falkordb/falkordb:latestThen open http://localhost:3000 to inspect agent state.
import asyncio
from agentic_graphs import Agent, OpenAILLM, tool
@tool
def add(a: float, b: float) -> float:
"""Add two numbers."""
return a + b
@tool
def multiply(a: float, b: float) -> float:
"""Multiply two numbers."""
return a * b
class MathAgent(Agent):
"""Simple math agent with custom tools."""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._extra_action_tools = {"add": add, "multiply": multiply}
self._extra_action_schemas = [add.schema, multiply.schema]
def build_tools(self, node):
schemas, impls = super().build_tools(node)
schemas += self._extra_action_schemas
impls.update(self._extra_action_tools)
return schemas, impls
async def main():
llm = OpenAILLM(model="gpt-4o-mini")
agent = MathAgent(llm, "What is (17 * 3 + 42) / 9?")
result = await agent.run()
print(f"Answer: {result}")
asyncio.run(main())from agentic_graphs.session import Session
from agentic_graphs.core.falkordb_backend import FalkorDBBackend
async def chat():
session = await Session.create(
llm=OpenAILLM(model="gpt-4o-mini"),
agent_class=MathAgent,
backend=FalkorDBBackend(),
thread_name="math-session",
user_id="alice",
)
# Each turn builds a fresh graph, history is auto-injected
reply = await session.chat("What is 5 * 8?")
print(reply)
reply = await session.chat("Add 10 to that result")
print(reply)
# Resume later by thread ID
session = await Session.create(..., thread_id=session.thread_id)# Math agent (single-turn)
uv run python -m agentic_graphs.examples.math_agent "What is 15 + 27?"
uv run python -m agentic_graphs.examples.math_agent --chat # Interactive
# Multi-turn chat session
uv run python -m agentic_graphs.examples.chat_session
# Multi-agent with subagents (research + math)
uv run python -m agentic_graphs.examples.multi_agent_demo
# Session debugger — inspect execution graphs
uv run python -m agentic_graphs.examples.debug_session
uv run python -m agentic_graphs.examples.debug_session --thread <thread-id>Open http://localhost:3000 to see the graph state in real-time.
Every agent execution builds a directed graph. Node types and states:
GOAL → TASK → ACTION → SYNTHESIS → (resolved)
↓
(pending/ready/active/resolved/failed)
- GOAL — user's request
- TASK — sub-goal decomposition
- ACTION — tool calls (mutations, external APIs)
- SYNTHESIS — final answer generation
Agents automatically have:
create_task(label, ...)— create a TASK nodecreate_action(label, instruction)— create an ACTION noderesolve_current_node(output)— mark node as RESOLVEDadd_dependency(waiting, prereq)— set up blocking edgesget_token_usage()— retrieve accumulated token costs
ACTION nodes also get your custom tools (e.g., add, multiply).
Subagents — delegate to child agents in sub-GOAL nodes:
agent.register_subagent(
"researcher",
agent_class=ResearchAgent,
description="Research any topic",
)Skills — progressive disclosure of domain tools:
agent.register_skill(
"web_search",
tools=[search.schema],
tool_fns={"search": search},
description="Search the web",
)Handoffs — state-driven agent switching:
if "financial" in task:
await agent.handoff_to("financial_analyst")- ✅ OpenAI — gpt-4o, gpt-4o-mini, gpt-4-turbo, gpt-5
- ✅ Anthropic — claude-sonnet-4, claude-opus
- ✅ Google Gemini — gemini-2.0-flash, gemini-pro
- ✅ Groq — mixtral, llama
- ✅ Ollama — local models
- ✅ Azure OpenAI
Switch providers with:
from agentic_graphs import AnthropicLLM, GeminiLLM
llm = AnthropicLLM(model="claude-sonnet-4")
llm = GeminiLLM(model="gemini-2.0-flash")Each node tracks cumulative token costs:
agent = Agent(llm, goal)
result = await agent.run()
# Check usage on any node
for node_id, node in agent.graph.nodes.items():
usage = node.props.get("_usage", {})
print(f"{node.label}: {usage.get('total_tokens')} tokens")Graph Model:
- Every agent owns a
Graphobject - Nodes have states: PENDING → READY → ACTIVE → RESOLVED | FAILED
- Edges define dependencies: REQUIRES (blocking), PART_OF (structural), PRODUCES (data)
Scheduler:
- Processes nodes in dependency order
- Auto-retries failed nodes with exponential backoff
- Persists state to FalkorDB on every mutation
Backend:
- FalkorDB stores all nodes, edges, messages as queryable graphs
- Each turn is a separate graph; sessions maintain history
- Semantic search finds similar prior problems for transfer learning
See docs/ARCHITECTURE.md for deep dive.
export OPENAI_API_KEY=sk-... # OpenAI
export ANTHROPIC_API_KEY=sk-ant-... # Anthropic
export GOOGLE_API_KEY=AIzaSy... # Gemini
export GROQ_API_KEY=gsk_... # Groq
export FALKORDB_HOST=localhost # FalkorDB (default: localhost:6379)llm = OpenAILLM(model="gpt-4o-mini", timeout=300.0)uv run pytest tests/ -v
uv run ruff check src/ # LintingPull requests welcome! Please:
- Run
uv run ruff check src/ --fixbefore committing - Add tests for new features
- Update docs if behavior changes
MIT — see LICENSE
- 📖 Detailed Usage Guide
- 🏗️ Architecture
- 🚀 Publishing to PyPI
- 📝 Research Paper
- Scheduler — processes READY nodes concurrently; fan-out via
asyncio.gather, fan-in via REQUIRES edges - LLM — abstract provider interface (OpenAI, LiteRT-LM, etc.)
- @tool — auto-generates OpenAI-compatible schema from type hints + docstrings
- Session — multi-turn conversation with per-turn graph traceability
- FalkorDB — native graph persistence with built-in browser UI
from agentic_graphs import FalkorDBBackend, Graph, Node, NT
backend = FalkorDBBackend(graph_name="my_agent")
# Push
backend.sync(my_graph)
# Pull
restored = backend.load("my_agent")
# Query
result = backend.query("MATCH (n:GOAL) RETURN n.label, n.state")
for row in result.result_set:
print(row)
# Auto-sync every mutation
from agentic_graphs import set_sync_hook
set_sync_hook(lambda g: backend.sync(g))src/agentic_graphs/
├── __init__.py # Public API
├── log.py # Coloured logging
├── core/
│ ├── graph.py # Graph, Node, Edge, algorithms
│ ├── tool.py # @tool decorator
│ └── falkordb_backend.py # FalkorDB persistence
├── llm/
│ ├── base.py # Abstract LLM interface
│ └── openai.py # OpenAI provider
├── agent/
│ ├── base.py # Agent base class (history_messages support)
│ ├── defaults.py # Default prompts, guides, mutation tools
│ └── scheduler.py # Run loop with retry + concurrency
├── session/
│ ├── models.py # Thread, Turn, TurnStatus, SessionConfig
│ ├── store.py # ThreadStore — FalkorDB-backed persistence
│ └── session.py # Session — multi-turn chat with graph traceability
└── examples/
├── math_agent.py # Math solver with @tool tools
├── multi_agent.py # Coordinator + parallel sub-agents
├── research_agent.py # Single research agent (fixed)
├── chat_session.py # Multi-turn session demo (new)
└── debug_session.py # Session debugger (new)