# Don't Build an Agent. Build the Agent Factory.

Anyone can build an AI agent in a weekend. A good model, a few tools, a decent system prompt — and you have a demo that impresses in Monday's meeting. I've already written about [the difference between a model and an agent](/en/blog/ai-model-vs-agent) and about [what agents look like in production](/en/blog/ai-agents-2026), so I won't repeat that part.

The real problem shows up at the second question, the one the weekend demo never touches: what happens when **ten teams** each want their own agent? Each with access to the CRM, to tickets, to databases. Each with their own API keys, their own prompts, their own idea of what "it works" means. Without an answer to that question you get what I now see in many companies: a pile of pilot agents that never reach production, because nobody can say who is allowed to touch what, how well anything actually performs, and what breaks on the next release.

The answer to it isn't "one more agent" — it's an **agent architecture**: the internal factory through which any team can ship governed, tested agents with controlled access to company systems. This article walks through the four pieces of that architecture and why you need each one.

## The two layers

First clarification, because this is where most discussions get tangled: the agent the user sees and the platform underneath are different layers with different problems.

The application layer is what you build for one concrete use case: orchestration with sub-agents, RAG over the relevant documents, approval gates where a human validates sensitive actions. It's the layer we build in client projects too, and the one 95% of agent articles are about.

The platform layer is what makes the **second, fifth and tenth** agent not start from zero. It answers three questions the application can't solve on its own: who is allowed to reach which system, how good an agent is before you ship it, and how team B finds out that team A's agent already exists.

<div class="article-figure">
<svg viewBox="0 0 900 470" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Two-layer architecture: the application layer with sub-agents, application RAG and approval gates, above the platform layer with catalog and evaluations, gateway, MCP servers and shared RAG, which sits in front of the company's systems">
<text x="10" y="22" fill="#eef2ff" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="15px" font-weight="600" text-anchor="start">Two layers: the agent and the factory</text>
<rect x="10" y="40" width="880" height="120" rx="12" fill="#181d27" stroke="#2a3147" stroke-width="1"/>
<text x="30" y="66" fill="#7b8cff" font-family="DM Mono, ui-monospace, monospace" font-size="12px" font-weight="600" text-anchor="start">APPLICATION LAYER — what the user sees</text>
<rect x="30" y="82" width="270" height="60" rx="8" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="165" y="108" fill="#eef2ff" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13.5px" font-weight="600" text-anchor="middle">Sub-agents</text>
<text x="165" y="127" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">task orchestration</text>
<rect x="315" y="82" width="270" height="60" rx="8" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="450" y="108" fill="#eef2ff" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13.5px" font-weight="600" text-anchor="middle">Application RAG</text>
<text x="450" y="127" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">answers from documents</text>
<rect x="600" y="82" width="270" height="60" rx="8" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="735" y="108" fill="#eef2ff" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13.5px" font-weight="600" text-anchor="middle">Approval gates</text>
<text x="735" y="127" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">a human validates actions</text>
<line x1="450" y1="160" x2="450" y2="186" stroke="#6b7a99" stroke-width="1.5"/>
<polygon points="450,196 444,184 456,184" fill="#6b7a99"/>
<rect x="10" y="196" width="880" height="150" rx="12" fill="#181d27" stroke="#4fffb0" stroke-opacity="0.4" stroke-width="1"/>
<text x="30" y="222" fill="#4fffb0" font-family="DM Mono, ui-monospace, monospace" font-size="12px" font-weight="600" text-anchor="start">PLATFORM LAYER — the agent factory</text>
<rect x="30" y="238" width="200" height="88" rx="8" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="130" y="266" fill="#eef2ff" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13.5px" font-weight="600" text-anchor="middle">Catalog + Evals</text>
<text x="130" y="286" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">registry, scores,</text>
<text x="130" y="302" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">regressions per release</text>
<rect x="250" y="238" width="200" height="88" rx="8" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="350" y="266" fill="#eef2ff" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13.5px" font-weight="600" text-anchor="middle">Gateway</text>
<text x="350" y="286" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">auth, rate limiting,</text>
<text x="350" y="302" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">centralized logging</text>
<rect x="470" y="238" width="200" height="88" rx="8" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="570" y="266" fill="#eef2ff" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13.5px" font-weight="600" text-anchor="middle">MCP servers</text>
<text x="570" y="286" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">tools and data exposed</text>
<text x="570" y="302" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">through a standard protocol</text>
<rect x="690" y="238" width="180" height="88" rx="8" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="780" y="266" fill="#eef2ff" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13.5px" font-weight="600" text-anchor="middle">Shared RAG</text>
<text x="780" y="286" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">ingestion and retrieval</text>
<text x="780" y="302" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">for every team</text>
<line x1="450" y1="346" x2="450" y2="372" stroke="#6b7a99" stroke-width="1.5"/>
<polygon points="450,382 444,370 456,370" fill="#6b7a99"/>
<rect x="10" y="382" width="880" height="52" rx="12" fill="#181d27" stroke="#2a3147" stroke-width="1"/>
<text x="450" y="413" fill="#c8d3e8" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13px" font-weight="400" text-anchor="middle">Company systems: CRM · tickets · documents · databases · internal APIs</text>
<text x="10" y="460" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="12px" font-weight="400" text-anchor="start">Teams build on top. The platform guarantees the bottom: access, quality, visibility.</text>
</svg>
</div>

