Stop Building Super Agents. Build Agent Systems Instead.
The mental model most developers use for AI agents is wrong — and it’s going to cost them in production.
Stop Building Super Agents. Build Agent Systems Instead.
The mental model most developers use for AI agents is wrong — and it’s going to cost them in production.
When most engineers picture an AI agent, they picture something like JARVIS: a single, omniscient system that can read anything, write anywhere, call any API, and reason its way through any problem. Give it a goal, watch it execute.
That mental model is not just wrong. It’s dangerous.
The Hollywood super-agent — one system with unlimited access and open-ended agency — is exactly the architecture you should be designing against. Super-agents are brittle, unpredictable, and almost impossible to secure. The more capable and unconstrained you make a single agent, the harder it becomes to audit what it did, why it did it, and how to stop it from doing something catastrophic.
The right mental model is not a super-agent. It’s a workforce.

Stop Building Super Agents. Build Agent Systems Instead
The Problem with Super Agents
Two failure modes dominate poorly designed agentic systems.
Super agency — the agent can do whatever it decides is necessary. There’s no constraint on the scope of action, no defined boundary between “what this agent should do” and “what it technically could do.”
Over-privilege — even when an agent has a narrow goal, it’s handed credentials that far exceed what the task requires. Read access when it only needs to query. Write access when it only needs to append. Admin credentials passed down as a convenience.
These two failure modes compound each other. A highly capable agent with broad privileges is one reasoning error away from an irreversible action. In a payment system, that means a transaction that shouldn’t have happened. In an infrastructure agent, that means a resource that shouldn’t have been deleted. In a customer data context, that means a record that shouldn’t have been exposed.
The fix isn’t to make agents less capable. It’s to make each agent specifically capable, with minimum necessary access.
The Design Principle: High Cohesion for Agents
Software engineers already have a name for this. It’s called high cohesion — the idea that a module should do one thing, do it well, and contain only what it needs to do that thing.
Applied to agents:
Each agent should have exactly one responsibility, and exactly the access required to fulfill it. Nothing more.
This maps directly to two constraints you should enforce at design time:
- Minimize the action surface — what can this agent do? Read? Write? Delete? Trigger external calls? Every capability you add is a failure mode you’re accepting.
- Minimize the access surface — what can this agent reach? Which systems, which data stores, which APIs? Scope access to the tightest boundary that still lets the agent complete its task.
When you apply these constraints across a workflow, you end up not with one agent doing everything — but a set of agents collaborating, each doing a narrow piece, each with a small footprint.
Categorizing Agents: The Risk-Capability Matrix
Not all agents are created equal, and you shouldn’t treat them as if they are. A useful way to think about agent design is a 2x2 matrix with two axes:
- Risk (low → high): What’s the potential for damage if this agent behaves unexpectedly?
- Capability (low → high): Does this agent need to reason, adapt, and make dynamic decisions — or does it follow a fixed, predetermined path?
LOW RISK HIGH RISK
┌──────────────┬──────────────────┐
HIGH CAPABILITY │ Style Guide │ Accounts │
│ Editor │ Payable Bot │
├──────────────┼──────────────────┤
LOW CAPABILITY │ Internal │ Finance Data │
│ RAG Agent │ Extractor │
└──────────────┴──────────────────┘
Let’s walk through each quadrant.
Low Capability + Low Risk
Example: Internal wiki RAG agent
This agent takes a query, retrieves relevant documents from an internal knowledge base, and returns a summary. It doesn’t reason about what to do next. It doesn’t call external systems. The information it handles is non-sensitive.
This is your simplest case. Traditional, deterministic, low stakes. Persistent credentials are fine. No special controls needed.
High Capability + Low Risk
Example: Style guide editor
This agent reads documents and rewrites them according to tone or style rules. It has more reasoning overhead — it interprets content and makes decisions about how to rewrite it — but the blast radius of a mistake is small. A poorly rewritten paragraph is not a production incident.
The higher capability here means more non-determinism in the reasoning path, but low risk keeps this manageable without heavy controls.
Low Capability + High Risk
Example: Finance data extractor
This agent has read-only access to sensitive financial records. It doesn’t reason about what to do next — it extracts and summarizes on a fixed path. But the data it touches is sensitive, so access must be tightly scoped, audited, and logged.
The key constraint here isn’t capability — it’s privilege. Read-only, scoped to specific tables or time ranges, with full audit trail.
High Capability + High Risk
Example: Accounts payable agent
This is your hardest case. The agent must:
- Parse an invoice
- Identify the vendor
- Determine the correct amount
- Verify approval status
- Initiate a payment transaction
It’s non-deterministic — the reasoning path changes with every invoice. And it’s high risk — it’s writing to financial systems, touching the ledger, moving money.
This quadrant is where most agentic system failures happen. It’s also where the most interesting engineering problems live.
Building for the High-Risk, High-Capability Quadrant
If the bottom-left of the matrix is “treat it like a normal system,” the top-right is “apply every control you have.” Here’s what that looks like in practice.
1. Make High-Capability Agents Ephemeral
An accounts payable agent shouldn’t have a persistent identity that accumulates permissions over time. Spin it up for the task, execute, tear it down. Ephemeral agents have a smaller attack surface, a cleaner audit trail, and no opportunity to accumulate stale credentials.
import boto3
import uuid
def create_ephemeral_agent_session(task_context: dict) -> dict:
"""
Create a short-lived IAM role session scoped to the current agent task.
The session expires after task completion or timeout.
"""
sts = boto3.client('sts')
session_name = f"agent-task-{uuid.uuid4().hex[:8]}"
# Request only the permissions this specific task requires
response = sts.assume_role(
RoleArn=task_context['role_arn'],
RoleSessionName=session_name,
DurationSeconds=900, # 15 minutes max
Policy=task_context['scoped_policy'] # task-specific permission boundary
)
return response['Credentials']
The scoped_policy here is critical — it's not the full role's permissions. It's the minimum subset needed for this specific task invocation.
2. Use Dynamic Access, Not Static Credentials
For low-capability agents, static API keys and persistent credentials are fine. For high-capability agents, access should be evaluated at every step of the reasoning chain, not just at initialization.
This means your agent runtime needs to answer: “Given where the agent is right now in its reasoning process, is it allowed to take this next action?”
from dataclasses import dataclass
from typing import Callable
@dataclass
class AccessPolicy:
allowed_tools: list[str]
allowed_operations: list[str] # ["read", "write"] — never "delete" by default
max_transaction_value: float | None = None
def evaluate_action(
proposed_action: dict,
current_context: dict,
policy: AccessPolicy
) -> bool:
"""
Evaluate whether an agent action is permitted given current context.
Called before every tool invocation in the reasoning loop.
"""
tool = proposed_action.get('tool')
operation = proposed_action.get('operation')
if tool not in policy.allowed_tools:
raise PermissionError(f"Tool '{tool}' not permitted in current context")
if operation not in policy.allowed_operations:
raise PermissionError(f"Operation '{operation}' not permitted")
# For financial actions, check value limits
if policy.max_transaction_value and tool == 'payment_api':
amount = proposed_action.get('amount', 0)
if amount > policy.max_transaction_value:
return False # Escalate to human review
return True
Every tool call goes through evaluate_action. The policy is not global — it's constructed from the task context at runtime.
3. Put a Human in the Loop
For high-risk actions, don’t let the agent be the final decision-maker. Build explicit human approval gates before irreversible actions execute.
import asyncio
async def request_human_approval(
action_summary: str,
approver_id: str,
timeout_seconds: int = 300
) -> bool:
"""
Pause agent execution and request human approval.
Times out and raises if no response within window.
"""
# Send approval request via your notification system
approval_id = await send_approval_request(
approver=approver_id,
action=action_summary,
expires_in=timeout_seconds
)
# Poll for decision
deadline = asyncio.get_event_loop().time() + timeout_seconds
while asyncio.get_event_loop().time() < deadline:
decision = await check_approval_status(approval_id)
if decision == 'approved':
return True
if decision == 'rejected':
return False
await asyncio.sleep(5)
raise TimeoutError("Human approval window expired — action blocked")
# Usage inside the accounts payable agent
async def process_payment(invoice: dict, policy: AccessPolicy):
payment_details = await extract_payment_details(invoice)
if payment_details['amount'] > policy.max_transaction_value:
approved = await request_human_approval(
action_summary=f"Pay ${payment_details['amount']} to {payment_details['vendor']}",
approver_id=policy.approver_id
)
if not approved:
return {"status": "rejected", "reason": "human_override"}
return await initiate_payment(payment_details)
The human-in-the-loop isn’t just a safety feature. It’s an architectural decision that tells you something important: this action is consequential enough that it shouldn’t be autonomous. Design that boundary explicitly, not as an afterthought.
Composing Multi-Agent Systems
Once you’ve categorized your agents and scoped their access, the question becomes: how do they work together?
The answer is orchestration — but not an orchestrator that assigns unlimited tasks to a single capable agent. Instead, a routing layer that delegates subtasks to appropriately scoped agents and aggregates their outputs.

