Skip to content

Agentic AI Orchestration Workflows Take Away

This page collects the design rules and operational lessons that emerged from building and testing the three workflows. The aim is not to generalise beyond what was actually observed, but to make the observed patterns reusable.

  • Guards beat prompts

    Architecture placement determines reliability — not model quality.

  • Keep deterministic things deterministic

    Code nodes for data; LLMs for intent. Not both.

  • Explicit contracts enable reliable pipelines

    Stable JSON interfaces between agents make debugging tractable.

  • Prompt precision reduces failure modes

    Vague instructions produce unpredictable failures, not just vague results.

  • Temperature 0 for structured tasks

    Any variance above 0 is harmful for agents with fixed outputs.

  • No-agent workflows win for API-driven automation

    LLMs add value at the natural-language boundary only.


Architectural lessons

Where you put the guards determines what you can trust

The central lesson from these experiments is simple: the location of the guard determines the reliability of the workflow.

In guarded agentic workflow, guards live in deterministic code nodes after every agent and before every write. In single orchestrator agent, the equivalent constraints exist mostly as prompt instructions inside one agent. The difference is operationally significant. A code node always evaluates the same way for the same input. A prompt instruction can be ignored, misread, or followed inconsistently.

This is why the guarded architecture works: not because the model is more intelligent, but because the architecture assumes the model will eventually misbehave and places deterministic checks exactly where they are needed.

Prompt rules are not architectural guarantees

A prompt can say do not invent IDs, make exactly one MCP call, or never call PATCH in Turn 1. That does not make those things impossible.

The orchestrator implementation demonstrated this clearly. Despite explicit instructions, the agent sometimes invented interface or VLAN IDs, skipped a validation step, or handled a turn incorrectly. Prompt quality matters a great deal, but a prompt is still guidance to a probabilistic model, not an enforcement boundary.

Practical rule: use prompts to improve behaviour, but use deterministic nodes to enforce safety-critical behaviour.

Keep deterministic operations deterministic

The LLM should not be asked to do work that a code node can do exactly.

Array manipulation, deduplication, sorting, rollback payload construction, boolean guard evaluation, approval parsing, and no-op detection all belong in deterministic JavaScript nodes. In the guarded workflow, this significantly reduced the chance of errors propagating downstream. In the orchestrator workflow, the same logic expressed in prompt form was more fragile.

Pattern: let the LLM interpret intent and query tools; let code transform data and decide whether the workflow can proceed.

Agentic contracts make multi-step pipelines reliable

Using explicit JSON contracts between agents and deterministic nodes made the multi-step pipeline easier to reason about, easier to debug, and easier to evolve. The Planner's contract defines exactly what the next node expects. The Verify agent's contract defines exactly what the verification gate consumes.

Once those interfaces are explicit, downstream nodes can be written against stable assumptions rather than defensive parsing of free-form text. That improves both reliability and auditability.

Structured output parsers are a first pass, not a guarantee

n8n's structured output parser is useful, but it is not sufficient by itself.

It helps catch obvious schema violations and can retry when the shape is wrong. However, during testing it still allowed outputs that were structurally valid while being semantically wrong, incomplete, or type-inconsistent. In other cases, attaching a parser to a lookup agent caused looping behaviour.

Practical rule:

  • use structured output parsers where they help
  • never treat them as the final guarantee
  • always follow agent output with deterministic normalisation and validation
The lookup step is the most fragile part of the pipeline

The lookup phase is where small inconsistencies become operational failures. If the wrong interface ID or VLAN ID is produced, the rest of the workflow may still look valid while acting on the wrong object.

This is why the lookup stage in the guarded workflow is split into dedicated agents and then normalised in code. It is also why this stage requires especially tight prompts and especially strict post-processing.

The VLAN VID vs database ID confusion

One of the most important specific lessons is that user-visible VLAN VIDs are not the same thing as NetBox database IDs.

  • the user asks for VLAN 40
  • the interface's tagged_vlans field contains NetBox object IDs
  • the PATCH call also expects NetBox object IDs

Without precise separation of responsibilities, an agent will often confuse these two. It may return 40 as though it were the database ID, or it may inspect the interface's current tagged_vlans list and conclude that only already-present VLANs exist.

Splitting this into a dedicated Lookup VLAN ID agent that queries ipam.vlan directly was one of the most important stabilising decisions in guarded agentic workflow.

The approval token pattern scales without extra infrastructure

Maintaining state across two conversational turns could have been solved with a database node, a static data store, or a session ID. The approach used in the orchestrator — embedding a structured JSON token in the agent's own response and reading it back from conversation history — requires no infrastructure beyond the Memory Buffer already needed for conversation context.

It worked reliably, and the token is human-readable, which makes debugging straightforward.

Single-agent simplicity has a real cost

The 8-node orchestrator workflow is dramatically easier to read, modify, and explain than the 40+ node multi-agent pipeline. Changes to behaviour require only a prompt edit. For rapid iteration and experimentation, this is a significant advantage.