The rest of the article takes the bottom layer apart piece by piece.

## The agent catalog: registry plus evaluations, not a wiki

The first piece sounds mundane and is the most underrated: an **internal agent registry**. Every agent has an entry with a description, the tools it can reach, the owning team and the current version. Teams check it before building something new — exactly like a service registry or an internal API catalog.

| Field | Example |
|---|---|
| Name | `support-triage-agent` |
| Description | Triages support tickets and proposes a reply |
| Owner | Customer Platform team |
| Version | 1.4.2 |
| Tools (via gateway) | `crm.search` · `tickets.update` · `kb.retrieve` |
| Eval scores | quality 92 · correctness 96 · safety 100 |
| Last regression run | passed · August 27, 2026 |

The difference between this and a wiki is the last two rows. A catalog without evaluations is a list of promises; a catalog with evaluations is a contract. Every agent comes with **test sets** — real input scenarios with expected outcomes — and scores along three axes: quality (how useful the answers are), correctness (how many claims are factually true, how many actions are the right ones) and safety (it refuses what it must refuse, doesn't leak data between customers, doesn't act outside its mandate).

The rule that ties it all together: **you don't publish a new version to the catalog unless it passes the evaluations.** Including — especially — the old suite. An agent that solves one new case at v1.4 but breaks three cases that worked at v1.3 does not ship. That's CI/CD, applied to agents:

