Originally published at[parvejshah.com/blog/deterministic-multi-agent-systems-production]by[Parvej Shah].
The standard architecture pattern for multi-agent systems right now is an orchestration agent: a central LLM that receives a goal, decides which specialized agents to invoke, passes messages between them, and decides when the task is complete.
In early 2025, we built this exact pattern for Minions.AI's automated technical content pipeline. An orchestrator LLM coordinated a research agent, a draft writer, a critic agent, and a formatting specialist.
It worked in 70% of runs. In the other 30%, it failed in creative, unpredictable ways.
The failure modes weren't bugs in the traditional sense. The individual prompts were well-engineered. The tool definitions were clean. The failures came from the non-deterministic nature of the control plane.
Loop oscillation. The critic agent would reject a draft for lacking specific technical details. The writer agent would add details, but slightly change the tone. The critic agent would then reject the new draft for tone issues, causing the writer to revert the details. The orchestrator would watch this tennis match loop until hitting the maximum turn limit.
Context poisoning. As agents passed conversational turns back and forth, the shared context window accumulated conversational residue — conversational filler, apologies, retry explanations. By turn 6, 40% of the token budget was spent on orchestration chatter rather than the actual task domain.
Non-deterministic convergence. The same topic with the same source signals would sometimes produce a crisp, 1,200-word technical deep dive in 4 turns, and other times produce a rambling 3,000-word overview in 14 turns costing 4x the inference budget.
The fix was conceptually simple: remove all control flow decisions from LLMs and put them in typed code.
LLMs are exceptional at content transformation, extraction, synthesis, and evaluation against specific criteria. They are terrible at state machine transitions, termination detection, and error routing.
We redesigned the multi-agent pipeline as a formal Finite State Machine (FSM) written in TypeScript:
type PipelineState =
| "HARVEST_SIGNALS"
| "DRAFT_CONTENT"
| "CRITIC_REVIEW"
| "REVISE_DRAFT"
| "STAGE_CMS"
| "FAILED";
interface PipelineContext {
topicId: string;
signals: IndustrySignal[];
draftMarkdown?: string;
critique?: CritiqueResult;
revisionCount: number;
maxRevisions: 2; // Strict deterministic limit
}
export async function runContentPipeline(
ctx: PipelineContext
): Promise<PipelineState> {
let state: PipelineState = "HARVEST_SIGNALS";
while (state !== "STAGE_CMS" && state !== "FAILED") {
switch (state) {
case "HARVEST_SIGNALS":
ctx.signals = await signalHarvesterAgent(ctx.topicId);
state = ctx.signals.length > 0 ? "DRAFT_CONTENT" : "FAILED";
break;
case "DRAFT_CONTENT":
ctx.draftMarkdown = await draftingAgent(ctx.signals);
state = "CRITIC_REVIEW";
break;
case "CRITIC_REVIEW":
ctx.critique = await criticAgent(ctx.draftMarkdown!);
if (ctx.critique.score >= 85) {
state = "STAGE_CMS";
} else if (ctx.revisionCount < ctx.maxRevisions) {
ctx.revisionCount++;
state = "REVISE_DRAFT";
} else {
// Hard exit: escalate to human editor rather than infinite loop
state = "FAILED";
}
break;
case "REVISE_DRAFT":
ctx.draftMarkdown = await revisionAgent(
ctx.draftMarkdown!,
ctx.critique!.actionableFixes
);
state = "CRITIC_REVIEW";
break;
}
}
return state;
}
The deterministic FSM pipeline has processed hundreds of scheduled content runs for Minions.AI with a 99.2% automated completion rate and zero loop oscillations. Inference cost variance dropped from ±120% to ±8%.
Parvej Shah is a Lead Full-Stack Web Developer & Platform Architect based in Dhaka, Bangladesh. Explore full architecture case studies and production code at parvejshah.com.