What Is Graph Engineering for AI Agents? From Prompt, Context, Harness, and Loop Engineering to System Intelligence
The demo works. Then you add a second worker, a shared artifact store, and a verifier, and the system starts producing results nobody can attribute,…

Key topics
The demo works. Then you add a second worker, a shared artifact store, and a verifier, and the system starts producing results nobody can attribute, reproduce, or stop. The loop did not break. The loop was never the whole model.
The Loop Was Always a Graph With One Node
You already know the layers below this one. Prompt engineering steers tokens. Context engineering curates the window. Harness engineering wraps the model in tools, memory, runtime, and verification hooks. Loop engineering shapes iteration: plan, act, observe, retry. I am not going to re-teach any of that here.
The reframe is narrower and more useful than it sounds: a loop is a control-flow graph with a single node and a self-edge. One unit of work. One edge pointing back at itself. That is a graph. It is just a graph with no topology to speak of.
The moment you add a second worker, you have fan-out. The moment you route a result to a verifier instead of back to the planner, you have a typed edge. The moment you gate a side effect behind human approval, you have a node that blocks state. None of this is new machinery. It is structure you either design or inherit by accident, and inherited structure is where attribution goes to die.
One word, two halves. Knowledge graphs are what agents remember: entities, typed relations, provenance, time. Task graphs are how agents work: jobs, execution dependencies, fan-out, verification, stop rules. Keep them separate in your head. They share a vocabulary and almost nothing else.
Graph engineering is a design vocabulary, not a library you install. There is no
pip install graph-engineeringthat makes your agents coordinate. There is a set of decisions about nodes, edges, state, and termination that you either make explicitly or make badly.
Nodes, Edges, and the State That Actually Moves
A node is a unit of work or a unit of knowledge. An edge is a typed dependency, a data flow, or a control transfer. The type is the load-bearing part. An untyped edge is a hope.
The claim "state lives on edges" is a useful slogan and a dangerous oversimplification. State in an agent system comes in at least five distinct classes, and conflating them is how you end up with a graph you cannot replay:
| State class | Where it lives | Lifetime | Replayable? |
|---|---|---|---|
| Transient model context | Inside one model call | One call | No — regenerate |
| Node-local runtime state | Process memory of one node | One node execution | Only if checkpointed |
| Durable workflow state | Checkpoint store | Across runs | Yes, by design |
| Edge payload | Message between nodes | One edge traversal | Yes, if typed and logged |
| Retrieved knowledge | Knowledge graph / vector index | Until invalidated | Yes, if provenance tracked |
The invariant I would tattoo on the wall: every edge must be independently observable and independently retryable. If you cannot replay one edge without replaying the whole graph, you do not have a graph. You have a loop wearing a graph costume.
The most common modeling error is conflating control flow with data flow. A DAG constrains execution order. It says nothing about what data crosses each edge. You can have a perfectly acyclic execution order and still leak one branch's assumptions into another through a shared store. The topology is clean; the payloads are not.
Here is the smallest artifact worth building — a three-node research-and-verify graph, specified before any framework touches it:
| Node | Edge in | Edge type | State location | Retry semantics | Failure owner |
|---|---|---|---|---|---|
| Planner | task spec | control | local | re-plan from spec | orchestrator |
| Researcher | plan slice | data (typed query) | message payload | re-run slice, idempotent | researcher |
| Verifier | draft + criteria | data (draft, rubric) | message payload | re-verify, no side effects | verifier |
| Aggregator | verified drafts | data (accepted set) | blackboard | re-aggregate only | orchestrator |
Read the last two columns together. Retry semantics and failure ownership are the same decision viewed from two angles. If you cannot name who owns a failure, no retry policy will save you.
Knowledge check
Check your understanding
Answer this question before you continue.
Task Graphs: Fan-Out, Verification, and the Stop Rule
The smallest useful task graph is four nodes: a planner, N parallel workers, one separate verifier, one aggregator. Write it as plain orchestration code before you reach for a graph framework. The framework is not the concept, and adopting it early hides the decisions you most need to see.
def run_task_graph(spec, workers, verifier, aggregator, budget):
plan = planner(spec)
slices = plan.slices # fan-out width is a design choice
drafts = parallel_map(workers, slices, budget_per_node=budget // len(slices))
accepted, rejected = [], []
for draft in drafts:
verdict = verifier(draft, criteria=plan.rubric) # separate context, separate criteria
(accepted if verdict.passed else rejected).append((draft, verdict))
if not accepted:
return Failure(reason="no_draft_passed", rejected=rejected)
return aggregator(accepted, spec=spec)
That code is topology-only pseudocode. It shows the shape of the graph but omits the runtime metadata that makes the graph actually retryable. Here is what a single edge traversal looks like when the invariant is honored:
{
"edge_id": "researcher->verifier:slice-3",
"payload_schema": "DraftV2",
"attempt": 2,
"checkpoint": "ckpt-0041",
"idempotency_key": "slice-3:sha256:9f2a...",
"side_effect_policy": "none",
"status": "completed"
}
Without edge_id, attempt, and idempotency_key, a retry is a guess. With them, a retry is a replay. That is the difference between a graph and a loop with extra steps.
The verifier must be a separate node with its own context. A model asked to check its own output in the same context is biased toward its first plausible answer — this is a well-documented failure mode, and harness builders have been explicit that self-verification needs to be forced rather than assumed. Separate node, separate context, separate criteria. If the verifier shares the producer's prompt, you have built verifier theater with extra tokens.
The stop rule is a first-class design decision, not a default. Unbounded fan-out plus no convergence criterion is how graphs become expensive loops with extra steps. Decide up front: what does "done" mean, what does "give up" mean, and what is the per-node budget that triggers the second one.
A human gate is just another node. Name where approval sits, what state it blocks, and what happens to in-flight parallel work when the gate rejects. That last question is the one teams forget, and it is the one that produces orphaned side effects.
Failure paths worth planning for explicitly:
- Partial fan-out failure — three of five workers succeed. Does the aggregator proceed, or does the graph re-plan?
- Verifier disagreement — the verifier passes a draft the aggregator cannot use. Whose criteria win?
- Duplicate work — overlapping node scopes produce the same artifact twice. Deduplicate at the edge, not at the end.
- Doom loops — a node keeps re-editing the same artifact. Loop-detection and pre-completion verification hooks are harness-level mitigations, and a graph makes them addressable per node instead of per run.
Knowledge check
Check your understanding
Answer this question before you continue.
One Trace, All Layers Composed
The abstract claim "a graph node is a harness running a loop" only becomes useful when you watch it happen. Here is a single research task traced through the four-node graph, annotated with what each layer contributes:
| Step | Node | Loop inside the node | Context assembled | State read/written | Edge payload out | Gate |
|---|---|---|---|---|---|---|
| 1 | Planner | plan → critique → revise (2 iters) | task spec + tool list + prior plans | reads: spec; writes: plan | PlanV1 (slices, rubric) | none |
| 2 | Researcher ×3 | search → read → extract → check (≤5 iters) | slice query + retrieved KG subgraph + source docs | reads: plan slice; writes: local draft | DraftV2 per slice | none |
| 3 | Verifier | check → score → justify (1 pass) | draft + rubric + counter-examples | reads: draft; writes: verdict | VerdictV1 (pass/fail, reasons) | rubric threshold |
| 4 | Aggregator | merge → dedupe → format | accepted drafts + spec | reads: accepted set; writes: final artifact | ArtifactV1 | human approval |
Read the table column by column. The loop column is what each node does internally — that is loop engineering, unchanged. The context column is what each node assembles before its model call — that is context engineering, scoped per node instead of per run. The state column is what the harness checkpoints and what the graph routes — that is the harness layer plus the task topology. The edge payload column is the typed contract that makes the whole thing replayable.
The knowledge graph shows up in step 2, not as a separate system but as one input to the researcher's context assembly. The task graph coordinates who works when; the knowledge graph supplies what relationships are retrievable. They meet inside a node's context window. That is the composition. It is not a merger.
A single execution trace of that graph tells you more than any architecture diagram. Log token cost per node, wall-clock overlap between parallel workers, and where the run actually spent its budget. If the verifier costs 40% of the total and rejects nothing, you have learned something the diagram could not tell you.
Knowledge check
Check your understanding
Answer this question before you continue.
Knowledge Graphs: What the Graph Remembers
The memory half is a pipeline, not a storage format. The shape that holds up: scope → representation → ontology → entities → relations → events → quality gate → fusion → serve. Model the domain before extracting. Fuse before storing. Verify at every stage.
Two properties separate a knowledge graph from a pile of triples. First, typed relations with provenance and time. Facts expire. A graph that does not record when an edge was created or last verified will confidently serve stale context, and the failure is invisible until someone acts on it. Second, entity resolution is the accuracy bottleneck. Multi-hop traversal over unresolved entities produces confident nonsense, and the retrieval layer will not warn you — it will return a clean, well-formed, wrong answer.
The decision between graph retrieval and flat similarity search is not a matter of taste. Define the axis first: does the task need multi-hop relationship reasoning, or does it need the single most similar passage? If it is the latter, a vector index is cheaper, simpler, and better. Graph memory earns its cost when the question is "how are these things connected," not "what does this text say."
A knowledge graph is a product with a schema and an owner, not a pile of triples. Budget for curation and re-extraction, not just ingestion. The ingestion pipeline is the easy half; keeping the graph true is the job.
Knowledge check
Check your understanding
Answer this question before you continue.
Where Graph Engineering Earns Its Cost
The decision axis is one question: does the task decompose into independently verifiable subtasks with real parallelism or real dependency structure? If not, a loop is cheaper to build, cheaper to debug, and cheaper to run.
The cost model is where most comparisons go wrong. Graphs spend more tokens per cycle and buy wall-clock time and attribution. Track cost per successful completion, not cost per call. A graph that costs 3x per call and completes 4x more often is cheaper in the only currency that matters.
| Loop | Single agent + harness | Task graph | |
|---|---|---|---|
| State model | local, implicit | harness-managed | explicit, on edges |
| Debuggability | trace the loop | trace the harness | per-node attribution |
| Cost profile | low per cycle | medium | high per cycle, amortized by success rate |
| Failure blast radius | whole run | whole run | one node or one branch |
| Switch signal | — | one agent, one context, no independent verification | parallel branches, heterogeneous specialists, audit requirements |
When a single agent with a good harness beats a graph: tightly coupled reasoning, small context, no independent verification signal, or a task where splitting the context destroys the information needed to decide. When graphs are overkill: two sequential steps, one tool, one artifact. The orchestration layer becomes pure overhead and a new source of bugs. When graphs are mandatory: long-horizon work with parallel branches, heterogeneous specialists, external side effects that need gates, or audit requirements where every decision must be attributable to a node.
Failure Modes and the Observability You Owe the Graph
Attribution failure. A bad final artifact with no way to tell which node produced it. Fix by logging node inputs, outputs, and edge payloads — not just the final answer. The final answer is the least useful log line in the system.
Context bleed. Shared state quietly carries one branch's assumptions into another. Fix by making edge payloads explicit and typed. If two nodes communicate through a blackboard, version the blackboard.
Convergence failure. The graph runs, spends, and never terminates. Fix with per-node budgets, iteration caps, and an explicit stop rule. This is the most expensive failure mode because it is silent until the bill arrives.
Verifier theater. A verification node that rubber-stamps because it shares the producer's context or criteria. Fix by separating criteria from the producing prompt. If the verifier cannot articulate why it rejected something, it is not verifying.
What to instrument: per-node latency and token cost, edge payload sizes, retry counts, gate rejection rates, and cost per successful completion. These are the numbers that tell you whether the graph is earning its structure. Recovery follows from the retryable-edge invariant: checkpoint at node boundaries so a failed branch can be replayed without re-running the whole graph. That is the practical payoff of designing edges as contracts.
The Migration Experiment That Answers the Question
The migration path is one experiment, and it needs a real acceptance rule or it will produce a false positive. Adding a verifier can improve acceptance while quietly increasing latency, token cost, correlated errors, or side-effect risk. A second verdict is not evidence of a better system.
Take an existing loop, split it into producer and verifier nodes, add a typed edge between them, and measure before and after:
| Metric | Why it matters | Acceptance rule |
|---|---|---|
| Rubric score | Did quality actually improve? | Higher than baseline on the same task set |
| Cost per successful completion | The only cost number that survives contact with reality | Lower than baseline |
| Wall-clock latency | Graphs buy parallelism but pay coordination | Within your task's tolerance |
| Retry rate per edge | Are edges genuinely independently retryable? | Retries succeed without re-running the graph |
| Verifier disagreement rate | Is the verifier doing real work? | Non-trivial, with reasons logged |
| False-pass / false-reject samples | Does the verifier catch what the producer misses? | At least one producer error caught per batch |
The last row is the one that decides whether the split earned its overhead. An independent verifier is valuable only when it detects errors the producer misses — not merely when it produces another verdict. If the verifier agrees with the producer on every sample, you have added cost and latency for nothing.
Two open questions I would hold honestly rather than resolve with confidence. First, how much of the reported harness-over-model advantage generalizes across tasks and model versions; the evidence is real but the effect size is not yet a law. Second, how much graph structure is genuinely necessary versus compensating for weak single-agent verification. If models get better at checking their own work, some graphs will collapse back into loops — and that would be the correct outcome, not a failure of the framing.
Instrument one loop with per-step cost, retry counts, and edge payload sizes. If the trace shows a step that could be independently verified or run in parallel, that step is your first node split. Run the before/after comparison above. The graph is only worth its overhead when the trace proves the structure is real.
Knowledge check
Final check
Finish the article by checking the ideas you just learned.
References
- LLM-assisted Knowledge Graph Engineering
- Improving Deep Agents with harness engineering
- The evolution of graph learning
- GitHub - codejunkie99/graph-engineering: Graph engineering for AI agents: the 9-stage knowledge-graph pipeline (translated from SEU's graduate course) + task-graph orchestration patterns, as a Claude skill with teaching mode and paste-ready workflows · GitHub
Research updated Sep 11, 2026