<div class="article-figure">
<svg viewBox="0 0 900 310" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Release pipeline for agents: a new version runs through evaluations and thresholds; if it passes it is published to the catalog, if it fails it is blocked; every release also re-runs the old suite as a regression check">
<text x="10" y="22" fill="#eef2ff" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="15px" font-weight="600" text-anchor="start">CI/CD for agents: nothing enters the catalog without evals</text>
<rect x="10" y="58" width="190" height="96" rx="10" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="105" y="100" fill="#eef2ff" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13.5px" font-weight="600" text-anchor="middle">New version</text>
<text x="105" y="121" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">v1.4 of the support agent</text>
<line x1="200" y1="106" x2="230" y2="106" stroke="#6b7a99" stroke-width="1.5"/>
<polygon points="240,106 228,100 228,112" fill="#6b7a99"/>
<rect x="240" y="58" width="210" height="96" rx="10" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="345" y="94" fill="#eef2ff" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13.5px" font-weight="600" text-anchor="middle">Evaluations</text>
<text x="345" y="114" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">test sets,</text>
<text x="345" y="130" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">LLM-as-judge</text>
<line x1="450" y1="106" x2="480" y2="106" stroke="#6b7a99" stroke-width="1.5"/>
<polygon points="490,106 478,100 478,112" fill="#6b7a99"/>
<rect x="490" y="58" width="200" height="96" rx="10" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="590" y="94" fill="#eef2ff" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13.5px" font-weight="600" text-anchor="middle">Thresholds</text>
<text x="590" y="114" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">quality · correctness</text>
<text x="590" y="130" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">safety · no regressions</text>
<line x1="690" y1="88" x2="722" y2="76" stroke="#4fffb0" stroke-opacity="0.7" stroke-width="1.5"/>
<polygon points="732,72 719,71 723,82" fill="#4fffb0" fill-opacity="0.8"/>
<line x1="690" y1="124" x2="722" y2="136" stroke="#ff6b6b" stroke-opacity="0.7" stroke-width="1.5"/>
<polygon points="732,140 723,130 719,141" fill="#ff6b6b" fill-opacity="0.8"/>
<rect x="732" y="46" width="158" height="52" rx="10" fill="#181d27" stroke="#4fffb0" stroke-opacity="0.5" stroke-width="1"/>
<text x="811" y="68" fill="#4fffb0" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13px" font-weight="600" text-anchor="middle">✓ Published to catalog</text>
<text x="811" y="87" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">visible to every team</text>
<rect x="732" y="114" width="158" height="52" rx="10" fill="#181d27" stroke="#ff6b6b" stroke-opacity="0.5" stroke-width="1"/>
<text x="811" y="136" fill="#ff6b6b" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13px" font-weight="600" text-anchor="middle">✗ Blocked</text>
<text x="811" y="155" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">back to development</text>
<path d="M 811 166 L 811 216 L 345 216 L 345 164" fill="none" stroke="#6b7a99" stroke-width="1" stroke-dasharray="5 4"/>
<polygon points="345,156 339,168 351,168" fill="#6b7a99"/>
<text x="578" y="236" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="12px" font-weight="400" text-anchor="middle">on every version, the entire old suite runs again — regressions block the release</text>
<text x="10" y="290" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="12px" font-weight="400" text-anchor="start">Exactly like code: build → tests → gate. Except the “tests” are scored evaluations, not binary asserts.</text>
</svg>
</div>

The non-deterministic part is the only genuinely new thing. A code test is binary; an agent answer is "good enough" or not. That's why evaluations combine exact checks (did it call the right tool? did it respect the format?) with **LLM-as-judge** — a model that scores the answer against a rubric written by humans. Not perfect, but consistent, cheap, and it runs on every release, which a human review cannot.

On AWS this piece exists as a service — the evaluations in Amazon Bedrock AgentCore — but it builds just as well as your own pipeline: a set of scenarios in git, a job that runs the agent through them, and a judge that scores. The gate is what matters, not the tool.

## The gateway: one place through which agents touch the world

The second piece solves an arithmetic problem. Three agents talking directly to five systems means fifteen integrations: fifteen places managing credentials, fifteen places to audit, fifteen implementations of rate limiting — usually zero. Every new agent multiplies the problem.

The gateway turns N × M into N + M: agents talk to a single layer, and that layer knows **who is allowed to reach what**.

