August 4, 2026
Graph Engineering for AI Agents: The Practitioner’s Guide to Designing Multi-Agent Systems as…
From chatbots to loops to graphs: how to architect, govern, and pay for multi-agent AI, explained through a working invoice dispute…

By Adnan Masood, PhD.
25 min read
From chatbots to loops to graphs: how to architect, govern, and pay for multi-agent AI, explained through a working invoice dispute resolution system
tl:dr; Graph engineering represents an architectural shift in AI development, moving beyond single-agent loops toward structured multi-agent organizations. By organizing AI tasks as nodes and edges in a governed topology, developers can separate logical judgment from deterministic computation to ensure reliability and financial accuracy. This methodology addresses common failures like context saturation and unbounded delegation by implementing typed handoff contracts and hardcoded policy routers. Using an invoice dispute system as a primary example, the post illustrates how specialized nodes — including agentic, deterministic, and human checkpoints — drastically reduce costs while improving performance. Ultimately, this approach transforms AI governance from a suggestion within a prompt into a provable property of the system's structure. This transition ensures that complex enterprise workflows remain transparent, auditable, and economically viable.
Your AI agent handles the easy cases beautifully and fails exactly when the stakes rise. That pattern is now so common in production that it has forced an architectural rethink: stop scaling the single agent and start engineering the organization around it. This is graph engineering, the emerging discipline of designing multi-agent systems as governed topologies, where agents, deterministic code, policy routers, and human checkpoints become nodes in an explicit graph, and where governance becomes a provable property of structure instead of a hopeful sentence in a prompt.
This post walks the full progression from chatbots to loops to graphs, then makes it concrete: a working invoice dispute resolution system built on LangGraph and Claude, refactored from a failing single agent into a seven-node graph that is 84 percent cheaper, three times faster, and, on the cases that matter, right.
Lets dive in.
1. The Problem: Your Agent Works Until It Matters
Let's start with a system that every enterprise recognizes. A customer emails to dispute an invoice. They believe they were overcharged on three line items, they cite their contract, and they want a credit. Someone in your organization now has to classify the complaint, pull the contract and the order history, recompute what the invoice should have been, decide whether the customer is right, draft a response, and, if a credit is due, move money.
In 2024 you would have built a chatbot to deflect the email. In 2025 you would have built an agent to handle it. An agent, in the sense the industry now uses the word, is a large language model wrapped in a loop: the model reads the task, decides on an action, calls a tool (a function the model can invoke, such as a database query or an API call), observes the result, and repeats until it declares the task done.
So you build one. You give a strong model five tools: search disputes, fetch contract, fetch orders, calculate credit, send response. You write a careful system prompt. And on easy disputes, it works. It is honestly a little magical.
Then a hard case arrives. A dispute spans fourteen line items across two contract amendments with a mid-term price change. Your agent pulls the contract, pulls the orders, and begins reasoning about arithmetic inside its own context window (the working memory of text the model can see at once). Somewhere around step nine, it transposes two numbers. It then confidently issues a credit for $4,180 when the correct figure was $1,480. Nothing crashed. No error was thrown. The system simply reasoned its way to being wrong about money, and there is no audit trail that explains why, because the "decision" is smeared across forty tool calls in one long transcript.
This is the problem statement of this article. The single-agent loop, the workhorse of 2025, has a ceiling, and production systems are hitting it. Three failure modes recur:
Context saturation. Everything the agent has seen accumulates in one context window. By the time it makes the decision that matters, the relevant facts are buried under retrieval debris, and model attention degrades.
Unbounded delegation. The agent can call any of its tools in any order, any number of times. There is no structural guarantee that money movement passes through a policy check, because "structure" exists only as a suggestion in the prompt, and prompts are requests rather than constraints.
Behavior entangled with structure. How the agent reasons (its behavior) and how the overall task is organized (its structure) live in the same place: one prompt, one loop. You cannot version them separately, test them separately, or hand them to different owners.
The discipline emerging in response to this ceiling is called graph engineering: designing the multi-agent system itself as an engineered graph, where you specify which nodes exist, which transitions between them are permitted, and how runtime task structures form [1], [2]. This article explains what that means, where it came from, why it matters, and then builds a real one, in real code, around the invoice dispute system described above.
One honesty note before we begin. The term is weeks old as of this writing, its provenance is contested, and it collides with an older usage from the knowledge-graph world [2]. The name may or may not survive. The engineering problems underneath it are durable, and they are the actual subject of this article.
2. How We Got Here: Chatbots, Agents, Loops, Graphs
The fastest way to understand graph engineering is to walk the industry's progression, because each stage exists to fix the failure mode of the stage before it.
Stage one: chat (2022 to 2023). A model answers a message. The unit of work is a single completion: text in, text out. The engineering discipline of this era was prompt engineering, the craft of phrasing instructions so the model produces what you want. Its limitation was obvious: the model could talk about work, and could not do work.
Stage two: tools and RAG (2023 to 2024). Two additions changed that. Tool use (also called function calling) let the model emit structured requests that your code executes, so the model could act on the world. Retrieval-augmented generation, or RAG, let the model pull relevant documents into its context before answering, so it could ground itself in your data instead of its training memory. The engineering discipline matured into context engineering: deciding what information a model call sees, in what form, at what length. The limitation: each call was still a single shot. Multi-step problems needed a human to drive.
Stage three: agents and loop engineering (2024 to mid-2026). The ReAct pattern [9] closed the loop: let the model reason, act, observe the result, and reason again, autonomously, until done. The industry spent two years learning to engineer this loop well, and a real discipline formed around it, sometimes explicitly named loop engineering [1]: designing the iteration cycle of a single agent. What does it retry? When does it stop? How does it self-check? How does its context get compacted as the loop runs long? Anthropic's guidance on building effective agents captured the era's hard-won consensus: simple, well-instrumented loops beat clever architectures for most tasks [10].
Loop engineering was, and remains, genuinely valuable. But everything in stage three happens inside one agent, and the three failure modes from Section 1 are all consequences of that "one."
Stage four: graph engineering (mid-2026 onward). The response to the ceiling is to stop scaling the agent and start structuring the organization. Instead of one loop with many tools, you build many specialized nodes with explicit wiring between them. The formulation that has stuck in the current discourse is compact: loops made agent behavior programmable; graphs make agent organizations programmable [1].
The progression, as a table:
+---------+------------------+----------------------+---------------------------+
| Era | Unit of work | Discipline | Ceiling it hit |
+---------+------------------+----------------------+---------------------------+
| 2022-23 | One completion | Prompt engineering | Can talk, cannot act |
| 2023-24 | Grounded call | Context engineering | One shot, human drives |
| 2024-26 | One agent loop | Loop engineering | Saturation, no governance |
| 2026- | Agent org graph | Graph engineering | (open; see Section 10) |
+---------+------------------+----------------------+---------------------------++---------+------------------+----------------------+---------------------------+
| Era | Unit of work | Discipline | Ceiling it hit |
+---------+------------------+----------------------+---------------------------+
| 2022-23 | One completion | Prompt engineering | Can talk, cannot act |
| 2023-24 | Grounded call | Context engineering | One shot, human drives |
| 2024-26 | One agent loop | Loop engineering | Saturation, no governance |
| 2026- | Agent org graph | Graph engineering | (open; see Section 10) |
+---------+------------------+----------------------+---------------------------+Notice what the progression preserves. Graph engineering does not replace the earlier layers. Every node in a graph still needs good context engineering. Every agent node still needs a well-engineered loop. The layers stack, and the new one sits on top [1], [4].
3. What Graph Engineering Actually Is
Now the definitions, precisely, because the rest of the article depends on them.
A graph, in the computer science sense, is a set of nodes connected by edges. Nothing exotic: boxes and arrows, formalized.
Graph engineering is the practice of designing a multi-agent system's topology (its shape): which nodes exist, which transitions between nodes are permitted, and how runtime task structures form and change [2]. It answers structural questions. Who does what? Who may hand off to whom? Where do humans sit? What can never happen?
Two graphs matter, and confusing them causes most of the muddled writing on this topic:
The org graph is the standing structure of the system: the defined roles, their tools, their permitted relationships. It is analogous to an org chart plus a set of standard operating procedures. You design it, review it, and version it like code, because it is code.
The work graph is the ephemeral structure created for one specific task at runtime: this dispute, decomposed into these steps, some parallel, some sequential. Work graphs are instances; the org graph is the class. You log work graphs like traces [1].
Four kinds of nodes populate these graphs [2]:
An agent node is an LLM with a role, tools, and its own loop. It handles judgment.
A deterministic node is plain code: same input, same output, every time. It handles everything that has a right answer.
A router node is a conditional branch: it inspects the state and chooses the next edge. It handles policy.
A human checkpoint is a node where the graph stops and waits for a person. It handles accountability.
And three disambiguations, because the term "graph" is doing heavy lifting in three different neighborhoods of AI right now:
This is not knowledge graph engineering. A knowledge graph structures data as entities and relationships (Acme Corp, is-customer-of, YourCo). GraphRAG, a retrieval technique that walks such graphs to answer multi-hop questions, structures data too [5]. Graph engineering, in the sense of this article, structures the agent organization. One system can use both: agents wired in an org graph, retrieving over a knowledge graph. Same word, different layer, and the collision is a known problem with the name [2].
This is not classic workflow orchestration. Tools like Airflow execute predetermined, static graphs of deterministic steps. Graph engineering deals with graphs that contain non-deterministic nodes (agents), that are sometimes generated at runtime by a planner, and whose central engineering problem is constraining what graphs may come into existence at all.
This is not just owning LangGraph. Frameworks such as LangGraph [6], CrewAI, and AutoGen are substrates: they give you the primitives to build graphs. Graph engineering is the design discipline exercised on top of them, the same way owning Terraform does not mean you have good infrastructure architecture. This article uses LangGraph because it is the current de facto substrate, and every design decision in it transfers to any other.
4. Why Bother: The Benefits, Stated Plainly
Before the code, the payoff. Graph engineering earns its complexity in four ways.
Reliability through specialization. Small, focused nodes with clean inputs outperform one saturated generalist. Each agent node sees only the context its role requires, which is context engineering made structural.
Governance through topology. In a single-agent system, "the agent must get approval before issuing credits over $500" is a sentence in a prompt, and the model can ignore sentences. In a graph, it is an edge that does not exist. You can prove, by inspecting the edge set, that no path reaches money movement without passing a policy check. Governance stops being a hope and becomes a property of the structure, which is the difference an auditor cares about.
Economics through substitution. Every node is a placement decision: model or code? Every LLM call you replace with a deterministic function is a call that costs nothing, takes milliseconds, and cannot hallucinate. Topology is the biggest FinOps lever in agentic systems, a point Section 9 quantifies.
Ownership through separation. Structure and behavior finally live in different places. A platform team can own the org graph; domain teams can own individual agent nodes; risk can own the router policies. You can change a prompt without touching the topology and change the topology without touching a prompt.
There is also an honest cost side, and skipping it would be malpractice: a graph multiplies moving parts, and a premature graph multiplies failure modes and token spend without adding capability. Section 8 gives the criteria for when a single well-engineered loop remains the right answer, which is more often than the current hype suggests.
5. The Running Example, Version 0: One Agent, Five Tools
Everything from here on is concrete. The stack is real and boring on purpose: Python 3.12, LangGraph as the graph substrate [6], Claude as the model behind agent nodes, Pydantic v2 for typed data contracts [7], SQLite for orders and contracts so the repository clones and runs anywhere, and Arize Phoenix over OpenTelemetry for tracing [8]. One API key, roughly 700 lines, runs on a laptop.
Version 0 is the system most teams build first, and it is a single ReAct-style agent:
# v0_single_agent.py
from langchain_anthropic import ChatAnthropic
from langgraph.prebuilt import create_react_agent
from tools import (
search_disputes, # find the dispute record
fetch_contract, # pull contract terms and amendments
fetch_orders, # pull order and invoice history
calculate_credit, # a calculator tool the model MAY choose to call
send_resolution, # email the customer and post the credit memo
)
SYSTEM = """You are a dispute resolution specialist. Investigate the
customer's claim against their contract and order history. Recompute
the correct invoice amounts. If the customer is owed money, issue a
credit and send a resolution. Be accurate. Get human approval for
credits over $500."""
agent = create_react_agent(
model=ChatAnthropic(model="claude-sonnet-4-6"),
tools=[search_disputes, fetch_contract, fetch_orders,
calculate_credit, send_resolution],
prompt=SYSTEM,
)
result = agent.invoke({"messages": [("user", dispute_email)]})# v0_single_agent.py
from langchain_anthropic import ChatAnthropic
from langgraph.prebuilt import create_react_agent
from tools import (
search_disputes, # find the dispute record
fetch_contract, # pull contract terms and amendments
fetch_orders, # pull order and invoice history
calculate_credit, # a calculator tool the model MAY choose to call
send_resolution, # email the customer and post the credit memo
)
SYSTEM = """You are a dispute resolution specialist. Investigate the
customer's claim against their contract and order history. Recompute
the correct invoice amounts. If the customer is owed money, issue a
credit and send a resolution. Be accurate. Get human approval for
credits over $500."""
agent = create_react_agent(
model=ChatAnthropic(model="claude-sonnet-4-6"),
tools=[search_disputes, fetch_contract, fetch_orders,
calculate_credit, send_resolution],
prompt=SYSTEM,
)
result = agent.invoke({"messages": [("user", dispute_email)]})Run this on fifty synthetic disputes and the results split cleanly. Simple disputes (one line item, no amendments): about 90 percent correct, and the transcripts read like competent work. Hard disputes (multiple amendments, mid-term price changes, partial shipments): correctness collapses, and the failures are exactly the three from Section 1, now observable.
The agent sometimes does arithmetic in its head instead of calling the calculator, because tool use is the model's choice, and models are confident. Its context saturates: by tool call thirty, the contract clause that matters is thousands of tokens behind it. And that "human approval over $500" line? In our runs the agent respected it most of the time. "Most of the time" is a phrase that ends careers in financial services.
The instinct at this point is to write a longer prompt. The graph engineering move is different: stop instructing one agent to be an organization, and build the organization.
6. Designing the Org Graph: Node Taxonomy in Practice
The refactor begins with one question asked about every responsibility in the workflow: does this step require judgment, or does it have a right answer? Judgment gets a model. Right answers get code. This single heuristic does more for reliability and cost than any prompt technique, and it produces the following seven-node org graph:
+--------------------+
email ----> | intake_classifier | (agent)
+---------+----------+
| DisputeCase
+---------v----------+
| evidence_retriever | (deterministic)
+---------+----------+
| EvidenceBundle
+---------v----------+
| recompute_engine | (deterministic)
+---------+----------+
| RecomputeResult
+---------v----------+
| resolution_drafter | (agent)
+---------+----------+
| ProposedResolution
+---------v----------+
| policy_router | (router)
+----+----------+----+
auto (<=$500, | | review (else)
high conf) | |
+--------v-+ +-v------------+
| executor |<-| human_review | approved
| (determ.)| | (checkpoint) |--+
+----------+ +--------------+ |
| rejected v
+-------> END+--------------------+
email ----> | intake_classifier | (agent)
+---------+----------+
| DisputeCase
+---------v----------+
| evidence_retriever | (deterministic)
+---------+----------+
| EvidenceBundle
+---------v----------+
| recompute_engine | (deterministic)
+---------+----------+
| RecomputeResult
+---------v----------+
| resolution_drafter | (agent)
+---------+----------+
| ProposedResolution
+---------v----------+
| policy_router | (router)
+----+----------+----+
auto (<=$500, | | review (else)
high conf) | |
+--------v-+ +-v------------+
| executor |<-| human_review | approved
| (determ.)| | (checkpoint) |--+
+----------+ +--------------+ |
| rejected v
+-------> ENDWalk the nodes and the reasoning behind each placement.
intake_classifier (agent). Reading a rambling customer email and extracting what is actually disputed requires judgment about messy natural language. Model. But its output is forced into a typed structure, DisputeCase, so everything downstream receives facts instead of prose.
evidence_retriever (deterministic). Given a customer ID and a date range, fetching the contract and orders is a database query. There is no judgment in a WHERE clause. In Version 0 this was an LLM deciding when and whether to retrieve; here it is forty lines of Python that always retrieves, completely, for free.
recompute_engine (deterministic). This is the demonstrative heart of the refactor. Recomputing an invoice from contract pricing, amendments, and shipment records is arithmetic. Arithmetic has a right answer. Putting a language model in charge of arithmetic on money is malpractice, full stop, and the fact that Version 0 did exactly that (whenever the model skipped its calculator tool) is the single largest source of its hard-case failures. Here it is pure Python with unit tests. It cannot hallucinate a credit because it cannot hallucinate anything.
resolution_drafter (agent). Deciding how to explain an outcome to an unhappy customer, choosing tone, acknowledging their specific frustration: judgment. Model. Note what this agent receives: a typed EvidenceBundle and a typed RecomputeResult, roughly 1,200 tokens of relevant facts. It never sees raw contracts, never sees the retrieval process, and never does math. Its numbers are copied from the recompute engine's output, and a validator checks that they match.
policy_router (router). The $500 threshold from the prompt becomes a Python conditional. This is policy as code: it cannot be persuaded, cannot have a bad day, and can be reviewed by your risk team in one glance.
human_review (checkpoint). For large or low-confidence credits, the graph stops. Actually stops: LangGraph's interrupt() primitive pauses execution, a checkpointer persists the entire graph state to disk, and the graph resumes hours later when a reviewer acts, in a different process if need be [6]. The human is a node in the topology, with defined inputs and outputs, instead of a wrapper bolted on around the system.
resolution_executor (deterministic). Writing the credit memo and sending the email is I/O. Code.
The agent nodes deserve one more comment, because "graph engineering" does not exempt you from engineering the agents themselves. Each agent node ships with a role definition, which reads more like a job description than a prompt [1]: the domain it owns (dispute intake), the tools it may touch (none, in the classifier's case; its only job is structured extraction), the context it is entitled to see, and the schema it must emit. Inside each agent node, all the loop engineering and context engineering craft of 2024 to 2026 still applies. The graph did not replace those disciplines. It contained them.
7. Edges: Handoff Contracts and the Serialization Tax
If nodes are where graph systems do their work, edges are where they fail. Ask anyone running multi-agent systems in production: the wreckage is at the handoffs [1].
The naive handoff, and the default in most framework demos, is transcript passing: agent A finishes, and its entire conversation history is prepended to agent B's context. This fails twice. It re-saturates every downstream context with upstream debris, recreating the exact disease the graph was meant to cure. And it costs real money, because every token crossing an edge is a token you pay to re-serialize into the next model call. Call it the serialization tax.
The graph engineering alternative is the handoff contract: a typed schema defining exactly what crosses each edge, with everything else dying at the boundary. In Python, Pydantic models [7]:
# contracts.py
from pydantic import BaseModel, Field
from decimal import Decimal
from typing import Literal
class DisputedItem(BaseModel):
line_item_id: str
claimed_reason: str
claimed_amount: Decimal
class DisputeCase(BaseModel):
"""Edge: intake_classifier -> evidence_retriever"""
customer_id: str
invoice_ids: list[str]
dispute_type: Literal["pricing", "quantity", "service"]
items: list[DisputedItem]
customer_sentiment: Literal["calm", "frustrated", "escalated"]
class RecomputeResult(BaseModel):
"""Edge: recompute_engine -> resolution_drafter"""
correct_total: Decimal
billed_total: Decimal
credit_due: Decimal
per_item_findings: list[dict] # itemized right/wrong per line
confidence: Literal["exact", "assumptions_made"]
assumptions: list[str] = Field(default_factory=list)
class ProposedResolution(BaseModel):
"""Edge: resolution_drafter -> policy_router"""
credit_amount: Decimal # validated == credit_due upstream
customer_message: str
internal_rationale: str# contracts.py
from pydantic import BaseModel, Field
from decimal import Decimal
from typing import Literal
class DisputedItem(BaseModel):
line_item_id: str
claimed_reason: str
claimed_amount: Decimal
class DisputeCase(BaseModel):
"""Edge: intake_classifier -> evidence_retriever"""
customer_id: str
invoice_ids: list[str]
dispute_type: Literal["pricing", "quantity", "service"]
items: list[DisputedItem]
customer_sentiment: Literal["calm", "frustrated", "escalated"]
class RecomputeResult(BaseModel):
"""Edge: recompute_engine -> resolution_drafter"""
correct_total: Decimal
billed_total: Decimal
credit_due: Decimal
per_item_findings: list[dict] # itemized right/wrong per line
confidence: Literal["exact", "assumptions_made"]
assumptions: list[str] = Field(default_factory=list)
class ProposedResolution(BaseModel):
"""Edge: resolution_drafter -> policy_router"""
credit_amount: Decimal # validated == credit_due upstream
customer_message: str
internal_rationale: strThree properties make contracts more than tidiness. They are enforceable: if the classifier emits garbage, validation fails at the edge, loudly, instead of poisoning three downstream nodes silently. They are testable: each node can be tested in isolation with fixture inputs, because its interface is a schema instead of "whatever the previous agent happened to say." And they are cheap: in our dispute system, the contract-based handoff into resolution_drafter carries about 1,200 tokens, versus roughly 9,000 for transcript passing at the same point in Version 0's flow, an 87 percent reduction on that edge alone. Section 9 totals the effect across the system.
The design question for every edge is always the same: what does the downstream node need to know to do its job, as opposed to what does the upstream node happen to know? Answering it well is context engineering promoted to an interface decision.
8. Wiring and Governance: Topology as Policy
Here is the complete wiring, and it is short enough to read whole, which is itself part of the argument:
# graph.py
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.sqlite import SqliteSaver
g = StateGraph(DisputeState)
g.add_node("intake", intake_classifier) # agent
g.add_node("evidence", evidence_retriever) # deterministic
g.add_node("recompute", recompute_engine) # deterministic
g.add_node("draft", resolution_drafter) # agent
g.add_node("human", human_review) # checkpoint (interrupt)
g.add_node("execute", resolution_executor) # deterministic
g.add_edge(START, "intake")
g.add_edge("intake", "evidence")
g.add_edge("evidence", "recompute")
g.add_edge("recompute", "draft")
g.add_conditional_edges("draft", policy_router,
{"auto": "execute", "review": "human"})
g.add_conditional_edges("human", apply_human_decision,
{"approved": "execute", "rejected": END})
g.add_edge("execute", END)
app = g.compile(checkpointer=SqliteSaver.from_conn_string("disputes.db"))# graph.py
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.sqlite import SqliteSaver
g = StateGraph(DisputeState)
g.add_node("intake", intake_classifier) # agent
g.add_node("evidence", evidence_retriever) # deterministic
g.add_node("recompute", recompute_engine) # deterministic
g.add_node("draft", resolution_drafter) # agent
g.add_node("human", human_review) # checkpoint (interrupt)
g.add_node("execute", resolution_executor) # deterministic
g.add_edge(START, "intake")
g.add_edge("intake", "evidence")
g.add_edge("evidence", "recompute")
g.add_edge("recompute", "draft")
g.add_conditional_edges("draft", policy_router,
{"auto": "execute", "review": "human"})
g.add_conditional_edges("human", apply_human_decision,
{"approved": "execute", "rejected": END})
g.add_edge("execute", END)
app = g.compile(checkpointer=SqliteSaver.from_conn_string("disputes.db"))And the router, in full, because its brevity is the point:
# policy.py
AUTO_RESOLVE_LIMIT = Decimal("500.00")
def policy_router(state: DisputeState) -> str:
r = state["resolution"]
if (r.credit_amount <= AUTO_RESOLVE_LIMIT
and state["recompute"].confidence == "exact"):
return "auto"
return "review"# policy.py
AUTO_RESOLVE_LIMIT = Decimal("500.00")
def policy_router(state: DisputeState) -> str:
r = state["resolution"]
if (r.credit_amount <= AUTO_RESOLVE_LIMIT
and state["recompute"].confidence == "exact"):
return "auto"
return "review"Now the governance claim, stated carefully, because it is the strongest claim in this article.
Look at the edge set. There is no edge from draft to execute. The drafting agent, the one non-deterministic component anywhere near money, is structurally incapable of triggering money movement. Every path from START to execute passes through policy_router, and the router is fourteen lines of reviewable Python. In Version 0, the equivalent guarantee was a sentence in a prompt that the model honored "most of the time." Here it is a property of the graph, checkable by a script that walks the edges, demonstrable to an auditor in one diagram.
This is what "topology as governance" means, and it generalizes. The permitted-transition set is a policy artifact [2]. Approval thresholds live in routers. Accountability lives in human checkpoints with persisted state, which incidentally gives you a complete, replayable record of what the human saw and decided. Segregation of duties, the control your SOX auditor has been asking about, becomes literal graph structure: the node that proposes cannot be the node that executes. None of this required trusting a model. All of it required designing a graph.
9. Work Graphs, Observability, and the Economics of Topology
Three shorter topics complete the practitioner picture, and each one earns its own future deep dive.
Dynamic work graphs. Everything so far is a static topology: every dispute walks the same seven nodes. The frontier of graph engineering is the work graph generator: a planner node that examines an incoming task and constructs the runtime graph itself, deciding which nodes to spawn, in what order, and where parallelism is safe [1]. In the dispute system, the natural version is small: a planner that fans a fourteen-line-item dispute out into parallel per-item recomputations, then joins the results. LangGraph supports this via its Send API for dynamic fan-out [6]. The engineering discipline is in bounding the generator: maximum fan-out, cycle prevention, a per-task cost ceiling. An unbounded work graph generator is a machine for converting bugs into invoices, so treat the bounds as part of the design, never as an afterthought. And note the honest default: most systems, including this one, do fine with a static graph. Reach for dynamic generation when task structure genuinely varies, which is later than the demos imply.
Observability and evaluation. A graph you cannot see is a graph you cannot govern. Instrumenting the system with OpenTelemetry, viewed in Arize Phoenix [8], turns every run into a trace where each node reports its latency, token usage, and cost, and every edge shows its payload. Two practices matter. First, evaluate at two levels: node evals (does the classifier extract disputes correctly against a labeled set? does the recompute engine pass its unit tests?) and graph evals (does the whole topology produce the right end-to-end outcome on a maintained set of golden disputes, including handoff fidelity, the errors that only appear between nodes?). Second, regression-test the topology: when you rewire the graph, the golden set tells you whether the structure still works, independent of any prompt change. The open research problem, flagged honestly: evaluating dynamically generated work graphs, where the structure itself differs per run, has no settled methodology yet.
Token economics. Topology drives spend, and the dispute system quantifies it. Measured across our fifty-dispute test set:
+--------------------------------+-------------+-------------+
| Metric (avg per dispute) | V0 (loop) | V1 (graph) |
+--------------------------------+-------------+-------------+
| LLM calls | 23 | 4 |
| Total tokens (in + out) | ~61,000 | ~9,500 |
| Cost at Sonnet pricing | ~$0.31 | ~$0.05 |
| Hard-case correctness (n=20) | 55% | 95% |
| p50 latency | 94 s | 31 s |
+--------------------------------+-------------+-------------+
| V1 remaining errors: 1 misclassified intake, caught at |
| human_review. Zero incorrect credits reached execution. |
+--------------------------------+-------------+-------------++--------------------------------+-------------+-------------+
| Metric (avg per dispute) | V0 (loop) | V1 (graph) |
+--------------------------------+-------------+-------------+
| LLM calls | 23 | 4 |
| Total tokens (in + out) | ~61,000 | ~9,500 |
| Cost at Sonnet pricing | ~$0.31 | ~$0.05 |
| Hard-case correctness (n=20) | 55% | 95% |
| p50 latency | 94 s | 31 s |
+--------------------------------+-------------+-------------+
| V1 remaining errors: 1 misclassified intake, caught at |
| human_review. Zero incorrect credits reached execution. |
+--------------------------------+-------------+-------------+The mechanism behind the numbers is general, and it gives you the three FinOps levers of graph engineering: substitute (every deterministic node is an LLM call at zero dollars; retrieval and recomputation went from the costliest steps to free), compress at edges (typed contracts beat transcripts by 80-plus percent per handoff), and bound fan-out (parallelism multiplies spend linearly, so cap it in the generator). An 84 percent cost reduction alongside a 40-point accuracy gain on hard cases is the kind of sentence that sounds like vendor copy, which is why the repository publishing these numbers reruns them in CI.
10. The Operating Model, What Comes Next, and What to Build Now
Who owns the graph? The question sounds organizational because it is. Once topology is a governed artifact, someone must own it the way someone owns a production schema: versioned, reviewed, changed through pull requests. The pattern emerging in enterprises is a platform team owning the org graph and its routers, domain teams owning individual agent nodes (their role definitions, prompts, and node evals), and risk owning the policy thresholds, with the graph definition as the contract among all three. For forward-deployed engineers, the practitioners embedded with clients to make AI systems work in the field, the job description quietly shifts from "build the agent" to "design the topology," which is a more senior and more durable skill.
A simple maturity model for locating yourself:
+-------+---------------------------+-----------------------------------+
| Level | Shape | Governance |
+-------+---------------------------+-----------------------------------+
| 0 | Chat + RAG | None needed |
| 1 | One agent, tools, loop | Prompt-based (advisory) |
| 2 | Static org graph | Topology-based (structural) |
| 3 | + dynamic work graphs | + bounded generators |
| 4 | Governed agent org, many | Graph registry, org-wide policy, |
| | graphs, shared registry | cross-graph observability |
+-------+---------------------------+-----------------------------------++-------+---------------------------+-----------------------------------+
| Level | Shape | Governance |
+-------+---------------------------+-----------------------------------+
| 0 | Chat + RAG | None needed |
| 1 | One agent, tools, loop | Prompt-based (advisory) |
| 2 | Static org graph | Topology-based (structural) |
| 3 | + dynamic work graphs | + bounded generators |
| 4 | Governed agent org, many | Graph registry, org-wide policy, |
| | graphs, shared registry | cross-graph observability |
+-------+---------------------------+-----------------------------------+Most enterprises in mid-2026 are at Level 1 and hurting. This article is the Level 1 to Level 2 move. Level 4 is where the discourse is headed.
Where does this proceed next? Four trajectories seem likely from the current vantage point. First, standardization of the substrate: graph definitions will want a portable, declarative format the way infrastructure wanted Terraform, and protocols like MCP (Model Context Protocol, the emerging standard for connecting agents to tools) already hint at the interoperability layer. Second, graphs of graphs: once every department has an org graph, the edges between departments become the next engineering surface, and "the enterprise as a governed agent organization" stops being a metaphor. Third, learned topology: today humans design the graph and models fill the nodes; research on agent organization is already probing whether the structure itself can be optimized from outcomes, with the graph engineer setting constraints rather than drawing every edge [5]. Fourth, and least glamorous, regulation catching up: topology-as-governance produces exactly the artifacts (permitted-transition sets, checkpoint records, replayable state) that AI risk frameworks are starting to ask for, and the teams that can hand an auditor a graph will move faster than the teams that hand them a prompt.
Will the name stick? Unclear, and the honest sources say so [2]. "Graph engineering" may lose to some other label, or fragment back into orchestration vocabulary. Buy the problems, rent the terminology.
What to build this quarter, regardless. Take one workflow that matters, one where a wrong output costs money or trust. Build it as a static graph: separate judgment from computation, put typed contracts on the edges, put policy in a router, put a human at the checkpoint, and instrument every node. Measure cost and correctness against your current single-agent version. In our running example that exercise took roughly 700 lines and produced a system that is cheaper, faster, dramatically more accurate on hard cases, and, for the first time, provable.
The loop made your agent capable. The graph makes your system trustworthy.
That is the trade the industry is now making, whatever we end up calling it.
Frequently asked questions
1. What is graph engineering in one sentence? It is the discipline of designing a multi-agent AI system as an engineered graph: which nodes exist (agents, deterministic functions, routers, human checkpoints), which transitions are permitted, and how runtime task structures form. Loops made agent behavior programmable; graphs make agent organizations programmable.
2. How is it different from loop engineering? Loop engineering designs how a single agent iterates: retries, stopping conditions, self-checks, context compaction. Graph engineering designs the organization around agents: who does what, who may hand off to whom, where humans sit. They stack rather than compete; every agent node in a graph still needs a well-engineered loop inside it.
3. Is this just knowledge graphs or GraphRAG with a new name? No, and the name collision is the term's biggest liability. Knowledge graphs and GraphRAG structure data for retrieval. Graph engineering structures the agent organization. One system can use both: the dispute system's agents could retrieve over a knowledge graph of contracts while remaining wired in an org graph.
4. Isn't this what Airflow or Step Functions already do? Classic orchestrators execute predetermined, static graphs of deterministic steps. Graph engineering handles graphs containing non-deterministic nodes, sometimes generated at runtime by a planner, where the central problem is constraining which graphs may exist at all. The governance question ("prove no path reaches money movement without a policy check") has no analogue in a cron DAG.
5. If I use LangGraph, am I doing graph engineering? Owning the substrate isn't practicing the discipline, the same way owning Terraform isn't having good infrastructure architecture. Graph engineering is the design layer: node taxonomy decisions, handoff contracts, forbidden edges, checkpoint placement. The dispute system's most important line of "code" is an edge that doesn't exist.
6. What are org graphs and work graphs? The org graph is the standing structure: roles, tools, permitted relationships, versioned like code. The work graph is the ephemeral structure spawned for one task at runtime, logged like a trace. The dispute system's seven nodes are its org graph; one dispute flowing through them (or fanning out per line item) is a work graph.
7. When do I actually need a graph instead of one good agent? Later than the demos suggest. The honest triggers: a single agent's context saturates on hard cases, subtasks need different tool permissions or trust levels, regulators or auditors need provable constraints, or parallelism materially cuts cost or latency. A premature graph multiplies failure modes and token spend without adding capability.
8. How do I test and evaluate a graph? At two levels. Node evals verify each node in isolation (the classifier against labeled emails, the recompute engine against unit tests). Graph evals run golden cases end to end and catch handoff failures, the errors that only appear between nodes. The open problem is regression-testing dynamically generated work graphs, where structure differs per run.
9. Does this save money or cost more? Topology is the primary FinOps lever in agentic systems. Three moves: substitute deterministic nodes for LLM calls, compress context at edges with typed contracts instead of transcript passing, and bound fan-out. In the dispute system this cut LLM calls from 23 to 4 per case. Unbounded fan-out runs the arithmetic in reverse.
10. Will the term survive? Unsettled. It surfaced in mid-2026, its provenance is contested, and it collides with older graph vocabulary. The safe position: buy the problems, rent the terminology. Topology-as-governance, handoff contracts, and node taxonomy will matter under whatever name wins.
Glossary of Key Terms
Graph engineering — Designing a multi-agent system as an engineered graph: which nodes exist, which transitions are permitted, how runtime structures form. Example: the seven-node dispute system, where money movement is unreachable except through a policy check.
Loop engineering — Designing how a single agent iterates: retries, stopping conditions, self-checks, context compaction. Example: the intake classifier retrying once on a failed schema validation, then raising.
Agent — An LLM wrapped in a loop that reasons, calls tools, observes results, and repeats until done. Example: V0's single dispute agent with five tools.
Org graph — The standing structure of the system: roles, tools, permitted relationships. Versioned like code. Example: the fixed wiring in graph.py.
Work graph — The ephemeral structure created for one task at runtime. Logged like a trace. Example: one fourteen-line-item dispute fanned out into parallel per-item recomputes.
Agent node — A graph node backed by an LLM, owning a judgment task. Example: resolution_drafter, which adapts tone to an angry customer.
Deterministic node — A graph node that is plain code: same input, same output. Example: recompute_engine, which recalculates invoices in Decimal and cannot hallucinate.
Router node — A conditional branch that inspects state and picks the next edge. Policy as code. Example: policy_router, fourteen lines enforcing the $500 threshold.
Human checkpoint — A node where the graph pauses, persists state, and waits for a person. Example: human_review via LangGraph's interrupt(), resumable days later from the CLI.
Handoff contract — A typed schema defining exactly what crosses an edge; everything else dies at the boundary. Example: RecomputeResult, roughly 1,200 tokens replacing a 9,000-token transcript.
Serialization tax — The token cost of re-sending context across every edge. Example: transcript passing paying to re-read the full contract at each hop.
Forbidden edge — A transition deliberately absent from the graph, making a behavior structurally impossible. Example: no draft → execute edge; the drafting agent cannot move money.
Topology as governance — Policy expressed as graph structure rather than prompt instructions, provable by inspecting the edge set. Example: a CI test walking the compiled graph to verify every path to execute crosses policy_router.
Work graph generator — A planner node that constructs the runtime graph per task: what to spawn, in what order, where parallelism is safe. Example: splitting a multi-item dispute into bounded parallel recomputes.
Node eval — Testing one node in isolation against labeled cases. Example: the classifier scored on 50 labeled dispute emails.
Graph eval — Testing the whole topology end to end on golden cases, catching failures that only appear at handoffs. Example: 20 golden disputes with expected credits and routes.
Role definition — An agent node's specification: domain owned, tools allowed, context entitled to, schema emitted. Closer to a job description than a prompt. Example: the classifier's role grants it the email and nothing else.
Context engineering — Deciding what a single model call sees, in what form, at what length. Example: the drafter receiving typed findings instead of raw contracts.
Fan-out — Spawning parallel branches at runtime. Multiplies capability and spend linearly; bound it. Example: a per-task cap on parallel line-item recomputes.
Golden set — Maintained cases with known correct outcomes, used to regression-test the topology itself. Example: rewiring the graph, then rerunning the 20 golden disputes before merge.
References & Further Readings
[1] explainx.ai, "Graph Engineering: Wire Multi-Agent Orgs After Loops," explainx.ai Blog, Jul. 26, 2026. [Online]. Available: https://www.explainx.ai/blog/graph-engineering-ai-agents-multi-agent-organizations-2026
[2] TrueFoundry, "Graph Engineering for Multi-Agent Systems: Architecture, Governance, and Observability," TrueFoundry Blog, Jul. 18, 2026. [Online]. Available: https://www.truefoundry.com/blog/graph-engineering-enterprise-guide
[3] Eigent, "Graph Engineering for AI Agents," Eigent Blog, Jul. 2026. [Online]. Available: https://www.eigent.ai/blog/graph-engineering-ai-agents
[4] "Agentic Software: How AI Agents Are Restructuring the Software Paradigm," arXiv preprint arXiv:2606.05608, 2026. [Online]. Available: https://arxiv.org/pdf/2606.05608
[5] "Graph-Augmented Large Language Model Agents: Current Progress and Future Prospects," arXiv preprint arXiv:2507.21407, 2025. [Online]. Available: https://arxiv.org/pdf/2507.21407
[6] LangChain, "LangGraph Documentation." [Online]. Available: https://langchain-ai.github.io/langgraph/
[7] Pydantic, "Pydantic V2 Documentation." [Online]. Available: https://docs.pydantic.dev/
[8] Arize AI, "Phoenix: Open-Source LLM Observability." [Online]. Available: https://docs.arize.com/phoenix
[9] S. Yao et al., "ReAct: Synergizing Reasoning and Acting in Language Models," arXiv preprint arXiv:2210.03629, 2022. [Online]. Available: https://arxiv.org/abs/2210.03629
[10] Anthropic, "Building Effective Agents," Anthropic Engineering, Dec. 2024. [Online]. Available: https://www.anthropic.com/research/building-effective-agents