However, the orchestrator's validation logic is invisible in the n8n canvas. When something goes wrong, the only way to understand why is to read the system prompt and infer the agent's reasoning from the conversation log. In the multi-agent guarded workflow, every decision point is a visible node with inspectable inputs and outputs. For teams that need to audit, certify, or hand off automation to others, that visibility matters.

No-agent workflows remain the right answer for API-driven automation

Implementation 1 was the most predictable, the cheapest to run, and the easiest to test. For use cases where the caller is another system — a ticketing platform, a CI/CD pipeline, or an ITSM tool — rather than a human typing into a chat window, a deterministic webhook-triggered workflow is the correct choice.

AI adds value at the natural-language boundary. Once the input is already structured, it adds cost and variance without adding capability.


Writing effective agent prompts

The quality of an agent's behaviour is directly determined by the quality of its prompt. Vague prompts produce vague results, imprecise prompts produce imprecise results, and prompts that leave edge cases unspecified produce unpredictable behaviour on those cases.

The following practices were validated through building and iterating on the agents in these workflows.

Give each agent exactly one job

The more tasks a single agent is asked to perform, the more opportunities it has to make a mistake, and the harder it is to debug when something goes wrong. The Lookup agent makes one MCP call and returns structured data. The Verify agent makes one MCP call and returns a boolean. Each agent has a single, clear responsibility.

Start with a role definition

Begin every system prompt with a concise role statement such as You are a NetBox lookup agent or You are a NetBox verification agent. This helps the model treat the task as a bounded activity rather than an open-ended conversation.

Enumerate steps explicitly and in order

Do not describe what the agent should do only in general prose. List every step as a numbered action.

1. Make exactly ONE MCP call with these exact parameters.
2. If count=0, output this exact JSON and stop.
3. If count>=2, output this exact JSON and stop.
4. If count=1, extract these exact fields and output this exact JSON.

The model follows numbered lists more reliably than broad descriptions, and failures are easier to diagnose afterwards.

Specify failure cases before the happy path

Prompts often describe what the agent should do when everything works. Failure cases are equally important and should be specified first. An agent that is not told what to do on a failure path will often invent an answer.

Use explicit stop conditions

For any step where the agent must not proceed, say so explicitly and literally: STOP on first failure, do NOT proceed to Step 5 or reply ONLY this message and STOP. The word STOP in capitals proved more reliable than softer phrasing.

Constrain tool usage precisely

If an agent should make exactly one MCP call, say Make exactly ONE MCP call, not merely use the MCP tool. Back this up with an iteration limit in the n8n agent node configuration. The prompt constrains intent; the node configuration enforces a practical boundary.

Tell the agent what to ignore, not just what to use

NetBox returns rich objects with many fields, most of which are irrelevant to the task. If the agent is not explicitly told which fields to ignore, it may include them in its output or misinterpret them.

For example:

tagged_vlans is a list of objects. Ignore all fields except id. Extract only the integer id field from each object.

This prevents the agent from including URLs or whole objects where the downstream code node expects an array of integers.

Define the output format exactly, including types

Do not merely say return a JSON object with the results. Provide the exact template, including which fields are integers, strings, arrays, or null.

Output ONLY this JSON (no markdown, no explanation):
{
  "interface_id": <integer or null>,
  "mode": "<string or unknown>",
  "tagged_vlan_ids": [<integers>],
  "error_message": <"string" or null>
}

This reduces quoting mistakes, empty-string versus null inconsistencies, and extra fields that downstream nodes do not expect.

Inject context values directly into the prompt

For agents that operate on specific runtime values — device name, interface name, VLAN VID — inject those values directly into the prompt using n8n expressions rather than expecting the agent to recover them from conversation history.

filters={"device": "{{ $json.params.device }}", "name__ie": "{{ $json.params.interface }}"}

This avoids a class of errors where the agent misremembers or misinterprets an earlier value.

For multi-turn agents, define turn detection explicitly

If an agent behaves differently depending on the conversational turn, provide an explicit detection rule.

Check conversation history. If any previous assistant message contains a line starting with APPROVAL_TOKEN: then this is Turn 2. Otherwise this is Turn 1.

This proved more reliable than asking the model to infer the turn from context.

Iterate on failure, not on intuition

The most effective prompt improvements came from observing actual failures — an agent returning VIDs instead of IDs, adding markdown fences around JSON, or making two MCP calls instead of one — and then adding a specific instruction to address that exact failure.

Prompts refined this way were more reliable than prompts written from scratch to anticipate every imaginable edge case.

Prompt quality is not just about accuracy — it is about failure modes

Loose prompts produce workflows that work most of the time. Precise prompts that explicitly enumerate failure conditions produce workflows that fail predictably and legibly.

Examples that worked better than softer alternatives include:

  • if count=0, reply ONLY this message and STOP
  • NEVER call the PATCH tool in Turn 1
  • make exactly ONE MCP call

The time spent tightening prompt language paid back immediately in reduced debugging effort. Vague instructions do not just produce vague results; they produce unpredictable failure modes that are hard to reproduce and harder to fix.


