
The same bug fix as a workflow cost a quarter to a sixth as much as the agent
Chapter 1 fixed one Go bug on four models in two ways, as a three-step workflow written in code and as an agent that picks its own steps. The workflow was cheaper and faster on every model, and its single failure shows what it trades away.
This page works on one stage of the loop
- 1Build the request
- 2Call the model
- 3Run the tools
- 4Decide (this page)
¼ to ⅙ of the agent’s cost
Written as a fixed three-step workflow, the bug fix cost a quarter to a sixth as much as the agent on each of four models, and its one model call took between under a second and 2.5 seconds, while each agent run took 7.5 to 13.5 seconds.
- Task
- the
durationbug fix, as a three-step workflow and as an agent with four tools - Models
anthropic/claude-haiku-5.5,openai/gpt-5.6-luna,z-ai/glm-5.3-flash,deepseek/deepseek-v4.1-flash- Runs
- ten per model for each version; costs are medians
- Date
- October 2026
Chapter 1, and chapter 5’s table of shapes
In an agent, the model picks every next step. In a workflow, your code has already picked the steps, and the model is called at the places the code chose. A common rule of thumb says to prefer a workflow whenever you know the steps. Chapter 1 of the book checked that rule on a task small enough to build both ways.
What was tested
The task: a small Go package, duration, has failing tests because its unit table maps 'm' to time.Second.
The agent is chapter 4’s program: the loop from the agent loop in Go with a real model client, given four tools (list_files, read_file, edit_file, run_tests) and left to find its own way.
The workflow is three steps written into the program:
- Run the tests, and read the package file and its test file.
- Put all of that into a single request and ask the model for one edit, in JSON.
- Apply the edit, then run the tests a second time.
Each version ran ten times on each of four inexpensive models in October 2026: anthropic/claude-haiku-5.5, openai/gpt-5.6-luna, z-ai/glm-5.3-flash, and deepseek/deepseek-v4.1-flash.
The result
Costs are medians of ten runs:
| Model | Workflow: tests pass | Workflow: cost | Agent: tests pass | Agent: cost |
|---|---|---|---|---|
anthropic/claude-haiku-5.5 |
9 of 10 | $0.00013 | 10 of 10 | $0.00080 |
openai/gpt-5.6-luna |
10 of 10 | $0.00022 | 10 of 10 | $0.00089 |
z-ai/glm-5.3-flash |
10 of 10 | $0.00018 | 10 of 10 | $0.00076 |
deepseek/deepseek-v4.1-flash |
10 of 10 | $0.00019 | 10 of 10 | $0.00116 |
On every model, the workflow’s cost was between a quarter and a sixth of the agent’s, and it finished several times sooner. The gap comes from the shape of the two programs. The agent made four to six model calls, and each one resent the conversation so far along with about 270 tokens of tool definitions, plus whatever the provider adds around them. The workflow made a single call and offered no tools. On this bug, the workflow is the better choice.
The one failure
One workflow run failed, on anthropic/claude-haiku-5.5.
Go source is indented with tabs, and the model put a literal tab character inside a JSON string, which JSON forbids, so the edit could not be decoded.
Nothing in the three steps allowed a second try, so the run ended there.
An agent handles the same mistake differently. Its loop would have sent the decoding error back to the model, which could then have corrected its call on the following turn. The loop’s argument decoder writes the reason and an example of the expected shape into that error:
// decodeArgs decodes a tool call's arguments. When they don't decode,
// the error says what was wrong and shows the shape the tool expects,
// so the model can fix its next call.
func decodeArgs[T any](args jsontext.Value, example string) (T, error) {
var v T
if err := json.Unmarshal(args, &v); err != nil {
return v, fmt.Errorf("bad arguments: %w; send JSON like %s",
err, example)
}
return v, nil
}
That one run shows the trade. The workflow is cheap because a person fixed the steps in advance, and it is fragile because nobody wrote a step for a model reply that can’t be used.
What it can’t show
The task is easy on purpose, and that is what lets the comparison work at all. The workflow succeeds because its author already knew what the bug needed: the package file, its test, and a single edit. Move the cause into a third file, or make it a bug you can only find by running the tests, and the three steps no longer match the problem. Ten runs per cell are enough to show a four- to six-fold cost difference, but far too few to measure failure rates: one failure in forty runs doesn’t support an estimate. The task also can’t tell the models apart, since every agent run passed in four to six turns. To compare models, or to learn whether a change to an agent helped, you need tasks that agents sometimes fail.
What to do with it
- Begin with the steps you already know. If you can list them, build a workflow. It costs less, runs faster, and is simpler to test, because every run follows the same path.
- Use an agent when each step depends on what the previous one found. That dependence is what the agent’s extra calls pay for. A crash whose cause sits far from where it showed up, or a problem where you must collect evidence before you know what to read, won’t fit a fixed sequence.
- Combine the two. Most real systems fall somewhere between. A support system, for instance, can send each ticket down a workflow and pass only the odd cases to an agent.
- Let a workflow retry its model step. Its one failure here was a decoding error that a second attempt could have fixed, and an agent’s loop already has that retry built in.
Try it
The workflow and agent runs behind the table are in the repository’s evidence directory, and go run ./evidence, with no key set, prints the table again from them. The agent itself is chapter 4’s program.
From the code directory of a clone of the companion repository:
$ go run ./ch04
This replays the agent’s recorded run on the default model, runs go test for real, and prints the cost: $0.0008 across four model calls.