Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

When to use multiple agents

After this lesson: I can use token estimates to decide when more than one agent is worth the cost.

60 min lesson6 commandsAI coding agent lab: use opencode to explain and fix code, and check its work

More agents is not more intelligence

A multi-agent system is a program where one model call hands work to other model calls, each with its own context. It matters because every agent you add is paid for in tokens, time and new ways to fail.

Teams of agents are sold as the next step. Sometimes they are. Often one agent with good tools does the same job for much less.

By the end of this lesson

Note

I can use token estimates to decide when more than one agent is worth the cost.

Key words

WordWhat it means
Context windowthe most text one agent can hold at once
Orchestratorthe agent that splits the work and joins the answers
Workeran agent that does one part and reports back
Shared textinstructions every agent must read again
Coupled worksteps where each one needs the result of the last
Parallelparts that can be done at the same time

The cells students fill in are left blank in this preview.

Every agent reads the shared text again

A lone agent reads its instructions once. A team does not. The orchestrator reads them, and so does each worker, because a worker has a separate context and cannot see anyone else's.

So a team costs the shared text once per agent, plus a brief and a result for every part. The part itself is only read once, by the worker that owns it.

Worked example: three reports

WhoReadsTokens
One agentShared 1500 + three reports 5500 + answer 4007400
OrchestratorShared 1500 + three briefs 600 + final 3002400
Three workersShared 1500 each + a report each + a result each10600
The team in allOrchestrator and workers together13000

The cells students fill in are left blank in this preview.

When a split pays for itself

Split when one agent cannot hold the work. Split when the parts are independent and speed matters. Split when a part needs a clean context, so earlier text cannot mislead it.

Do not split coupled work. If step two needs the exact result of step one, a second agent only adds a lossy summary between them.

A common mistake

Warning

Many people split a task because it has several nouns in it. Count the dependencies, not the nouns. Work that shares one record and edits it in order is one agent's job.

Write the model helper, part 1

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// The token counts of a reply, or null when the reply carries none.' 'function count(data, name) {' '  return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the model helper, part 2

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' '  try {' '    const res = await fetch(base + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"status \" + res.status);' '    const data = await res.json();' '    const text = data.choices[0].message.content;' '    return { text, inTokens: count(data, \"prompt_tokens\"), outTokens: count(data, \"completion_tokens\"), recorded: false };' '  } catch (error) {' '    console.log(\"Recorded sample: no model answered (\" + error.message + \").\");' '    return { text: sample, inTokens: null, outTokens: null, recorded: true };' '  }' '}' 'module.exports = { ask };' >> model.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the cost script, part 1

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const WINDOW = 8000; // tokens one agent can hold' 'const NOTE = 200; // one brief or one result' 'const CASES = [' '  { name: \"three reports\", shared: 1500, parts: [1800, 2000, 1700], coupled: false },' '  { name: \"one long report\", shared: 1500, parts: [900], coupled: false },' '  { name: \"edit one file\", shared: 1500, parts: [1200, 1000], coupled: true },' '  { name: \"ten documents\", shared: 1500, parts: Array(10).fill(900), coupled: false },' '];' > split.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the cost script, part 2

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function sum(list) { return list.reduce(function (a, b) { return a + b; }, 0); }' '// One agent reads the shared text once, then every part, then answers.' 'function single(c) { return c.shared + sum(c.parts) + 400; }' '// A team: the boss reads the shared text again, and so does every worker.' 'function team(c) {' '  const boss = c.shared + NOTE * c.parts.length + 300;' '  const workers = c.parts.map(function (p) { return c.shared + p + NOTE; });' '  return boss + sum(workers);' '}' >> split.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the cost script, part 3

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function choose(c) {' '  if (c.coupled || c.parts.length < 2) return \"one\";' '  if (single(c) > WINDOW) return \"several\";' '  return team(c) <= 2 * single(c) ? \"several\" : \"one\";' '}' 'async function main() {' '  for (const c of CASES) {' '    const x = Math.round((team(c) * 10) / single(c)) / 10;' '    console.log(c.name + \": one \" + single(c) + \", team \" + team(c) + \" (x\" + x + \"), choose \" + choose(c));' '  }' '  const q = [{ role: \"user\", content: \"In one sentence: name a job that should not be split between agents.\" }];' '  const r = await ask(q, \"Editing one file in steps, because every step needs the last one.\", 40);' '  console.log(\"Model: \" + r.text.trim());' '}' 'main();' >> split.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Run the cost script

Command
docker exec -w /home/node/project agent node split.js

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

These are estimates

The Run does not call a team. It works the sums over four recorded cases, because a real team would spend the lab's allowance in one go. The token sizes are invented, and a real system measures its own.

The one live call only asks for a sentence.

One possible output

LineWhat it shows
three reports: one 7400, team 13000 (x1.8), choose severalIt fits in one window, but the team is under double
one long report: ... choose oneOne part cannot be shared out
edit one file: ... choose oneCoupled work stays with one agent
ten documents: one 10900, team 29800 (x2.7), choose severalOne agent cannot hold it, so the cost is paid
Model: ...A sentence that differs every run

The cells students fill in are left blank in this preview.

About this lab and its source: AI coding agent lab: use opencode to explain and fix code, and check its work

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.