When to use memory

The decision to use a Memory Buffer node should be deliberate and based on what the agent genuinely needs to know across turns.

The orchestrator agent uses an n8n Memory Buffer with a 20-message window. This is necessary because the orchestrator manages a multi-turn conversation. Turn 1 produces the approval table and embeds the APPROVAL_TOKEN. Turn 2 must read that token back from earlier in the conversation history to know what was proposed and what needs to be executed. Without memory, the two-turn flow breaks.

Memory also lets the orchestrator maintain conversational continuity: the user can refer back to what was said earlier, and the agent can answer follow-up questions without the user repeating themselves.

The agents in the multi-agent guarded pipeline do not use a Memory Buffer. Each agent — Planner, Lookup, Lookup VLAN ID, and Verify — is called with a fresh context and receives only the information it needs for its specific task, injected directly into its prompt via n8n expressions.

This is intentional. Giving these agents access to full conversation history introduces noise. The agent might misread an earlier user message as a current instruction, pick up stale values from a previous run, or become confused by a conversation containing multiple requests.

Situation Use memory? Why
Agent manages a multi-turn conversation ✅ Yes Must recall what it said in earlier turns
Agent needs to answer follow-up questions ✅ Yes Conversational continuity requires history
Agent makes one tool call and returns structured data ❌ No Context adds noise with no benefit
Agent validates or verifies a specific piece of data ❌ No All needed context is injected per invocation
Multiple sequential specialised agents in a pipeline ❌ No Each agent should operate on clean, injected inputs

The general rule is: add memory when the agent needs to refer back to its own prior output or maintain conversational state across turns. Remove it when the agent's job is bounded, single-purpose, and fully specified by its input.


Stability and model behaviour

Neither workflow is 100% stable

Neither the multi-agent guarded workflow nor the single orchestrator agent produces identical results on every run. Under the same conditions with the same user input, agents occasionally misbehave: they may format output differently, make an extra tool call, skip a step, or produce a value that does not match what the prompt specified.

The single orchestrator agent exhibits this instability more frequently than the guarded agentic workflow. Because the orchestrator has no deterministic layer between its reasoning and the write operation, any misbehaviour — including inventing values or calling the PATCH tool in the wrong turn — flows directly into an API call or a wrong result. In guarded agentic workflow, the normalisation, validation, and guard layers absorb most of these failures before they reach a write operation, making the visible failure rate significantly lower even though the underlying LLM behaviour is similarly probabilistic.

This instability is not a bug that can be fully eliminated. It is an inherent property of using LLMs in operational workflows. The practical response is to design the architecture so that instability fails safely — visibly, with a clear error message and no unintended write — rather than silently producing a wrong result. That is precisely what the guarded architecture of guarded agentic workflow achieves.

Set temperature to 0 for every agent except the one handling user intent

Temperature controls how much randomness the model introduces into its output. For agents with a precisely defined task — make this MCP call, return this JSON structure, check this condition — any temperature above 0 is harmful. It introduces variance that the downstream normalisation node then has to recover from: fields formatted differently between runs, values phrased in unexpected ways, or instructions interpreted with slight variations.

The only agent that benefits from a non-zero temperature is the Planner, whose job is to understand free-form natural language from a user. Some flexibility helps there because user requests are naturally varied and unpredictable. All other agents should run at temperature 0, making their behaviour as deterministic as possible given a fixed input.

This applies regardless of model. Even a well-behaved model at temperature 0 will occasionally produce unexpected output, but at least the behaviour is as consistent as the model can be made. Raising temperature above 0 for structured-task agents makes an already probabilistic system more unpredictable for no benefit.

Model choice matters more than model size in this work

Not all models of similar size behave the same way on structured agentic tasks. During testing, qwen2.5:72b consistently outperformed gpt-oss:120b despite the latter being the larger model. The Qwen model followed multi-step prompt instructions more reliably, produced cleaner structured JSON output without requiring retries, handled the orchestrator's two-turn flow with fewer reasoning errors, and was noticeably better at chaining sequential MCP tool calls — a critical capability given that the lookup steps require multiple dependent calls to complete correctly before any write operation can proceed.

At this stage, this observation should remain specific to the models that were actually tested rather than being over-generalised.


Balancing the benefits

The three implementations sit at different points on a spectrum between operational rigour and development velocity.

🔧 No agents 🛡️ Multi-agent guarded 🤖 Single orchestrator
Reliability Highest High Model-dependent
Auditability Full Full Limited
Development speed Slow, many nodes Moderate Fast, prompt-only changes
Maintenance Node edits needed Agent prompts plus guard code Prompt edits only
Best suited for API-driven callers Chat plus operational rigour Chat plus rapid iteration

Neither the guarded nor the orchestrator approach is universally better. Choosing between them requires knowing which dimension of complexity matters most for the team and the operational context. Smaller teams or those exploring the space gain the most from the orchestrator's simplicity; teams with audit obligations or stricter change management requirements will find the guarded pipeline's transparency worth the additional nodes.