Graph Engineering: The Missing Architecture for AI Agents

If you’ve built an AI agent recently, there’s a good chance you’ve accidentally built a graph.
You may not have called it that.
Maybe your code looks something like this:
const research = await researchTopic(topic);
const draft = await writeDraft(research);
const review = await reviewDraft(draft);
const final = await improveDraft(draft, review);
At first, this feels perfectly reasonable.
Research the topic.
Write something.
Review it.
Improve it.
Done.
But there’s a problem hiding in that innocent-looking sequence:
everything is waiting for everything else.
And that becomes increasingly expensive, slow, and fragile as your agents become more capable.
The interesting thing about modern AI systems isn’t just that we can give an LLM more tools.
It’s that we can start designing the work itself.
And that is where graph engineering comes in.
The problem with the straight line
The simplest AI workflow looks like this:
A → B → C → D
A has to finish before B starts.
B has to finish before C starts.
C has to finish before D starts.
This is completely fine when those dependencies are real.
The problem is that we often create dependencies that don’t actually exist.
Imagine an agent tasked with producing a report about three competitors.
A naïve implementation might look like:
Research Competitor A
↓
Research Competitor B
↓
Research Competitor C
↓
Write Report
But ask yourself:
Does researching Competitor B actually depend on finishing the research for Competitor A?
Usually, no.
They’re independent pieces of work.
So why are we forcing them to happen sequentially?
A better architecture is:
┌─ Competitor A ─┐
│ │
Question ────────┼─ Competitor B ─┼──→ Write Report
│ │
└─ Competitor C ─┘
Now the three research tasks can happen at the same time.
This is the first important idea in graph engineering:
Don’t create dependencies that don’t exist.
A graph is just your workflow made explicit
The word “graph” can make this sound much more complicated than it is.
At its simplest, a graph has two things:
Nodes
A node represents a piece of work.
For example:
Research a company
Search for documentation
Extract information
Write a draft
Check a claim
Review code
Generate a summary
A node doesn’t necessarily mean “an AI agent”.
It could be a function.
An API call.
A database query.
A human approval.
Another model.
Or an entire sub-workflow.
Edges
An edge represents a relationship between pieces of work.
In the simplest case, it means:
“B needs something produced by A.”
So:
Research → Write
means the writing step depends on the research.
Once you start thinking this way, an AI workflow stops looking like a pile of prompts and starts looking much more like software architecture.
And that’s the interesting shift.
You’ve already been using graphs
Software engineers shouldn’t find this concept particularly exotic.
We have been using graphs for a long time.
A build system has dependencies.
A package manager has dependencies.
A CI pipeline has dependencies.
A database query has dependencies.
A distributed system has services communicating with other services.
Even something as simple as JavaScript promises can express a graph.
Compare:
await researchA();
await researchB();
await researchC();
with:
await Promise.all([
researchA(),
researchB(),
researchC(),
]);
The second version doesn’t make the individual operations smarter.
It changes the dependency structure.
The work that was unnecessarily sequential is now concurrent.
AI agents introduce a similar problem, except the cost of getting the architecture wrong can be much higher.
Instead of wasting a few milliseconds, you might waste:
seconds or minutes of latency
thousands of tokens
expensive model calls
context window
tool calls
and potentially the reliability of the entire workflow
The fake edge
This is one of the most useful questions you can ask when designing an agent system:
Does this step actually depend on the previous step?
Call it the fake edge test.
Suppose you have:
Search → Summarise → Fact Check
Perhaps that is correct.
The summariser needs the search results.
The fact checker needs the summary.
But now consider:
Search A → Search B → Search C → Summarise
Maybe that’s not actually a chain.
It might really be:
Search A ─┐
Search B ─┼──→ Summarise
Search C ─┘
The arrows in the first diagram aren’t representing real dependencies.
They’re just representing the order in which the programmer happened to write the code.
That’s a dangerous distinction.
Execution order and dependency order are not the same thing.
Good graph engineering is largely about discovering the difference.
Parallelism is only the beginning
It’s tempting to think that graphs are mainly about making AI systems faster.
That’s certainly part of it.
But parallelism is actually the easy part.
The more interesting property is that a graph allows different pieces of work to have different responsibilities.
Consider an AI coding system.
A simple agent might do this:
Write Code
↓
Run Tests
↓
Fix Code
↓
Done
A graph can introduce independent perspectives:
┌─ Security Review ──┐
│ │
Write Code ──────┼─ Test Suite ───────┼──→ Fix
│ │
└─ Code Review ──────┘
Now the system isn’t just executing instructions.
It’s creating a small system of checks and balances.
One component writes.
Another tests.
Another looks for security problems.
Another reviews the design.
The output from those processes can then influence the next step.
This is where graphs become much more interesting than simple chains.
The diamond pattern
One pattern appears again and again in useful agent systems.
It’s the diamond:
┌─ Agent A ─┐
│ │
Input ───────┼─ Agent B ─┼──→ Verify ─→ Synthesise
│ │
└─ Agent C ─┘
You start with one problem.
You split it into independent pieces.
Those pieces are worked on in parallel.
Then you bring the results back together.
This pattern is powerful because it separates two fundamentally different problems:
exploration and synthesis.
The workers explore.
The final node makes sense of what they found.
You can use the same structure for:
researching a market
analysing a codebase
comparing products
reviewing documents
investigating an incident
generating a report
analysing customer feedback
evaluating multiple solutions
The specific agents change.
The architecture doesn’t.
Give agents different jobs
There’s another mistake I see frequently in agentic systems.
We create several agents but give them essentially the same job.
For example:
Agent 1: "Review this answer."
Agent 2: "Review this answer."
Agent 3: "Review this answer."
That isn’t necessarily useful redundancy.
If all three agents approach the problem in exactly the same way, they may simply reproduce the same mistake.
A better graph gives each node a different responsibility.
For example:
┌─ Factual accuracy
│
Draft ────────┼─ Completeness
│
├─ Contradictions
│
└─ Style
Now each reviewer is looking for something different.
This is an important principle:
Independence is more valuable than duplication.
Verification should be a first-class node
One of the most useful things you can do with a graph is make verification explicit.
Instead of:
Research → Write → Done
you can build:
Research → Write → Verify → Final
Or, even better:
┌──────────────→ Verify ──────┐
│ ↓
Research ───────────────→ Write ─────→ Final
The exact structure depends on the problem.
But the important idea is that verification is part of the architecture rather than an afterthought.
This changes how you think about reliability.
Instead of asking:
“How do I make my agent never make mistakes?”
you start asking:
“What should happen when this agent makes a mistake?”
That’s a much more realistic engineering question.
Errors shouldn’t automatically kill the workflow
A straight-line workflow tends to behave like this:
A → B → C → D
If B fails, C never happens.
But sometimes that’s the wrong behaviour.
Suppose three independent research agents are investigating a question:
A ─┐
B ─┼──→ Synthesis
C ─┘
If B fails, perhaps A and C still provide useful information.
The graph can decide what to do.
Maybe:
A ───────────┐
│
B ──→ Retry ─┤
├──→ Synthesis
C ───────────┘
Or perhaps B’s failure is itself useful information:
A ───────────┐
│
B ──→ Failed ├──→ Synthesis
│
C ───────────┘
This is a subtle but important change in mindset.
Failure becomes data.
The system can decide how to respond to it instead of blindly propagating it.
But graphs aren’t magic
There’s a temptation in AI engineering to assume that adding more agents automatically makes a system better.
It doesn’t.
A graph can make a bad system more complicated.
Imagine this:
Agent
↓
Agent
↓
Agent
↓
Agent
↓
Agent
You’ve now created five opportunities for failure instead of one.
And if every agent receives a huge context window, your costs can explode.
Graphs introduce their own problems:
Context explosion
Every node potentially produces information that another node needs to consume.
If you’re not careful, the graph becomes a giant context-passing machine.
Shared state
Two nodes may appear independent but actually depend on the same mutable resource.
That hidden dependency can create race conditions and inconsistent results.
Error propagation
Parallelism doesn’t automatically provide reliability.
If three agents independently make the same wrong assumption, your graph may simply produce three copies of the same mistake.
Orchestration complexity
At some point, the graph itself becomes difficult to understand.
That’s a signal.
If you need a 40-node workflow to accomplish something a single agent can reliably do, you’ve probably over-engineered it.
Not everything needs a graph
This is probably the most important warning.
Don’t use a graph because graphs are interesting.
If the workflow is genuinely sequential:
A → B → C
then keep it sequential.
If a single agent can solve the problem reliably, use a single agent.
If a simple loop works, use a loop.
The goal isn’t to maximise the number of nodes.
The goal is to create the simplest architecture that gives you the behaviour you need.
A graph becomes particularly useful when you have one or more of these:
independent work that can run concurrently
multiple specialised agents
verification or critique
retries or recovery paths
branching decisions
human approval
long-running workflows
different sources of evidence
failure isolation
complex dependencies
If none of those exist, you may not need one.
How to design your first agent graph
You don’t need an agent framework to start thinking this way.
Take an existing workflow and write down every meaningful piece of work.
For example, imagine you’re building an agent that researches a company.
Start with:
Research company
Write report
Then decompose the research:
Company
↓
Research ──→ Products
│
├───────→ Competitors
│
├───────→ Financials
│
└───────→ Recent news
Now ask:
Which of these actually depend on each other?
Probably very few.
So:
Products ────────┐
Competitors ─────┤
Financials ──────┼──→ Verify → Synthesise
Recent news ─────┘
That’s already a graph.
Then ask another question:
What could go wrong?
Perhaps financial information needs additional verification.
So:
Financials → Financial Verification
Maybe the final report should only be produced once enough evidence exists.
Now you’ve introduced another dependency.
This is how a graph should emerge:
from the requirements of the system, not from a desire to use a graph.
Think in contracts, not just prompts
One of the biggest changes I’d recommend when building more sophisticated graphs is to stop thinking about nodes as “prompts”.
Think about them as software components with contracts.
Instead of:
“Research this company.”
Think:
Input:
companyName
Output:
{
claims: [...],
sources: [...],
confidence: ...
}
Now the next node knows exactly what it is receiving.
This makes the graph easier to reason about.
It also makes failures easier to diagnose.
If the synthesis node produces a bad result, you can inspect the output from each upstream node.
That’s much closer to debugging normal software.
And that’s where I think the most interesting future of agent engineering is heading.
AI agents are becoming distributed systems
The more capable our agents become, the less useful it is to think of them as isolated chatbots.
A serious agent system may have:
multiple models
multiple tools
external APIs
databases
queues
persistent state
retries
verification
human approval
scheduled work
parallel execution
At that point, you’re not really building “a prompt”.
You’re building a distributed system where some of the workers happen to be language models.
That means many of the lessons from traditional software engineering become relevant again:
dependencies matter.
interfaces matter.
failure modes matter.
observability matters.
timeouts matter.
retries matter.
contracts matter.
architecture matters.
The fact that one of your components happens to be an LLM doesn’t make those principles disappear.
The real shift
I think the most useful way to think about graph engineering is this:
We’re moving from agent prompting to agent architecture.
The early generation of AI applications focused heavily on:
“What prompt should I give the model?”
The next generation increasingly asks:
“What should the system do when the model is wrong?”
And then:
“Which work should happen independently?”
And:
“Which outputs should be trusted?”
And:
“Who checks the checker?”
And:
“What happens when a node fails?”
Those are architecture questions.
Not prompt questions.
The graph is not the product
There’s one final distinction worth making.
A graph itself isn’t valuable.
A graph is simply a way of expressing the architecture of a system.
The value comes from what that architecture allows you to achieve:
faster execution
better verification
clearer failure handling
independent reasoning
better observability
more reliable automation
The best graph is usually the one you barely notice.
It’s just the structure that makes the system behave correctly.
Start with the dependencies
If you take one thing away from this article, make it this:
Don’t ask what agents you need. Ask what work needs to happen, and what each piece of work actually depends on.
Start with the simplest workflow.
Draw the nodes.
Draw the edges.
Then challenge every edge.
Does this dependency really exist?
If it doesn’t, remove it.
If two things can happen independently, run them independently.
If something needs verification, make verification explicit.
If something can fail, design the recovery path.
And if none of that is necessary?
Don’t build a graph.
Build the simple thing.
That’s good engineering too.
Final thought
AI agents are often described as if they’re a completely new category of software.
In some ways, they are.
But the problems we encounter when combining them aren’t entirely new.
We’re still dealing with dependencies.
We’re still dealing with concurrency.
We’re still dealing with failures.
We’re still dealing with systems that need to communicate with one another.
The difference is that some of our workers can now reason, use tools, and operate on tasks that previously required a human.
That makes the architecture more important, not less.
The future of AI engineering probably isn’t one incredibly capable agent doing everything.
It’s systems of specialised workers that know what they need, what they can do independently, when to ask for help, and how to recover when something goes wrong.
And those systems look a lot like graphs.
