Most multi-agent framework comparisons focus on feature checklists: which supports streaming, structured output, retries, observability hooks, or MCP integration. That grid conceals the architectural choice that determines whether you will be productive six months in: who decides the topology.
Graph-first frameworks make you decide at design time. Goal-first frameworks delegate that decision to a coordinator agent at runtime. Each approach pays the decomposition cost in a different currency. Graph-first pays in code. Goal-first pays in tokens and latency. The right default depends on what kind of work your team actually has.
The Central Design Choice
Every multi-agent framework must answer: how do agents know what to do next?
Graph-based orchestration (LangGraph, Mastra, Flowise) requires you to define an explicit control flow graph. You write nodes, edges, conditional branches, and state transitions. The framework executes the graph you declared. If the task changes, you change the graph.
Goal-driven orchestration (open-multi-agent, CrewAI-style patterns) gives agents a goal and lets a coordinator agent decide which agents to invoke, in what order, with what context. The framework infers the execution plan at runtime. If the task changes, the coordinator adapts without code changes.
The difference is not cosmetic. It determines:
- Where state lives and how it propagates
- What debugging looks like
- How you handle failure recovery
- Whether TypeScript types help or hurt you
- What your observability surface looks like
Graph-Based Orchestration: Explicit Control Flow
In a graph-based framework, you define a state machine. Each node is a function or agent invocation. Each edge is a transition rule. The framework provides primitives for conditional routing, loops, and parallel execution.
State Management
State is explicit. You define a state schema (often with Zod or TypeScript interfaces). Each node reads from and writes to a shared state object. The framework handles state persistence and checkpointing.
import { StateGraph } from "@langchain/langgraph";
interface AgentState {
query: string;
researchResults?: string[];
draft?: string;
finalOutput?: string;
}
const workflow = new StateGraph<AgentState>({
channels: {
query: { value: (x, y) => y ?? x },
researchResults: { value: (x, y) => y ?? x },
draft: { value: (x, y) => y ?? x },
finalOutput: { value: (x, y) => y ?? x },
},
});
workflow.addNode("research", async (state) => {
const results = await researchAgent.run(state.query);
return { researchResults: results };
});
workflow.addNode("draft", async (state) => {
const draft = await writerAgent.run(state.researchResults);
return { draft };
});
workflow.addConditionalEdges(
"draft",
(state) => state.draft.length > 500 ? "finalize" : "research"
);
State transitions are deterministic. You can replay a graph execution by replaying the state sequence. Debugging is straightforward: inspect the state at each node.
Failure Modes
Failures are local. If a node throws, the framework can retry that node, skip it, or halt execution. You control the error boundary explicitly.
The graph does not adapt. If the task requires a step you did not anticipate, the graph fails or produces incorrect output. You must update the graph definition and redeploy.
TypeScript Integration
Graph-based frameworks benefit from TypeScript’s structural type system. State schemas are validated at compile time. Edge conditions are type-checked. The framework can infer node input/output types from the state schema.
This works well when the task is stable. It becomes friction when the task evolves faster than your deployment cycle.
Goal-Driven Orchestration: Implicit Coordination
In a goal-driven framework, you define agents with capabilities and a goal. A coordinator agent (often an LLM) decides which agents to invoke, in what order, based on the goal and intermediate results.
State Management
State is implicit. The coordinator maintains a conversation history or task context. Agents read from and write to this shared context. The framework does not enforce a schema.
import { Crew, Agent, Task } from "open-multi-agent";
const researcher = new Agent({
role: "Research Analyst",
goal: "Find relevant information",
tools: [webSearch, documentRetrieval],
});
const writer = new Agent({
role: "Technical Writer",
goal: "Synthesize findings into clear prose",
tools: [markdownFormatter],
});
const crew = new Crew({
agents: [researcher, writer],
tasks: [
new Task({
description: "Research TypeScript agent frameworks",
expectedOutput: "Summary of orchestration patterns",
}),
],
process: "sequential", // or "hierarchical"
});
const result = await crew.kickoff();
The coordinator decides: “I need research first, then writing.” If the research is insufficient, the coordinator might invoke the researcher again or switch to a different agent. The execution plan is not fixed.
Failure Modes
Failures are global. If the coordinator makes a bad decision (invokes the wrong agent, misinterprets intermediate results, loops indefinitely), the entire task fails. You cannot retry a single step because there is no explicit step boundary.
The coordinator adapts. If the task requires an unanticipated step, the coordinator can invoke an agent you did not expect. This is powerful when the task is exploratory. It is dangerous when the task has compliance or safety constraints.
TypeScript Integration
Goal-driven frameworks struggle with TypeScript. Agent capabilities are described in natural language, not type signatures. The coordinator’s decision logic is opaque. You cannot type-check the execution plan because it does not exist until runtime.
Some frameworks (open-multi-agent, for example) use Zod schemas for tool inputs and structured outputs, but the orchestration layer remains untyped. You get type safety within agents, not across them.
Debugging and Observability
| Dimension | Graph-Based | Goal-Driven |
|---|---|---|
| Replay | Deterministic. Replay state sequence. | Non-deterministic. Coordinator may choose differently. |
| Breakpoints | Set breakpoints at nodes. Inspect state. | No explicit breakpoints. Inspect conversation history. |
| Trace visualization | DAG with node execution times. | Linear conversation log with agent invocations. |
| Failure attribution | Node X failed at step Y. | Coordinator made bad decision at turn Z. |
| Observability hooks | Lifecycle hooks at node entry/exit. | Lifecycle hooks at agent invocation. |
| State inspection | Structured state object. | Unstructured conversation context. |
Graph-based frameworks give you a call stack. Goal-driven frameworks give you a conversation transcript. The former is easier to debug when you know what went wrong. The latter is easier to debug when you do not know what should have happened.
When to Use Each
Use Graph-Based Orchestration When:
- The task has a stable, well-understood structure
- You need deterministic execution for compliance or auditing
- Failure recovery requires retrying specific steps
- You want compile-time type safety across agent boundaries
- Your team is comfortable writing and maintaining state machines
- Latency is critical (no coordinator overhead)
Use Goal-Driven Orchestration When:
- The task structure is exploratory or changes frequently
- You want the system to adapt to new requirements without code changes
- You trust the coordinator to make reasonable decisions
- Your team prefers declarative agent definitions over imperative control flow
- You can tolerate higher latency (coordinator LLM calls)
- Observability focuses on conversation logs rather than execution traces
The Hybrid Middle Ground
Some frameworks (Mastra, for example) support both patterns. You can define an explicit graph for the high-level workflow and use goal-driven coordination within nodes. This gives you deterministic top-level control with adaptive sub-tasks.
The cost is complexity. You now have two orchestration models to reason about. Debugging requires understanding both the graph execution and the coordinator’s decisions.
Production Considerations
Token Costs
Goal-driven orchestration burns tokens on coordination. Every decision the coordinator makes is an LLM call. For long-running tasks with many agent invocations, this adds up.
Graph-based orchestration burns tokens only on agent work. The control flow is free (in token terms).
Latency
Goal-driven orchestration adds latency at every decision point. The coordinator must decide what to do next, which requires an LLM round-trip.
Graph-based orchestration has no coordination overhead. Latency is determined by agent execution time and network I/O.
Deployment Shape
Graph-based frameworks often compile to a serializable graph definition. You can deploy the graph as a static artifact, version it, and roll back.
Goal-driven frameworks deploy agent definitions and a coordinator prompt. The execution plan is not versioned because it does not exist until runtime. Rolling back requires changing the coordinator’s behavior, which is harder to test.
Security Boundaries
Graph-based frameworks enforce security at node boundaries. You can sandbox individual nodes, rate-limit specific agents, or require approval for certain transitions.
Goal-driven frameworks enforce security at agent boundaries. The coordinator decides which agents to invoke, so you must trust the coordinator or constrain its decision space (which undermines the adaptive benefit).
Technical Verdict
Choose graph-based orchestration if you are building a production system with well-defined workflows, compliance requirements, or tight latency budgets. The upfront cost of defining the graph pays off in debuggability, determinism, and operational simplicity.
Choose goal-driven orchestration if you are prototyping, building internal tools, or working in domains where task structure changes faster than your deployment cycle. The runtime cost of coordination buys you adaptability and faster iteration.
Avoid goal-driven orchestration if you need deterministic execution, fine-grained failure recovery, or low-latency responses. The coordinator’s opacity and non-determinism will hurt you in production.
Avoid graph-based orchestration if your task structure is exploratory or changes weekly. The cost of updating and redeploying graphs will slow you down more than the coordinator’s token cost.
The feature checklist matters, but the orchestration model matters more. Pick the model that matches your decomposition budget.