Graph Engineering Graph engineering, the practice of designing the structure an AI agent runs inside, is introduced as a solution for complex multi-step tasks that overwhelm single-agent loops. The article defines key terms—harness, loop, and graph—and outlines four core patterns (sequential, branching, parallel, and conditional routing) that cover most production systems. It emphasizes that graphs prevent steps from interfering with each other, improving reliability over monolithic agent prompts. You have probably built an agent. Maybe it calls a search tool, reasons over the results, formats a response, done. One loop. Works fine. You feel good about it. Then a coworker drops a harder problem on your desk. Not a single-step retrieval task. Something with moving parts, multiple specialised checks, parallel processing, a human who needs to approve before anything irreversible happens. You try to cram it all into one agent loop. The system starts behaving strangely. It skips steps. It forgets what it was doing three turns back. You add more instructions to the prompt. Things get worse. This is the moment graph engineering becomes relevant. Graph engineering is the practice of designing the structure an AI agent runs inside, not the agent itself. Think of it this way. An agent is like an employee: it has skills, memory, tools, and judgment. Graph engineering is the org chart that defines who that employee talks to, when they talk to them, what information gets passed along, and under what conditions work moves forward versus gets sent back. You are not just hiring smart people. You are designing how the organisation works. The nodes are the workers. The edges are the handoffs. The state is the memory shared between them. Before the patterns, three terms. Get these right and the rest of the article clicks. Every agent sits inside what practitioners call a harness. It is the wrapper around the model itself , the memory it has access to, the tools it can call, and the guardrails that prevent it from doing something catastrophic. The harness is not the agent’s intelligence. It is the agent’s operating environment. A well-built harness gives the agent exactly what it needs for its specific job and nothing extra. A poorly built harness dumps everything into the context window and hopes for the best. A loop is the iterative cycle inside a single agent. The agent reads a problem, decides whether to call a tool or produce an answer, acts, observes the result, and goes again. This is the ReAct pattern. It is powerful for focused tasks. The key word is focused . One agent. One goal. Loop until done. Loops break down when the problem has distinct phases with different context requirements. Asking one agent to review code for security issues and performance issues and API design and test coverage in one loop is like asking one person to simultaneously be your security auditor, your performance engineer, your API designer, and your QA lead. They cannot fully inhabit all four mental models at once. A graph is a structured workflow that connects multiple nodes — each node being an agent, a function, or a processing step — with edges that define how work moves between them. The simplest graph is one node with an edge looping back to itself. That is just a loop with extra vocabulary. The interesting graphs are the ones with branching, parallelism, synchronisation points, and conditional routing. Those are the patterns below. These four patterns cover the overwhelming majority of what real production systems do. Everything complex you will ever build is some combination of these. The simplest structure. Node A completes, passes its output to Node B, which completes and passes to Node C. Each step processes the output of the previous one. Node A → Node B → Node C → Output When do you use this? When a task genuinely benefits from decomposition into sequential steps. A code review pipeline might: first parse the diff, then check it for security issues, then format the findings into a report. Each step has a different job and benefits from receiving a focused, clean input rather than raw everything. The critical point here: the graph is not making the steps smarter. It is preventing them from interfering with each other. A small code example shows the shape clearly: Each node does one focused job and returns a state updatedef parse diff state: State - dict: parsed = extract changed files state "raw diff" return {"parsed diff": parsed}def check security state: State - dict: findings = security llm.invoke state "parsed diff" return {"security findings": findings}def format report state: State - dict: report = format llm.invoke state "security findings" return {"final report": report} Each function receives the full state and returns only the fields it changed. The graph wires them together. No node needs to know what the others are doing. This is where graphs justify their existence. Fan-out takes one task and splits it into multiple parallel sub-tasks that run simultaneously. Join is the synchronisation node that waits for all of them to finish, then merges the results. ┌→ Security Agent ─┐ ├→ Perf Agent ──┤Input → Router┤→ API Agent ──┼→ Join → Output ├→ Test Agent ──┤ └→ Quality Agent ─┘ The real-world example from the video is a pull request review system. You could send the same PR diff through a security reviewer, a performance reviewer, and a test coverage reviewer sequentially. Or you fan out to all three simultaneously, wait for all three to finish, and merge the findings. Total time is roughly equal to the slowest single reviewer, not the sum of all three. The fan-out pattern in code uses the Send API to dispatch parallel branches: php from langgraph.constants import Senddef fan out to reviewers state: State - list Send : Dispatch all reviewers simultaneously Each runs independently, returns findings to the same state field return Send "security agent", state , Send "performance agent", state , Send "api agent", state , Send "test agent", state , The join happens automatically when you use an accumulator on the findings field: python from typing import Annotatedimport operatorclass State TypedDict : operator.add concatenates lists from parallel branches safely Without this, the last agent to finish would overwrite all the others findings: Annotated list, operator.add That single operator.add annotation is doing serious work. When four agents all return findings simultaneously, LangGraph collects every write and concatenates them instead of letting the last writer win. This is not a coincidence. It is a deliberate design decision you make when you define the state schema. A router reads the current state and sends work to a different node depending on what it finds. ┌→ Fixer Agent → back to startInput → Reviewer ─┤ └→ Human Review Gate → Approved → Done From the video: after a code review agent evaluates a pull request, the router checks the outcome. Tests failed? Send it to a fixer agent. Tests passed? Route it to a human for final approval. The reviewer’s output determines where work goes next. This is where the distinction between LLM routing and Python routing matters enormously. You could ask the LLM to decide where to send the work. Or you could write a Python function that reads a structured field from the state and returns a node name. The routing function is Python — not an LLM calldef route after review state: State - str: if state "test result" == "failed": return "fixer agent" deterministic, testable, free elif state "risk level" == "critical": return "human review" also deterministic return "approve and merge"