Skip to content

Case study · Reliability & Cost & latency

Multi-agent systems without the spiral

Two production agent systems on MCP and CrewAI — a project-management assistant and an autonomous lead-generation pipeline. What multi-agent buys you, what it costs, and the specific cases where a single agent with good tools wins.

In production, not a demo
MCP + CrewAI
My role
Technical Lead — architecture, agent design, delivery
Stack
PythonFastAPIModel Context ProtocolCrewAILangChainAzure OpenAIPostgreSQLDocker

What broke

A researcher agent and a qualifier agent disagreed about whether a company was worth pursuing, so the orchestrator asked both again. And again. Nineteen billed model calls to decide one lead was a bad fit.

I have built two multi-agent systems that ran in production rather than in a demo: a project-management assistant that let people manage tasks and boards conversationally, and an autonomous lead-generation pipeline that researched prospects, enriched company data, qualified leads, and drafted personalised outreach.

Both worked. Both taught me that the interesting engineering in multi-agent systems is almost entirely about bounding them.

The honest framing first

Multi-agent architectures are oversold. The genuine wins are narrow:

  • Separation of context. A researcher agent that only sees research context produces better output than one prompt trying to hold research, qualification and writing at once.
  • Different tools per role, so no single agent gets a bloated tool list billed on every call.
  • Independent, parallelisable work — enriching forty companies concurrently.

Everything else people claim for multi-agent — “emergent collaboration”, “self-correcting teams” — I have not seen hold up under cost scrutiny. Two agents debating is two agents billing. If a single agent with a well-designed tool set can do the job, it will be cheaper, faster, and far easier to debug.

Architecture

Lead generation pipeline, with the bounds made explicit

The interesting parts are the step ceiling, the structured handoffs, and the fact that agents cannot call each other directly.

Select a stage to see the decision made there.

01 Trigger & budgetFastAPI

Every run starts with an explicit budget: a maximum step count and a maximum token spend. The run is a bounded resource from the first line, not something that gets bounded later when the bill arrives.

Tradeoff: Occasionally a genuinely complex prospect hits the ceiling and returns partial results. Partial results with a clear reason beat unbounded spend.

What broke

The qualifier agent originally returned prose with a recommendation embedded in it. The orchestrator’s logic checked whether the recommendation was confident enough to proceed — and when it could not tell, it re-ran the research and qualification steps to gather more information.

On an ambiguous prospect, that produced a loop. The researcher found slightly different information, the qualifier expressed slightly different hedged confidence, and the orchestrator asked again. Nineteen billed model calls to conclude that one company was a bad fit — a conclusion a human reaches in about four seconds.

Three things fixed it, and all three are now defaults for me:

  1. Structured output with an explicit confidence field. The orchestrator branches on a number, not on its reading of a sentence. Ambiguity became a value the code could handle rather than a condition it could not detect.
  2. A step ceiling per run. Bounded before it is needed, not after.
  3. Repetition detection. Hash each tool call with its arguments; if the same hash recurs within a run, stop and escalate rather than hoping the next attempt differs.

I have since written this failure up as a named category — the runaway loop — because I have now seen it in several other codebases with the same root cause.

What MCP actually changed

For the project-management assistant, I used Model Context Protocol to expose tools — task manager, board manager, status handler — as modular servers rather than functions wired into the agent.

The real benefit was not the protocol itself. It was that the tool boundary became a place where validation, authorisation and logging naturally lived. When tools are ordinary in-process functions, it is tempting to pass model output straight through. When they are a separate server with a schema, validating input is the obvious thing to do.

The cost: another deployment surface, and the tool schemas count against input tokens on every call. For a system with many tools, trimming those schemas was a measurable cost win.

What I would tell you before you build one

Start with a single agent and good tools. Add a second agent only when you can name the specific context separation or parallelism it buys you. When you do:

  • Agents return structured data to an orchestrator; they do not call each other.
  • Every run has a step ceiling and a token budget before it is ever launched.
  • Every agent gets only the tools its role needs.
  • One trace ID spans the whole run, or you will not be able to explain anything.