ADR 0004 — Multi-agent workflows: native engine first, LangGraph as a backend¶
Status¶
Accepted (2026-06).
Context¶
The platform needs n8n/Flowise-style multi-agent orchestration: users compose a DAG of agents ("AI employees") on a canvas, run it, and watch data flow along edges. The community standard for graph-based agent orchestration is LangGraph; LangChain is the broader ecosystem around it. Both resolve and install on our Python 3.14 toolchain (langgraph 1.2.x, langchain-core 1.4.x).
Two architectural options:
- Build the workflow engine on LangGraph exclusively.
- Build a small, deterministic native engine and also compile the same
workflow spec to a LangGraph
StateGraphas a selectable backend.
Decision¶
Option 2. aop.orchestrator.workflow defines the WorkflowSpec contract
(nodes/edges/templates), validation (unique ids, known agents, acyclic), and a
WorkflowEngine with two real backends:
- native (default): level-parallel topological execution on asyncio. ~150 lines, zero dependencies, fail-fast semantics we fully control.
- langgraph: the same spec compiled to a
StateGraph(fan-in nodes usedefer=Trueso joins run exactly once). Selected per run (enginefield) or globally (AOP_WORKFLOW_ENGINE=langgraph).
aop.llm.langchain_bridge.build_chat_model() additionally exposes any AOP
provider (Ollama, OpenRouter, fine-tuned registry models, …) as a
langchain-core BaseChatModel, so LangChain/LangGraph tooling can drive our
unified adapter stack directly.
Consequences¶
- The product works fully without the optional
orchestrationextra; with it, users get LangGraph execution and LangChain interop with the same specs. - Both backends share node execution (template render → agent run → event publish), so behaviour and event streams are identical from the UI's view.
- The deliberate cost: two execution paths to keep in parity. The shared
_run_nodekeeps the divergence to graph traversal only.