Esmeralda C. Cabrera Ventura
Agentic AI · Security Operations

Agents as services, not prompts: engineering a deterministic multi-agent SOC analyst

Five specialist agents, each deployed as its own addressable inference endpoint, chained under a supervising orchestrator on IBM watsonx.ai — and the decision I would defend hardest, which was to make the pipeline deterministic rather than autonomous.

A security operations analyst working a single alert is really doing five jobs at once. They have to understand what the activity is, work out which weaknesses would have made it possible, map the situation onto whatever control framework the organization answers to, put a number on the business risk, and then decide what gets fixed first. Each of those is a discipline. Doing all five consistently, at volume, at three in the morning, is not a thing humans sustain well.

The obvious response is to hand the whole job to a language model in one large prompt. I built that version first, informally, to see what it did. It produces something that looks like an analyst report and reads like one, and it is unreliable in a specific and dangerous way: the quality of the later reasoning depends on how well the earlier reasoning went, but nothing in the architecture enforces that the earlier reasoning actually happened. Ask a model for five analyses in one breath and it will give you five headings. It will not necessarily give you five analyses.

So I built it as six cooperating services instead — five specialists and a supervisor — and the interesting engineering is almost entirely in the seams between them.

End-to-end architecture of the autonomous cybersecurity multi-agent system
From a raw security event, through a supervised five-stage pipeline and a trusted knowledge layer, to a finished analyst report.

Specialization is a contract, not a personality

The five agents are Threat, Vulnerability, Control-Mapping, FAIR-Risk and Prioritization. Each one is built in watsonx Agent Lab as a LangGraph agent using the ReAct pattern on Llama 3.3 70B, and each has exactly one responsibility.

What makes that decomposition load-bearing is not that each agent has a job description. It is that each agent has an output contract, and the next agent's input schema is that contract. The Vulnerability-Agent cannot receive a vague impression of the threat; it receives a typed JSON object with named fields, because that is the only thing the bridge between them will pass. If the Threat-Agent fails to produce a well-formed classification, the failure surfaces immediately at the boundary rather than propagating quietly as degraded reasoning three stages downstream.

A specialist agent is only specialized if something structurally prevents it from being asked to do the neighbouring job.

This is the same argument for interfaces that applies anywhere else in software. It just matters more here, because the failure mode of an unconstrained language model is not an exception — it is a plausible paragraph.

Deploying agents rather than defining them

Each specialist was deployed as an independent online AI service on watsonx Orchestrate, not left as a configured prompt inside a single workspace. That was a deliberate cost, and worth naming what it bought.

Every agent gets its own addressable inference endpoint, its own model binding, its own tool access, and its own scaling behaviour. The Threat-Agent can be tested, versioned or replaced without touching the four agents downstream of it. A bad deployment has a blast radius of one stage. And because each service is genuinely separate, the pipeline can later be parallelized where stages are independent, rather than being one long serial prompt that cannot be decomposed after the fact.

The watsonx Orchestrate deployment space listing six online AI services
Six online services — the five specialists plus the Python runtime that executes the agent-to-agent calling logic.

It also forces an honest architecture. When your agents are prompts in one file, you can tell yourself you have a multi-agent system. When they are six separately deployed services that have to authenticate to talk to each other, you find out very quickly whether you actually designed the hand-offs or just described them.

The bridge tools are the system

The orchestrator invokes each agent through a bespoke Python function tool. Each bridge exchanges an API key for a short-lived IBM Cloud IAM token, formats the request to match that deployment's input contract, posts to the inference endpoint, and normalizes what comes back.

That last step is the one that earns its keep. A deployed model returns a chat completion — a message envelope wrapping content that is supposed to be JSON. Sometimes it is fenced in code markers. Sometimes a field arrives as a string where the schema expects a list. The bridge tools carry an explicit normalization layer that strips fencing, parses defensively, coerces known shape variations, and returns a structured error object rather than throwing when the response genuinely cannot be salvaged.

Every bridge was tested independently against a simulated SOC alert before it was ever wired into a chain, because debugging a five-stage pipeline where you don't know which hand-off is malformed is a bad way to spend an evening.

Grounding that is structural rather than instructed

Anti-hallucination work in most systems is a sentence in a prompt asking the model to be accurate. That is not a control. It is a request.

The grounding layer here has two halves, and neither of them relies on the model's cooperation. The first is an in-memory vector index built from a curated corpus — CVE intelligence, threat-incident patterns, NIST 800-53 controls, the FAIR framework, response playbooks — embedded with granite-embedding-278m-multilingual at 2,000-character chunks with 200-character overlap.

A semantic query against the vector knowledge base returning ranked passages with similarity scores
Validating retrieval before trusting it: a semantic query returns the passages it should, with scores attached.

