Stop Making Your Agents Queue: A Beginner's Guide to Graph Engineering
85% of OpenAI's internal engineers run hundreds of agents with Codex, all thanks to graph engineering. Based on Codez's 14-step guide, this article walks you through core concepts including nodes, edges, parallelism and validation, and shows you how to implement a parallel, self-validating, scalable agent system with Claude Code.
An OpenAI engineer mentioned in a speech at Stanford that 85% of the company's internal engineers are running hundreds of agents using Codex. He noted that the key to this is Graph Engineering. The video is embedded below and well worth watching.
When most people build multi-step agents, they end up with a straight line: Step 1, Step 2, Step 3, with each step waiting for the previous one to finish. Codez points out in his guide that in 9 out of 10 cases, half of those steps don't need to wait at all. There's no routing, no branching, no parallelism — just waiting in line. One context, one task, until the context window fills up, and the agent forgets what it was doing.
His solution is: turn that single line into a graph. Nodes handle work, edges pass results. Claude Code already provides the tools to build this kind of graph: dynamic workflows. Claude writes a JavaScript orchestration script, then spins up a group of child agents to execute — and the coordination itself doesn't consume model tokens, because it's code, not conversation.

**Nodes and Edges**
A graph only has two components. Nodes are units of work — one agent, one bounded task, one input and one output. Edges are dependencies: they mean "the output of this node feeds the input of that node". A common mistake is treating every "then" as an edge. "Summarize the file, then tell me the weather" has no edge between these two steps — the weather doesn't consume the summary. For every "then", ask yourself: does the next step actually read the output of the previous step? If not, that wait is just waste.

When you write an agent as "do A, then B, then C, then D", what you're actually drawing is an unbranched chain. It runs correctly, but it's slow and fragile: if C gets stuck, D will never execute. The first real skill is to redraw this chain, find the arrows that don't actually pass data, cut them out, and the chain collapses into a wider structure. Every node should have a contract: bounded input, bounded output, exactly one task. In Claude Code, you can use JSON schema to force child agents to return validated structured data instead of free text.

Edges are data contracts. Name edges by their data shape, not by sequence. This makes it easier to see if the edge is real, and also lets you swap out nodes when the data shape stays the same. In code, edges are just JavaScript's reduce, flatten, filter — no agent needed. This is a quiet win of graph thinking: a lot of the work you spend model tokens on are actually just edges, and edges are free.


**Parallelism and Fan-in**
When you have N independent tasks, don't execute them in a chain. Dispatch them all at once with `parallel()`. In Claude Code, it accepts an array of thunks, spawns a child agent for each thunk to run concurrently, then returns an array of results. `parallel()` is a barrier: it waits for all thunks to complete before returning. If a thunk throws an exception, it resolves to null instead of failing the entire batch, so don't forget to add `.filter(Boolean)`. The number of concurrent tasks is limited by the number of cores, and any excess will queue, so you can pass a hundred thunks and they'll all complete — just a few at a time.

The convergence end is a fan-in node, where all upstream results are collected. One agent (or a snippet of code) sees all results together, then does the work that requires the full set: deduplication, sorting by impact, exiting early if the total set is empty. This is the only barrier worth waiting for. The rule: only use a barrier when a stage actually needs all previous results; otherwise, use inline edges.

Combining fan-out and fan-in gives you the most classic topology: the diamond. One node decomposes the task, multiple nodes work in parallel, one node merges the results. Market scanning, dependency auditing, code review, research reports — swap out the inputs and prompts, and the skeleton is the same. Remember this formula: fan out → reduce → synthesize.

**Routing and Validation**
Graphs aren't always static. Sometimes which edge you take depends on what the node discovers. A router node checks the result and decides the subsequent path. In Claude Code, this is just an if or switch statement, because control flow lives in code. You can use Claude to make the routing decision (e.g. classification), but the routing itself is written in code, so the same classification always takes the same path. Determinism is a feature, not a limitation.

The real leverage comes from validation. A validator node sits on an edge, and its only job is to try to kill the finding. Only if it survives is it allowed through. There are three common patterns: adversarial validation (N independent skeptics try to refute the finding), perspective diversification (check correctness, safety, reproducibility), and panel judging (N attempts, scored in parallel, synthesize the optimal result). This pattern helped a team successfully port the Bun runtime.

**Failure Isolation and Looping**
In a graph, failures should be contained within nodes. A thrown exception from a thunk in parallel() becomes null, so eight good agents still return their results while the bad one drops out. When designing fan-in, you should tolerate missing inputs. Another subtle issue: parallel file writing can cause conflicts, and the solution is to have each agent work in an independent git worktree.

Some tasks have unknown size and require looping. But loops must converge. The pattern is loop-until-dry: keep dispatching finders until no new content is found for K consecutive rounds. The key detail is that deduplication is applied against everything you've ever seen, not just what's been confirmed — otherwise you'll get an infinite loop.

**Model Tiering and Topology Cost**
Not every node needs the most powerful model. A graph lets you clearly see which nodes are repetitive and which are judgmental. Run repetitive work on cheaper models, and save expensive tokens for places that actually need judgment. In Claude Code, you can specify the model for individual agent() calls.

Topology directly affects latency. A parallel() barrier makes everything wait for the slowest node, while pipeline() lets each item flow through all stages independently with no barrier. Use pipeline() by default, only use a barrier when you actually need all results. Separating stages isn't the same as synchronizing them.

**Let Claude Build the Graph Itself**
The final step: let Claude write the orchestration script itself. Describe your goal, and Claude will decompose the task, choose fan-out, dispatch child agents and synthesize the results. In Claude Code, just saying "workflow" triggers this. Or you can use the built-in /deep-research workflow, which is already a production-grade graph: scope → parallel search → fetch → adversarial verify → synthesize.

**Six Graphs You Can Build Right Now**
Codez gives six examples: security scanning for every route file, research reports with citations, module porting file-by-file, adversarial diff review, scheduled ecosystem scanning, problem discovery for unknown-sized tasks. The diagram below summarizes all of them.

Conclusion: Prompt engineers ask questions, graph architects draw graphs. Linear agents aren't the ceiling — they're just the first shape most people reach for because of how we type. Once you can see nodes and edges, you'll stop asking agents to do more things, and start making your graph wider. Most people have their agents waiting in line; a few learn to draw graphs, and they run a whole fleet that never hits the ceiling overhead.
发布时间: 2026-08-10 11:38