Home / Blog / Article
Agentic AI on AWS · Part 3

Five Agents, One Customer: Multi-Agent RAG Without the Chaos

NovaMart, the Nanodegree capstone: a supervisor and four specialist agents, parallel search over three knowledge bases, and shared state that cannot be silently overwritten.

Multi-Agent RAGStrands AgentsS3 Vectors
120/120Official test score
5Cooperating agents
3Knowledge bases in parallel
0Failed trace nodes
NovaMart multi-agent architecture on Amazon Bedrock AgentCore

Why split one assistant into five

NovaMart is a support assistant for a fictional online shop and the capstone of the Future AWS Agent Engineer Nanodegree. A single customer question such as "Where's my order, and can I still return it?" needs order data, a refund decision and policy text at the same time. One agent holding every tool tends to blur those jobs: it reads policy while deciding refunds, or answers account questions with policy text.

NovaMart gives each job to its own agent, makes the routing between them explicit, and keeps their work in one shared, versioned record. The official assignment run scored 120/120 on 8 October 2026.

Architecture

The system runs on Amazon Bedrock AgentCore Runtime and is built with the Strands Agents SDK. A Bedrock Guardrail checks each request before it reaches the orchestrator. Order and customer data live in DynamoDB, policy documents live in three Bedrock Knowledge Bases backed by Amazon S3 Vectors, and CloudWatch with AWS X-Ray provides tracing.

NovaMart project cover and conceptual agent topology. The repository's Mermaid diagrams and config.py are the authoritative description of the submitted system.
Fig. 1 NovaMart project cover and conceptual agent topology. The repository's Mermaid diagrams and config.py are the authoritative description of the submitted system.

Five agents, one job each

AgentResponsibilityTools
Orchestrator (Claude Haiku 4.5)Initialise state, choose specialists, enforce routing, call Communication lastinitialize_session, four route_to_*
InventoryOrder and customer facts, no policy decisionscheck_order_status, get_customer_tier, list_customer_orders
PolicySearch three policy domains at once and summarise grounded passagessearch_all_policies
RefundEvaluate eligibility; refund only when explicitly requestedget_inventory_context, initiate_refund
CommunicationRead the accumulated state and write the customer replyget_full_workflow_context

The four workers run on Claude Sonnet 4.5; the cheaper, faster Haiku model handles routing.

A routing contract, not a vibe

Routing is written down as six rules and checked by tests in continuous integration, rather than left to the orchestrator's judgement:

Request typeRoute before the final reply
Account details or customer tierInventory only, never Policy
Order status or historyInventory, then Refund for evaluation only
Policy-only questionPolicy
Explicit return or refundInventory, then Policy, then Refund
Mixed order and policyInventory, then Policy
ArithmeticOrchestrator only

Communication is always the last step. An order-status route may pass through the Refund agent to evaluate eligibility, but it never authorises a refund unless the customer asks for one.

Representative execution paths for order, policy and direct-answer requests. Every path writes to shared state and ends with the Communication agent.
Fig. 2 Representative execution paths for order, policy and direct-answer requests. Every path writes to shared state and ends with the Communication agent.

Searching three knowledge bases at once

Returns, shipping and warranty policies each have their own knowledge base, so a question can need any combination of them. The Policy agent's single tool starts three retriever sub-agents in a thread pool and joins their grounded findings with source information:

@tool
def search_all_policies(query: str) -> str:
    """Query all three policy knowledge bases in parallel."""
    retrievers = {
        "Returns":  returns_retriever,
        "Shipping": shipping_retriever,
        "Warranty": warranty_retriever,
    }
    # each retriever runs concurrently in a ThreadPoolExecutor,
    # then the passages are combined with their sources

The total wait is roughly the slowest of the three searches rather than their sum, and the Bedrock retrieval details stay inside the tool, so the agent's prompt only reasons over the passages it gets back.

The three synchronised knowledge bases (warranty, shipping, returns) in the Amazon Bedrock console.
Fig. 3 The three synchronised knowledge bases (warranty, shipping, returns) in the Amazon Bedrock console.

Shared state that cannot be silently overwritten

Agents pass their results through a DynamoDB WorkflowStateTable, not only through prompts. Each record is keyed by session_id and stores the customer ID, a creation time, a 24-hour TTL, a version number and one result column per worker. Every write is conditional on the version it read:

read state              → version = n
worker produces result
conditional write       → only if version is still n
  ✓ success             → store result, version = n + 1
  ✗ conflict            → reload state and retry

This is optimistic locking. Two workers cannot overwrite each other without noticing, and the Communication agent always reads a complete record. AgentCore Memory complements rather than duplicates this: DynamoDB holds one request's operational state, while Memory's session summary strategy keeps conversational summaries for seven days.

Safety and privacy by default

  • Service boundaries validate input and configuration before any agent runs.
  • Guardrail interventions become controlled responses rather than unhandled errors.
  • Telemetry uses process-local pseudonyms, omits raw request text and logs tool argument names without their values.
  • Resource identifiers come from environment variables or ignored local files, never the repository.

Proving it works

With CloudWatch logging and X-Ray tracing enabled, the trace map after the final run showed the orchestrator connected to all four workers and all three knowledge bases, with no failed nodes. If the trace map does not match the architecture diagram, one of them is wrong.

CloudWatch X-Ray trace map from the final three-scenario run: one orchestrator, four workers, three knowledge bases.
Fig. 4 CloudWatch X-Ray trace map from the final three-scenario run: one orchestrator, four workers, three knowledge bases.
Task: rubric areaScore
2: Multi-agent graph, tools, models and routing40/40
3: Guardrail and AgentCore Runtime20/20
4: AgentCore Memory15/15
5: Knowledge Bases and parallel retrieval25/25
6: CloudWatch and X-Ray observability20/20
Total120/120

Delivery without long-lived keys

The repository separates credential-free CI from protected delivery. The validation workflow runs on every push and pull request with read-only permissions and no AWS credentials. It lints and compiles the code, rejects committed secrets and private configuration, checks secure defaults and the routing contract, runs the assignment test suite and builds the CDK project. Deployment is manual only: an approval-protected environment uses GitHub OIDC to obtain short-lived AWS credentials, so no access key is ever stored.

Advice for a first multi-agent system

  • One job per agent. If two agents could both answer a question, the routing rules are not specific enough.
  • Write the routing down. A small table of rules can be tested; a prompt that "usually routes well" cannot.
  • Put state where you can inspect it. A versioned table is auditable; a prompt is not.
  • Run independent steps in parallel. It is easy once retrieval is wrapped in one tool.
  • Plan cleanup. TTLs reduce stale data, but the deployment still has to be deleted when the review ends.