Study guides / CCDV-F / Domain 3

Agents & Workflows · Lesson 3 of 5

3.3 - Task Decomposition Strategies

Break a large task into steps deliberately, and recognise attention dilution before it degrades output quality.

Two broad decomposition strategies cover most cases. A fixed sequential pipeline has a known step order in advance, where each step's output feeds the next as a separate, focused call - summarise, then extract, then translate. A dynamic adaptive decomposition lets the agent decide its next step based on what it's learned so far, because the full plan genuinely isn't knowable upfront - this is what an agentic loop (Lesson 3.1) already gives you: each iteration's tool choice is itself a decomposition decision made in response to the latest tool result. Fixed pipelines are simpler to build, test, and debug, since each step's prompt and expected output are stable and can be checked in isolation. Dynamic decomposition is necessary when the task's shape genuinely depends on intermediate findings - debugging an unfamiliar codebase, open-ended research, anything where step 2 can't be written until you know what step 1 found.

Choosing pipeline granularity

Granularity is a real design decision, not a detail to leave to instinct. Steps that are too coarse recreate attention dilution inside a single step - you've just moved the bundling problem down one level. Steps that are too fine add needless round-trip latency and cost, and can lose cross-step context that a slightly larger step would have kept naturally (a step that only sees an isolated fragment of the task may lack the surrounding information to do its narrow job well). A workable rule of thumb: one step should correspond to one checkable objective - something you could independently verify as done correctly or not, given just that step's output.

Attention dilution, mechanically

Handing a single agent several simultaneous objectives in one turn - "summarise this, also extract these five fields, also translate it, and flag compliance issues" - degrades performance on all of them compared to sequencing them as separate steps. This isn't just vague "loss of focus": a single generation pass has to simultaneously satisfy criteria that can actively conflict (concise vs. exhaustive, literal vs. interpretive), and it has one shot to allocate attention across all of them at once rather than each objective getting a full, focused pass. The same fragmentation applies to extended thinking budget: a model given a large thinking budget on a bundled multi-objective prompt tends to spread that budget thin across sub-problems rather than working any single one through completely. Decomposing into smaller, single-objective steps is very often a bigger reliability win than a more carefully worded combined prompt.

Common exam distractor

An answer that tries to fix a multi-objective quality problem purely by rewording the prompt more carefully, without decomposing the task itself, is treating a structural problem as a wording problem. Better instructions can help at the margins, but they don't remove the fundamental fact that several objectives are still competing for the same reasoning pass.

Verification between pipeline steps

In a fixed pipeline, an error or hallucination at step 2 propagates silently into step 3 if step 3 has no way to notice something is off - it just trusts its input and does its job on bad data. A lightweight verification checkpoint between steps (a schema check on extracted fields, a sanity check on item counts, a quick "does this look complete" pass) catches this before it compounds, and is cheap relative to redoing the whole pipeline after a downstream step produces garbage from bad upstream input. This connects directly to Lesson 3.5: verification that must never be skipped belongs in code as a deterministic gate, not left to the next step's judgment.

Practical example: a support-ticket triage pipeline

A team builds an agent to handle incoming support tickets in one bundled call: classify the ticket's category, assess urgency, draft a reply, and flag anything that looks like a legal or safety issue - all in a single prompt against the raw ticket text. Urgency assessment and legal-flagging come back inconsistent; sometimes a genuinely urgent ticket is scored as low priority, and legal-relevant language occasionally slips past the flag entirely.

The team's first instinct is to add more examples and stronger wording to the urgency and legal-flag instructions. It helps marginally, but the inconsistency persists, because the actual cause is structural: four judgment calls sharing one generation pass, two of which (urgency, legal risk) carry outsized cost when wrong. Splitting into a pipeline - classify, then assess urgency using the category as context, then check for legal/safety flags as its own single-objective step, then draft the reply last, informed by all three - resolves the inconsistency far more reliably than any amount of additional prompt tuning on the bundled version. The legal-flag step in particular is a good candidate for the verification-and-gating pattern from Lesson 3.5: given the cost of a missed flag, it may be worth pairing the step with a deterministic keyword/pattern pre-check rather than trusting model judgment alone for that one narrow slice of the pipeline.

Key concept

Decomposition granularity is a design decision on par with prompt wording, not something to leave to instinct - both too coarse (attention dilution inside a step) and too fine (latency, lost context, needless overhead) are real failure modes, not just one of them.

Exam traps

Practice question

An agent is asked in one turn to summarise a document, extract five specific data points, translate the summary, and flag any compliance concerns. Output quality on the data extraction and compliance flags is inconsistent. What's the most likely fix?

  • A Decompose into sequential steps - summarise, then extract, then translate, then flag - so each gets focused attention. Correct

    This is a textbook attention-dilution case: four distinct objectives crammed into one turn. Sequencing them into focused steps addresses the root cause.

  • B Increase max_tokens so there's more room for a complete answer.

    The problem is quality/consistency across multiple bundled objectives, not truncated length - more output room doesn't fix attention dilution.

  • C Switch to a cheaper model tier to reduce cost, since output quality is unrelated to task structure.

    This doesn't address the actual cause (too many simultaneous objectives) and would likely make quality worse, not better.

  • D Enable prompt caching on the document content.

    Caching affects cost/latency of re-processing input, not the quality degradation from bundling multiple objectives in one pass.

Build exercise: Decompose a multi-objective prompt into a verified pipeline

Intermediate · 35 minutes

