Modular or Merely Split? Designing AI Agents That Survive Their Second Quarter
The most expensive AI agent in your organization isn't the one throwing errors. It's the one that works, and that nobody wants to touch.
Errors get fixed because they are loud. The quieter failure looks like this: six months after launch, the same formatting logic lives in three places and two of them have been edited since. A project key is hard-coded into a workflow, a topic, and a tool description. Someone asks which version production is running, and the honest answer is a shrug. A one-line change to one topic needs regression testing against four others because they share undocumented dependencies.
None of that is a bug. Every component passes its tests. The organization of the system is what failed, and you pay for it in hesitation instead of error messages. To solve this, teams must prioritize modular AI agent design during the initial architecture phase.
This post comes out of graduate coursework in enterprise AI agent orchestration, where I'm building one multi-agent system that grows week by week. Last time I split a helpdesk agent into a root agent and an escalation specialist. This week's question was harder: was that split actually modular, or did I just cut it in two?
I graded my own work. It didn't do as well as I'd hoped.
A module has to earn its boundary
A reusable module needs all four of these properties. Three out of four doesn't count toward effective modular AI agent design.
- A coherent capability. You can name what it does without describing the system around it. "Urgency assessment" is a capability. "Step four of the escalation topic" is not.
- A clear responsibility. It owns the work end to end. If a caller has to clean up afterward, or sometimes skips the module and does the job itself, the responsibility isn't clear.
- Defined inputs and outputs. Named values in, a predictable shape out, and the part everyone skips: a stated result for when the work can't be done. If only the happy path is documented, every caller invents its own guess about the rest.
- Limited dependence. It doesn't borrow conversation state it wasn't given, rely on a variable someone else set, or assume a step ran before it. A module that needs its old neighbors isn't portable. It has just moved.
The fastest diagnostic I know for ai agent lifecycle management is the second-caller test: what would it cost a second, unrelated caller to use this? If the answer is "a rewrite," you have a piece, not a module.
| Dimension | Genuinely modular | Merely split |
|---|---|---|
| Boundary | Drawn around a capability | Drawn where the thing got long |
| Responsibility | Owned end to end | Shared with the caller |
| Interface | Named inputs and outputs | Whatever happened to be in scope |
| Dependence | Runs without its neighbors | Needs its old neighbors |
| Reuse | Second caller costs little | Second caller costs a rewrite |
| Change | Evolves behind its interface | Ripples back to every caller |
Grading my own split
My system has a Helpdesk agent that handles password-reset conversations. When troubleshooting fails, it hands off to an Escalation Agent, which collects details, has a model summarize the issue, runs a workflow that classifies urgency, creates a Trello ticket, emails the user, and returns a ticket ID.
It works end to end. Here's how it scores against modular AI agent design principles:
| Property | Verdict | Evidence |
|---|---|---|
| Coherent capability | Partial | "Create a support ticket" is a real capability, but the agent's description says it's for when a password reset wasn't resolved. That's a caller's situation, not the capability. |
| Clear responsibility | Pass | It owns ticket creation fully. The Helpdesk never touches Trello. |
| Defined inputs and outputs | Partial | A ticket ID comes back on success. There's no stated result for failure, so a failed ticket looks the same as a slow one. |
| Limited dependence | Fail | The user's email, already collected by the Helpdesk, doesn't cross the boundary, so the specialist asks for it again. The board, list, and sending mailbox are fixed inside the workflow. |
Consider the second-caller test: if a facilities bot or an HR agent wanted to file a ticket tomorrow, it would be routed by a description mentioning passwords, it would re-interview the user for their email, and it could only write to one specific board. That requires a rewrite, not a simple configuration change.
So the honest answer: I drew the boundary in roughly the right place, but I hadn't earned it. I split the system without making it modular.
The redesign
The fix isn't another agent. It's a tighter contract:
- In: a self-contained payload with summary, requester email, source system, and optional urgency hint. The caller passes what it already knows, and nobody gets asked twice.
- Out: a ticket ID and urgency on success, or an explicit failure with a reason. Callers never have to guess.
- Description: "Creates a support ticket from a complete request," with no mention of passwords.
- Configuration: board, list, and mailbox move out of the workflow and into named variables (more on that next).
Each change shrinks what the module has to know about its surroundings. That's what coupling means, and lowering it is the point of all four properties in modular AI agent design.
Configuration: the least glamorous fix that saves the most
Some values have to differ between environments: project keys, mailbox addresses, endpoints, thresholds, queue names. The values are fine. The problem is where they get written down.
The default behavior is to type the value into whichever component needs it, then into the second one, and by the third nobody remembers the first two. Then promotion to production means opening the thing you tested and editing it. What runs in production is no longer what you validated, and test and production drift apart while everyone thinks they match.
The alternative is an environment variable: a named value resolved at runtime. The component references the name, and the environment supplies the value. Microsoft's copilot studio alm guidance says the same thing: use environment variables for settings that change across environments, and ship agents inside solutions. In that platform, makers can't even edit environment variables from inside the agent. They're set in Power Apps, which is a useful guardrail for ai agent lifecycle management.
There's a governance benefit too. A reviewer can inspect a named value without reading a prompt to find it.
The unit of deployment is the solution, not the agent
In mature enterprise ai orchestration, agents, workflows, variables, and knowledge sources depend on each other, so they should move together as one package, with a manifest that lists what's inside and what it depends on. Ship an agent that calls a workflow that didn't travel with it, and you've shipped a broken system that shows no symptom until someone takes that path.
Then establish rigorous ai agent versioning for the package. The operational question isn't "What does production do?" It's:
Which version is production running, and can we go back?
A team that cannot identify the production version cannot effectively investigate an incident. A team that cannot roll back has only one recovery option: push forward. Doing so under pressure is a recipe for further failure.
A "version" of an agent means its behavior, not just its code
This is where agents differ from ordinary software. Behavior depends on the prompt, the model and its settings, tool definitions, guardrails, and knowledge content, and Git usually captures only some of those. Fruxon's glossary argues that ai agent versioning should be an immutable snapshot of all of it, so "version 12" means the same thing forever and you can diff 12 against 11 when something regresses.
I saw this on a small scale in my own build. The same password-reset request came back rated High urgency on one run and Medium on another, because the summary is regenerated each time and the classifier judges what it gets. Nothing in the code changed. If I swapped the model or rewrote the summary prompt, ticket priorities would shift across the board, and no code diff would show why.
Agent Opz makes the practical point well: a prompt change is a deployment. It needs the same versioning, staged rollout, and rollback plan as a code change. Agent regressions also tend to be subtle (slightly worse output, slightly higher cost) rather than loud crashes. That makes the safety net more important for ai agent lifecycle management than for traditional services, not less.
One package, three environments, zero edits
Build in Develop against sample data, where breaking things is free. Promote the same package to Test, where it runs with realistic configuration and gets signed off. Promote it again to Production, where nothing is edited on the way in, the version is recorded, and the previous one stays deployable. Following copilot studio alm patterns ensures that these transitions are predictable.
This path is a process, and it's also a design check:
If promotion requires an edit, the thing you're promoting was never properly configured.
Every value you change by hand at a gate belonged in a variable. Every component you have to open at a gate has a boundary that wasn't clean.
Evolving without breaking callers
The promise of modularity is that pieces evolve independently. That doesn't happen automatically. You keep the promise on purpose.
- Write down dependencies. Variables, connections, knowledge sources, other modules. The dependency nobody recorded is the one that fails at promotion, in the environment where you have the least room to debug.
- Add before you remove. New optional inputs and extra outputs are safe. Renaming a field, making an optional input required, or changing what failure looks like breaks callers, and usually quietly.
- Version the contract. When a breaking change is unavoidable, publish it alongside the old one and let callers migrate on their own schedule, not yours.
- Know what can't roll back. Auxiliobits makes a point that's easy to miss: once an agent has filed tickets, sent emails, or posted transactions, rolling back the code doesn't undo those actions. For agents with real side effects, plan to roll forward and make sure actions are safe to retry.
A module that can't change isn't stable. It's stuck.
Six questions for your next agent design review
- Can you name each module's capability without mentioning who calls it?
- What does each module return when it can't do the job?
- Does any module ask the user for something its caller already knew?
- Would a second caller cost a configuration change or a rewrite?
- Can you say which version production is running, and redeploy the previous one today?
- Did your last promotion require opening and editing anything?
If question 6 gets a yes, start there. That edit tells you exactly what to fix.
What's next
The next phase of my build turns this into practice within the context of enterprise ai orchestration. I'll ground the specialist in an access policy that only it can see (a module-boundary decision), add an Outlook MCP server with a deliberately constrained tool description, move the ticketing project key and support mailbox into environment variables, and package the whole system as a versioned solution, tested alone and then integrated.
The sentence I'm keeping from this week: modular AI agent design is a property you design, not a count of parts. Five agents that all need each other are harder to run than one agent. Two agents with a clean contract between them can each keep improving for years.
If your team is working through how to structure, package, or promote agent systems, I'm glad to compare notes.
References
- Microsoft Learn, Application lifecycle management for Copilot Studio
- Microsoft Learn, Work with variables in Copilot Studio (environment variables)
- Microsoft Learn, Environment variables overview
- Microsoft Learn, ALM overview for Power Platform
- Microsoft MCS Labs, Application Lifecycle Management in Copilot Studio
- Fruxon, What is AI agent versioning?
- Auxiliobits, Versioning and rollbacks in modern agent deployments
- Agent Opz, Deployment strategies for AI agents: blue-green, canary, and prompt versioning
- Acacia Tech Group, From One Agent to a Coordinated System: A Helpdesk Escalation Build