<div class="article-figure">
<svg viewBox="0 0 900 400" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Comparison: without a gateway, three agents connect directly to five systems through fifteen integrations; with a gateway, agents talk to a single layer that centralizes authentication, authorization, rate limiting and logging">
<text x="10" y="22" fill="#eef2ff" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="15px" font-weight="600" text-anchor="start">Without a gateway vs. with a gateway</text>
<rect x="10" y="40" width="430" height="310" rx="12" fill="#181d27" stroke="#ff6b6b" stroke-opacity="0.35" stroke-width="1"/>
<text x="30" y="68" fill="#ff6b6b" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13.5px" font-weight="600" text-anchor="start">No gateway: N × M connections</text>
<text x="225" y="98" fill="#c8d3e8" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="12px" font-weight="400" text-anchor="middle">agents</text>
<line x1="105" y1="134" x2="79" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<line x1="105" y1="134" x2="157" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<line x1="105" y1="134" x2="235" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<line x1="105" y1="134" x2="313" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<line x1="105" y1="134" x2="391" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<line x1="225" y1="134" x2="79" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<line x1="225" y1="134" x2="157" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<line x1="225" y1="134" x2="235" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<line x1="225" y1="134" x2="313" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<line x1="225" y1="134" x2="391" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<line x1="345" y1="134" x2="79" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<line x1="345" y1="134" x2="157" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<line x1="345" y1="134" x2="235" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<line x1="345" y1="134" x2="313" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<line x1="345" y1="134" x2="391" y2="270" stroke="#ff6b6b" stroke-opacity="0.3" stroke-width="1"/>
<circle cx="105" cy="120" r="14" fill="#7b8cff" fill-opacity="0.85"/>
<circle cx="225" cy="120" r="14" fill="#7b8cff" fill-opacity="0.85"/>
<circle cx="345" cy="120" r="14" fill="#7b8cff" fill-opacity="0.85"/>
<rect x="47" y="270" width="64" height="34" rx="6" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="79" y="291" fill="#c8d3e8" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11px" font-weight="400" text-anchor="middle">CRM</text>
<rect x="125" y="270" width="64" height="34" rx="6" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="157" y="291" fill="#c8d3e8" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11px" font-weight="400" text-anchor="middle">Tickets</text>
<rect x="203" y="270" width="64" height="34" rx="6" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="235" y="291" fill="#c8d3e8" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11px" font-weight="400" text-anchor="middle">Docs</text>
<rect x="281" y="270" width="64" height="34" rx="6" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="313" y="291" fill="#c8d3e8" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11px" font-weight="400" text-anchor="middle">DB</text>
<rect x="359" y="270" width="64" height="34" rx="6" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="391" y="291" fill="#c8d3e8" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11px" font-weight="400" text-anchor="middle">Lambda</text>
<text x="225" y="334" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="12px" font-weight="400" text-anchor="middle">15 integrations · credentials everywhere · audit impossible</text>
<rect x="460" y="40" width="430" height="310" rx="12" fill="#181d27" stroke="#4fffb0" stroke-opacity="0.35" stroke-width="1"/>
<text x="480" y="68" fill="#4fffb0" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="13.5px" font-weight="600" text-anchor="start">With a gateway: N + M connections</text>
<text x="675" y="98" fill="#c8d3e8" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="12px" font-weight="400" text-anchor="middle">agents</text>
<circle cx="555" cy="120" r="14" fill="#7b8cff" fill-opacity="0.85"/>
<circle cx="675" cy="120" r="14" fill="#7b8cff" fill-opacity="0.85"/>
<circle cx="795" cy="120" r="14" fill="#7b8cff" fill-opacity="0.85"/>
<line x1="555" y1="134" x2="601" y2="168" stroke="#4fffb0" stroke-opacity="0.5" stroke-width="1"/>
<line x1="675" y1="134" x2="675" y2="168" stroke="#4fffb0" stroke-opacity="0.5" stroke-width="1"/>
<line x1="795" y1="134" x2="749" y2="168" stroke="#4fffb0" stroke-opacity="0.5" stroke-width="1"/>
<rect x="520" y="168" width="310" height="64" rx="8" fill="#1e2535" stroke="#4fffb0" stroke-opacity="0.5" stroke-width="1"/>
<text x="675" y="194" fill="#4fffb0" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="14px" font-weight="600" text-anchor="middle">Gateway</text>
<text x="675" y="214" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11.5px" font-weight="400" text-anchor="middle">authentication · authorization · rate limiting · logging</text>
<line x1="529" y1="232" x2="529" y2="270" stroke="#4fffb0" stroke-opacity="0.5" stroke-width="1"/>
<line x1="607" y1="232" x2="607" y2="270" stroke="#4fffb0" stroke-opacity="0.5" stroke-width="1"/>
<line x1="685" y1="232" x2="685" y2="270" stroke="#4fffb0" stroke-opacity="0.5" stroke-width="1"/>
<line x1="763" y1="232" x2="763" y2="270" stroke="#4fffb0" stroke-opacity="0.5" stroke-width="1"/>
<line x1="830" y1="232" x2="841" y2="270" stroke="#4fffb0" stroke-opacity="0.5" stroke-width="1"/>
<rect x="497" y="270" width="64" height="34" rx="6" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="529" y="291" fill="#c8d3e8" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11px" font-weight="400" text-anchor="middle">CRM</text>
<rect x="575" y="270" width="64" height="34" rx="6" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="607" y="291" fill="#c8d3e8" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11px" font-weight="400" text-anchor="middle">Tickets</text>
<rect x="653" y="270" width="64" height="34" rx="6" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="685" y="291" fill="#c8d3e8" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11px" font-weight="400" text-anchor="middle">Docs</text>
<rect x="731" y="270" width="64" height="34" rx="6" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="763" y="291" fill="#c8d3e8" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11px" font-weight="400" text-anchor="middle">DB</text>
<rect x="809" y="270" width="64" height="34" rx="6" fill="#1e2535" stroke="#2a3147" stroke-width="1"/>
<text x="841" y="291" fill="#c8d3e8" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="11px" font-weight="400" text-anchor="middle">Lambda</text>
<text x="675" y="334" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="12px" font-weight="400" text-anchor="middle">8 connections · one point of control and audit</text>
<text x="10" y="384" fill="#6b7a99" font-family="DM Sans, system-ui, -apple-system, sans-serif" font-size="12px" font-weight="400" text-anchor="start">Bonus: an existing API (REST, Lambda) becomes an MCP tool at the gateway level, without a rewrite.</text>
</svg>
</div>