Composing Multi-Agent Systems
Each agent in this system is independently deployable, independently auditable, and independently scoped. The orchestrator doesn’t need to know about payment systems — that’s the AP agent’s concern. The AP agent doesn’t need access to the wiki — that’s the RAG agent’s concern.
Common Mistakes to Avoid
Giving every agent the same credentials. This is the easiest shortcut and the most dangerous one. Scoped credentials are not optional for production agentic systems.
Making agents too long-lived. An agent that stays running accumulates context, and potentially stale permissions. For high-capability agents especially, shorter lifetimes mean less blast radius.
Skipping the human gate on financial or destructive actions. The instinct is to automate everything. The right instinct is to identify which actions are irreversible, and make those approval-gated by default.
Treating the orchestrator as the agent. The orchestrator should route and aggregate. If your orchestrator is also reasoning about invoices and making payment decisions, you’ve rebuilt the super-agent inside a wrapper.
Conflating capability with risk. A highly capable agent isn’t necessarily high risk. A low-capability agent accessing sensitive data absolutely is. Risk and capability are independent axes — treat them that way.
Key Takeaways
- Avoid super-agents. The single omniscient agent is a liability, not an asset.
- Design for high cohesion. Each agent does one thing, with minimum necessary access.
- Use the risk-capability matrix to determine how to treat each agent: how it’s deployed, how access is managed, what controls apply.
- High-capability, high-risk agents need ephemeral identities, dynamic access evaluation, and human approval gates.
- Low-capability, low-risk agents can use traditional access patterns — the complexity overhead isn’t worth it.
- The orchestrator routes. It doesn’t reason about domain problems. Keep that separation clean.
The shift from “one agent that does everything” to “a system of agents that collaborate” isn’t just a safety improvement. It’s also better software engineering. Narrow scope means easier testing, clearer auditing, and faster iteration on individual components.
Build agents the same way you’d build microservices: small, focused, independently deployable, and scoped to the minimum access they need to do their job.
Building a multi-agent system and want to discuss the architecture? Leave a comment — always happy to go deeper on orchestration patterns, access control, or specific tooling.
메타데이터
- post_id
- b4bf23e7d1be
- slug
- stop-building-super-agents-build-agent-systems-instead-b4bf23e7d1be
- url
- https://medium.com/@ramkumar.harish/stop-building-super-agents-build-agent-systems-instead-b4bf23e7d1be
- canonical_url
- https://medium.com/@ramkumar.harish/stop-building-super-agents-build-agent-systems-instead-b4bf23e7d1be
- author_url
- https://medium.com/@ramkumar.harish
- status
- ok
- fetched_at
- 2026-06-22 05:41:33