You'll practice:

  1. Write a single bundled prompt that asks Claude to do three distinct things on some sample text: summarise it, extract a list of 4 specific facts, and critique its argument. Run it once and inspect the quality of all three parts.

    You need the attention-dilution baseline in front of you before decomposition means anything concrete - this is the failure mode you're about to fix.

    You should see: One response attempting all three objectives, with at least one (commonly the extraction or critique) noticeably weaker or less complete than if it were the only ask.

    Hints
    1. What sample text would make it easy to spot a missed or wrong extracted fact?
    2. Pick a text with clearly identifiable facts (e.g. specific numbers, names, dates) so it's obvious if the extraction step misses or fabricates one under the bundled prompt.
    3. const bundled = `Text:\n${sampleText}\n\n1) Summarise in 2 sentences.\n2) Extract: author, publication year, main claim, one cited statistic.\n3) Critique the argument's weakest point.`;
      const r = await client.messages.create({ model: "claude-sonnet-5", max_tokens: 600, messages: [{ role: "user", content: bundled }] });
  2. Split the same task into three sequential calls - summarise, then extract (given the summary), then critique (given both) - each with a single, narrow objective, and run those against the same input.

    This is the actual decomposition move the exam tests: each step gets a full, undivided reasoning pass instead of splitting attention across three asks at once.

    You should see: Three separate API calls, each returning output for exactly one objective, chained so each step's prompt includes the prior step's output.

    Hints
    1. Does the extraction step need the original text, the summary, or both to do a good job?
    2. Pass the original text to every step (extraction and critique often need to check facts against the source, not just the summary), plus the prior step's output for continuity.
    3. const summary = await callStep(`Text:\n${sampleText}\n\nSummarise in 2 sentences.`);
      const extracted = await callStep(`Text:\n${sampleText}\n\nSummary: ${summary}\n\nExtract: author, publication year, main claim, one cited statistic. Return as JSON.`);
      const critique = await callStep(`Text:\n${sampleText}\n\nSummary: ${summary}\nExtracted facts: ${extracted}\n\nCritique the argument's weakest point.`);
  3. Add a verification checkpoint after the extraction step: parse its JSON output and confirm all 4 required fields are present and non-empty before passing it into the critique step; if a field is missing, re-call the extraction step once with a targeted follow-up before proceeding.

    This is the pipeline-reliability half of decomposition - catching a malformed or incomplete intermediate result before it silently degrades the next step, rather than trusting linear propagation.

    You should see: A check that fails loudly (and triggers a retry) on incomplete extraction output, and passes silently through when the extraction is well-formed.

    Hints
    1. What's the cheapest possible check that would catch "the model forgot to extract the statistic"?
    2. Try/parse the extraction output as JSON and check that every expected key has a non-empty value. On failure, don't just fail the whole pipeline - retry that one step with an explicit reminder of what's missing.
    3. function verifyExtraction(json) {
        const required = ["author", "publication_year", "main_claim", "cited_statistic"];
        const parsed = JSON.parse(json);
        const missing = required.filter(k => !parsed[k]);
        return { ok: missing.length === 0, missing, parsed };
      }
      let check = verifyExtraction(extracted);
      if (!check.ok) {
        extracted = await callStep(`Text:\n${sampleText}\n\nYour previous extraction was missing: ${check.missing.join(", ")}. Extract ALL four fields as JSON.`);
      }
  4. Compare the bundled run and the verified pipeline run side by side on the same input and note which objective(s) improved.

    This is the direct evidence that decomposition (not just better wording) was the fix - you're confirming the mechanism, not just trusting the theory.

    You should see: The decomposed, verified pipeline producing more consistently correct or complete results on at least the extraction step, and arguably the critique step too since it now has verified facts to work from.

    Hints
    1. What would count as objective evidence of improvement, rather than a vibes-based comparison?
    2. Check the same 4 extracted fields' correctness in both versions against the source text, and count how many are present/correct in the bundled run vs. the pipeline run.
    3. console.log("Bundled extraction fields correct:", countCorrectFields(bundledResult));
      console.log("Pipeline extraction fields correct:", countCorrectFields(check.parsed));
  5. Now deliberately over-decompose: split the 2-sentence summarisation step alone into two separate calls (one per sentence), time the whole pipeline before and after, and note that this split adds latency and cost without fixing any real quality problem.

    The exam also tests the opposite failure - recognising when further splitting has stopped being decomposition and started being needless overhead. Feeling the added latency directly is the clearest way to internalise the boundary.

    You should see: A measurable increase in total wall-clock time and API call count for the over-split version, with no corresponding quality improvement on the (already single-objective) summarisation step.

    Hints
    1. Is there a second, distinct objective inside "write a 2-sentence summary," or is it still one objective just being split arbitrarily?
    2. Splitting a single coherent objective into artificial sub-steps (sentence 1, then sentence 2) isn't decomposition by objective - it's decomposition by arbitrary boundary, and each extra API call just adds latency for the same underlying task.
    3. console.time("normal-pipeline");
      const summaryNormal = await callStep(`Text:\n${sampleText}\n\nSummarise in 2 sentences.`);
      console.timeEnd("normal-pipeline");
      
      console.time("over-split-pipeline");
      const sentence1 = await callStep(`Text:\n${sampleText}\n\nWrite the first sentence of a 2-sentence summary.`);
      const sentence2 = await callStep(`Text:\n${sampleText}\n\nFirst sentence: ${sentence1}\n\nWrite the second sentence.`);
      console.timeEnd("over-split-pipeline");

Sources