Concretely, the gateway centralizes four things that every team would otherwise reimplement badly and differently: **authentication** (agents get identities, not API keys pasted into prompts), **authorization** (the support agent sees tickets, not salaries), **rate limiting** (an agent stuck in a loop doesn't bring the CRM to its knees) and **logging** (every tool call, with the agent's identity attached — the only way you'll ever answer "who changed this record?").

Its second function is less obvious but enormous in practice: the gateway **translates existing APIs into MCP tools without rewriting them**. You have an internal REST API or a Lambda function? Describe it at the gateway level and it becomes a tool any compatible agent can call. On AWS that's exactly what AgentCore Gateway does; the same pattern builds fine standalone.

## MCP servers: the layer that actually exposes the tools

Below the gateway sit the servers that actually expose the tools and the data: CRM, tickets, documents, databases. I've written about [MCP from a local-setup perspective](/en/blog/mcp-lm-studio); at enterprise level the logic is identical, only the stakes are higher — MCP is what stops the platform from becoming a pile of proprietary integrations.

Because the protocol is standard, the MCP server for tickets written by one team is reusable by any agent in the company, regardless of the framework the agent is built with. And when your vendors expose MCP servers themselves — increasingly common — you put them behind the same gateway and they get the same access rules and the same audit trail as the internal tools. The gateway + MCP pair is what turns "integration" from a three-week project into a configuration entry.

## RAG: shared, not reinvented per agent

The last piece is the one you already know — with one positioning correction. RAG shows up in both layers, but each layer builds something different: the application decides *what to ask and what to do with the answer*; the platform owns *the pipes* — document ingestion, indexing, embeddings, and above all **permission-aware filtering at retrieval time**. If every team builds its own ingestion pipeline, you get five indexes aging at different speeds and at least one serving confidential documents to the wrong audience. Retrieval is infrastructure, like the database; the question of "which documents is this agent allowed to see" belongs to the platform, not to the good intentions of each prompt.

## Why you need an agent architecture

Because none of the problems above can be solved inside an agent. You can write the best agent in the world and still have no answer to "who is allowed to reach what", "how good is it before release" and "what breaks on the next one" — those are properties of the system around the agents, not of any single agent.

And if you look at the four pieces together, you'll notice none of them is about AI in the strict sense. The catalog is governance. The evaluations are QA. The gateway is security and networking. Shared RAG is a data platform. The model — the "AI" part — is a dependency, not the product. That's why this is an architecture problem, not a better-prompts problem.

That, I think, is the most useful lens for this moment: with agents, we are where software was before DevOps. Everybody knows how to write one; almost nobody has the pipeline that ships it safely, measures it and retires it when it degrades. The gap between demo and production isn't a better model — it's the architecture around it.

And the practical order, if you start from zero, is the reverse of the enthusiasm: first a gateway with a single MCP server behind it and logging on every call. Then an eval set for the first agent — even 30 scenarios beat zero. The catalog comes third, once there's something to put in it. Shared RAG, when the second team asks for the same documents as the first.

An agent that works in a demo is a weekend. A factory through which ten teams ship agents without setting each other on fire is an architecture. If you're at the point where the first exists and the second doesn't, [let's talk](/contact).
