cd /news/ai-agents/why-we-stopped-using-llm-agents-to-c… · home topics ai-agents article
[ARTICLE · art-112345] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

Why We Stopped Using LLM Agents to Control LLM Agents (Deterministic Multi-Agent FSM)

Parvej Shah, lead full-stack engineer at Minions.AI, detailed in a blog post why the company replaced an LLM orchestration agent with a deterministic finite state machine (FSM) for its automated content pipeline. The FSM, written in TypeScript, achieved a 99.2% automated completion rate and reduced inference cost variance from ±120% to ±8%, eliminating loop oscillations and context poisoning.

read3 min views1 publishedAug 26, 2026

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.

── more in #ai-agents 4 stories · sorted by recency
── more on @minions.ai 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/why-we-stopped-using…] indexed:0 read:3min 2026-08-26 ·