The second half is the one I find more interesting. The orchestrator can search the live web, but only through a Google Programmable Search Engine locked to an allow-list of authoritative security domains — nist.gov, csrc.nist.gov, nvd.nist.gov, cisa.gov, attack.mitre.org and a small number of vendor peers.

Programmable Search Engine configuration showing the allow-list of authoritative security domains
The allow-list as configuration. A low-quality source is not filtered out downstream; it is never reachable.

The distinction matters. A model told to prefer authoritative sources will usually comply and occasionally won't, and you will not know which run was which. A model whose search tool physically cannot return a result from outside the allow-list has no such degree of freedom. The guarantee moved out of the instruction layer and into the infrastructure, which is where guarantees belong.

The decision I would defend hardest

The supervisor is a LangGraph/ReAct agent with a full toolbelt: document search over the vector store, trusted web search, five agent bridges, and a phased operating instruction telling it to retrieve knowledge, execute the pipeline, optionally validate against trusted sources, and deliver a report.

The idiomatic way to run that is to let ReAct do what ReAct does — reason about which tool to call next, call it, observe, repeat, until it decides it is finished. It is the pattern the framework is built around, and it demonstrates well.

I took the autonomy out. The five bridge calls were consolidated into a single run_full_pipeline tool that executes the agents in a fixed sequence within one pass and returns one combined structured report.

Autonomy is a feature when the path is unknown. When the path is known, it is a source of variance you are paying for twice.

The order of a security triage is not in question. Threat before vulnerability, vulnerability before control mapping, controls before quantified risk, risk before prioritization — that sequence is the domain, not a search problem. Letting a reasoning loop rediscover it on every invocation buys nothing and costs three things: latency, token spend that varies run to run, and the possibility that on some invocation the loop skips a stage, repeats one, or terminates early. Every one of those is a bad outcome in a system whose entire purpose is producing a consistent, defensible analysis.

Testing the single-pass pipeline tool against a simulated alert and receiving a complete combined result
One call in, five stages executed in fixed order, one schema-compliant object out — repeatably.

So the supervisor keeps its judgement where judgement is genuinely required — deciding what to retrieve, whether a finding warrants validation against a trusted source, how to narrate the result for an executive reader — and loses it where the answer was never in doubt. Deterministic where the domain is deterministic; agentic where it isn't.

Security as a build constraint

A system that operates on security alerts and was always going to be published as a portfolio artefact has to be built as though both of those things are true from the first commit, not audited afterwards.

The redaction discipline is worth dwelling on for a second, because it is the part people skip. A build walkthrough is a genuinely useful artefact — and a screenshot of a working system is also a screenshot of its attack surface. Publishing one without treating the other as a real exposure is how portfolios become incidents.

What it does, and what it deliberately doesn't

End to end, the system takes one raw alert and returns an executive summary, agent-by-agent analysis, quantified risk, standards-aligned control mapping, and a ranked set of remediation actions. Repeated runs produce consistent, schema-compliant output at the agent level, the pipeline level and the orchestrator level.

The final analyst report produced by the orchestrator
The deliverable. Not a chat transcript — a decision-support document an analyst can act on or argue with.

What it does not do is act. Every output is a recommendation, and a human decides. That boundary is where the next increment lives, and it is the part I want to build most carefully: scoped connectors into identity providers, firewalls and endpoint protection so an approved recommendation can actually be applied — behind a mandatory approval gate, with full audit logging and rollback, and with explicit protection for the legitimate users who need continued access. The goal is least privilege, not over-blocking. A remediation system that locks out the finance team at 2am has not reduced risk; it has relocated it.

Alongside that: live SIEM and SOAR feeds so the pipeline triggers on incoming alerts rather than pasted ones, parallelization of the independent stages, confidence scoring, and a feedback loop that captures analyst approvals, edits and rejections so the system's risk scoring measurably improves against real decisions rather than assumptions.

What the build actually taught me

The parts of this that were hard were not the parts that sound hard. Getting a large model to produce competent threat analysis is close to free now. What took the work was everything around it: the contract at each hand-off, the normalization layer that absorbs a model's formatting whims without hiding real failures, the search tool that cannot reach a bad source, the authentication flow that makes six services into one system.

In an agentic system, the intelligence is commodity. The engineering is in constraining it.

IBM watsonx.ai · watsonx Agent Lab · watsonx Orchestrate · LangGraph · ReAct · Llama 3.3 70B · Vector RAG · IBM Cloud IAM · Google Custom Search API · Python

Read the full engineering dossier →

Built as an IBM SkillsBuild capstone. The full technical report, documenting every build stage with captioned screenshots, is available on request. More of my work is at esmeraldaspace.com, and I am reachable on LinkedIn.