The best way to understand this architecture is to build one realistic financial-services application twice:
RAG application — "Risk Policy Assistant"
Agentic AI application — "Risk Investigation Agent"
Both use the AWS components you listed, so you can explain the architecture in an interview and also implement a working prototype.
One important correction for interview accuracy: don't say Bedrock "blocks hallucinations" by itself. Guardrails can detect/filter certain unsafe or policy-violating content and can help with grounding-related controls, but hallucination prevention fundamentally comes from architecture: RAG grounding, tool constraints, evaluation, citations, and validation.
1. Real-world example
Imagine a bank has thousands of documents:
Risk Policies
Credit Policies
Liquidity Policies
Market Risk Policies
Counterparty Policies
Basel Documents
Regulatory Documents
Internal Procedures
Trade Processing ManualsA user asks:
"What is the bank's policy for counterparty exposure when the credit rating falls below investment grade?"
We want:
User
↓
AWS security perimeter
↓
AI Gateway
↓
RAG
↓
Authorized documents
↓
Bedrock
↓
Guardrails
↓
Answer + citationsThen we extend it.
User asks:
"Investigate why counterparty ABC breached its exposure limit yesterday and tell me what action should be taken."
Now we need an agent.
User
↓
Agent
├── Search risk policy
├── Retrieve counterparty data
├── Retrieve trades
├── Calculate exposure
├── Compare against limit
├── Investigate breach
└── Recommend actionThat is the difference between RAG and Agentic AI.
2. Complete AWS architecture
┌─────────────────┐
│ USER │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Amazon │
│ CloudFront │
└────────┬────────┘
│
┌────────▼────────┐
│ AWS WAF │
│ AWS Shield │
└────────┬────────┘
│
▼
┌─────────────────────┐
│ Application Load │
│ Balancer │
└──────────┬──────────┘
│
PRIVATE SUBNETS
│
┌─────────────▼─────────────┐
│ ECS / EKS │
│ │
│ Frontend │
│ API │
│ RAG Service │
│ Agent Service │
└─────────────┬─────────────┘
│
┌────────▼────────┐
│ AI Gateway │
│ │
│ Auth │
│ Rate Limit │
│ Tenant │
│ Cost Tracking │
│ Model Routing │
└────────┬─────────┘
│
┌────────────┼─────────────┐
│ │ │
▼ ▼ ▼
Bedrock Knowledge Application
Guardrails Bases Tools
│ │ │
▼ ▼ ▼
Bedrock OpenSearch APIs
Claude / Aurora DB
Llama pgvector Kafka
TitanNetwork path:
Internet
│
▼
CloudFront
│
▼
WAF + Shield
│
▼
ALB
│
▼
Private ECS/EKS
│
▼
AI Gateway
│
├───────────────► Bedrock
│
├───────────────► Knowledge Base
│
└───────────────► Internal APIs3. RAG application
Let's build the simpler system first.
User question
"What is the counterparty exposure policy
for below-investment-grade entities?"Architecture:
USER
│
▼
API Gateway
│
▼
AI Gateway
│
▼
Bedrock Guardrail
│
▼
Bedrock Knowledge Base
│
▼
Vector Search / OpenSearch
│
Top K documents
│
▼
Claude
│
▼
Grounded answer
│
▼
USER4. Document ingestion
Suppose we have:
s3://bank-risk-documents/
├── credit/
│ ├── credit_policy.pdf
│ └── rating_policy.pdf
│
├── market/
│ └── market_risk_policy.pdf
│
└── liquidity/
└── liquidity_policy.pdfThe pipeline is:
PDF
│
▼
Amazon S3
│
▼
Bedrock Knowledge Base
│
├── Parse
├── Chunk
├── Embed
└── Index
│
▼
Amazon OpenSearch ServerlessThe embedding model converts:
"Counterparty exposure must not exceed..."into something like:
[0.021, -0.182, 0.731, ...]The vector is stored in the vector index.
5. Retrieval
User asks:
"What happens if rating falls below BBB?"The question becomes:
query
↓
embedding
↓
vector similarity
↓
Top 5 chunksExample:
Document 1 → similarity 0.92
Document 2 → similarity 0.88
Document 3 → similarity 0.84
Document 4 → similarity 0.81
Document 5 → similarity 0.79Those documents become context for the LLM.
6. Important enterprise feature: authorization-aware RAG
This is where your architecture becomes enterprise-grade.
Suppose:
Consultant A
│
└── Client A documents
Consultant B
│
└── Client B documentsNever do:
results = vector_db.search(query)Do:
results = vector_db.search(
query=query,
filter={
"tenant_id": user.tenant_id,
"classification": {
"$in": user.allowed_classifications
}
}
)Metadata:
{
"document_id": "RISK-001",
"tenant_id": "BANK-A",
"classification": "CONFIDENTIAL",
"department": "MARKET_RISK",
"region": "EU"
}This prevents:
Client A
↓
Client B's documents
↓
DATA LEAK7. RAG code
A simplified Python service:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Query(BaseModel):
question: str
tenant_id: str
@app.post("/rag")
async def rag(query: Query):
documents = await retrieve_documents(
question=query.question,
tenant_id=query.tenant_id
)
context = "\n\n".join(
document["text"]
for document in documents
)
prompt = f"""
You are an enterprise risk assistant.
Answer only from the supplied context.
If the answer is not available,
say that the information is unavailable.
Context:
{context}
Question:
{query.question}
"""
response = await invoke_bedrock(
prompt=prompt
)
return {
"answer": response,
"sources": [
d["document_id"]
for d in documents
]
}Notice the architecture:
FastAPI
│
├── Authorization
│
├── Retrieval
│
├── Prompt construction
│
├── Bedrock
│
└── Citation8. Bedrock model invocation
Your application should not directly scatter Bedrock calls everywhere.
Bad:
bedrock.invoke_model(...)from 20 different microservices.
Better:
Applications
│
▼
AI Gateway
│
▼
BedrockThe gateway provides:
Authentication
Authorization
Rate limiting
Tenant isolation
Model routing
Cost tracking
Prompt policy
Guardrails
Observability9. LiteLLM architecture
If you use LiteLLM:
Applications
│
▼
LiteLLM
│
┌─────────┼─────────┐
▼ ▼ ▼
Claude Llama Titan
│ │ │
└─────────┼─────────┘
▼
BedrockNow your application doesn't need to know which model is being used.
For example:
response = completion(
model="bedrock/anthropic.claude",
messages=[
{
"role": "user",
"content": prompt
}
]
)Then your gateway can implement:
Premium request
↓
Claude
Normal request
↓
Llama
Low-cost request
↓
smaller model10. Where Guardrails belong
There are actually multiple guardrail points.
USER
│
▼
Input Guardrail
│
▼
AI Gateway
│
▼
RAG
│
▼
Bedrock
│
▼
Output Guardrail
│
▼
USERCheck:
Input:
├── Prompt injection
├── Toxicity
├── PII
└── Policy violations
Output:
├── PII
├── Unsafe content
├── Policy violations
└── Grounding/citation requirements11. Now let's make it Agentic AI
RAG answers:
"What does the policy say?"
Agentic AI can answer:
"Why did this counterparty breach its exposure limit?"
That requires multiple actions.
Architecture:
USER
│
▼
Agent API
│
▼
AI Gateway
│
▼
Agent
│
┌───────────────┼────────────────┐
│ │ │
▼ ▼ ▼
Policy RAG Exposure API Trade API
│ │ │
▼ ▼ ▼
Knowledge Base Risk Engine Trade DB
│ │ │
└───────────────┼────────────────┘
▼
Gemini/Claude
│
▼
Final Explanation12. Agent's tools
Define tools explicitly.
tools = [
get_counterparty_exposure,
get_counterparty_limit,
get_recent_trades,
search_risk_policy,
calculate_potential_exposure,
create_risk_case
]The LLM doesn't directly access databases.
Instead:
Agent
│
├── get_exposure()
│
├── get_limit()
│
├── search_policy()
│
└── get_trades()This is critical for security.
13. Example Agent Workflow
User:
"Investigate ABC's exposure breach."
Agent thinks in terms of actions:
STEP 1
Get ABC exposure
↓
STEP 2
Get ABC approved limit
↓
STEP 3
Compare exposure vs limit
↓
STEP 4
If breach:
search relevant policy
↓
STEP 5
Get recent trades
↓
STEP 6
Determine likely cause
↓
STEP 7
Generate recommendation
↓
STEP 8
Ask human approval
if action has financial impact14. Agent architecture
┌───────────────┐
│ USER │
└───────┬───────┘
│
▼
┌───────────────┐
│ Agent │
│ Orchestrator │
└───────┬───────┘
│
┌───────▼────────┐
│ Planner │
└───────┬────────┘
│
┌─────────────────┼──────────────────┐
▼ ▼ ▼
Policy Tool Exposure Tool Trade Tool
│ │ │
▼ ▼ ▼
RAG/KB Risk API Trade DB
│ │ │
└─────────────────┼──────────────────┘
▼
Result Aggregator
│
▼
LLM Judge
│
▼
Human Review
│
▼
Response15. Example Agent Tool
async def get_counterparty_exposure(
counterparty_id: str
):
response = await risk_api.get(
f"/counterparty/{counterparty_id}/exposure"
)
return {
"counterparty": counterparty_id,
"exposure": response["exposure"],
"currency": response["currency"],
"timestamp": response["timestamp"]
}Another:
async def get_counterparty_limit(
counterparty_id: str
):
response = await risk_api.get(
f"/counterparty/{counterparty_id}/limit"
)
return {
"limit": response["limit"],
"currency": response["currency"]
}16. Agent decision
Suppose tools return:
Exposure = $125M
Limit = $100M
Breach = $25MAgent then calls:
search_risk_policy(
"counterparty exposure breach"
)RAG returns:
"If exposure exceeds approved limit,
the breach must be escalated to Risk Control..."Then:
Agent
│
├── Exposure = $125M
├── Limit = $100M
├── Breach = $25M
│
└── Policy = escalation requiredFinal answer:
ABC currently exceeds its approved counterparty
limit by $25M.
The applicable risk policy requires escalation
to Risk Control.
Recent trade activity indicates that the breach
was primarily driven by ...
Recommended action:
Escalate to Risk Control and review the
transactions responsible for the increase.17. Human-in-the-loop
This is extremely important in financial services.
Never let the agent autonomously execute:
Cancel trade
Change credit limit
Transfer money
Approve transaction
Modify collateralInstead:
Agent
│
▼
Recommendation
│
▼
Human Approval
│
┌┴────────────┐
▼ ▼
Approve Reject
│
▼
Tool executionFor example:
Agent:
"I recommend reducing the exposure limit
from $100M to $80M."
↓
Risk Officer:
[ APPROVE ] [ REJECT ]18. Agent + RAG together
This is the architecture you should really understand.
RAG is a capability.
Agentic AI is an orchestration pattern.
AGENT
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
RAG API SQL
│ │ │
▼ ▼ ▼
Knowledge Risk Engine Database
BaseTherefore:
RAG ≠ Agent
Agent can USE RAG.19. AWS network architecture
Now incorporate your PrivateLink requirement.
INTERNET
│
▼
CloudFront
│
▼
WAF + Shield
│
▼
ALB
│
PUBLIC SUBNET
│
──────────┼──────────
│
PRIVATE SUBNET
│
┌───────▼───────┐
│ ECS / EKS │
│ │
│ RAG Service │
│ Agent Service │
│ API Gateway │
└───────┬───────┘
│
VPC Endpoints
│
┌────────────┼────────────┐
▼ ▼ ▼
Bedrock S3 OpenSearchThe important idea is:
Application
│
▼
Private VPC
│
▼
Interface VPC Endpoint
│
▼
AWS serviceSo your workloads don't need public internet paths to reach supported AWS services.
20. ECS vs EKS
For the example, I would start with ECS unless Kubernetes is explicitly required.
ECS
│
├── RAG API
├── Agent API
├── AI Gateway
└── WorkerUse EKS when you need:
Complex Kubernetes workloads
Custom scheduling
Service mesh
GPU workloads
Large microservice platform
Existing Kubernetes organizationFor an interview, say:
"I would default to ECS/Fargate for a relatively straightforward stateless GenAI platform because it reduces operational overhead. I would choose EKS where Kubernetes-level control, GPU scheduling, service mesh or an existing enterprise Kubernetes platform justifies the additional complexity."
21. Complete Agentic AI request
Here is the complete request flow:
USER
│
│ "Investigate ABC exposure breach"
▼
CloudFront
│
▼
WAF
│
▼
Shield
│
▼
ALB
│
▼
ECS
│
▼
AI Gateway
│
├── Authentication
├── Tenant validation
├── Rate limit
├── Cost tracking
└── Guardrails
│
▼
Agent
│
├──────────────┐
│ │
▼ ▼
RAG Tools
│ │
▼ ├── Exposure API
Bedrock KB ├── Limit API
│ ├── Trade API
▼ └── Risk DB
OpenSearch
│
└──────────────┐
▼
Bedrock
│
▼
Reasoning
│
▼
Recommendation
│
▼
Human approval
│
▼
User22. Production observability
You should instrument every agent step.
Example trace:
Trace ID: ABC-123
00ms API Gateway
15ms Authentication
20ms Guardrail
35ms Agent started
90ms RAG retrieval
150ms Exposure API
180ms Limit API
250ms Trade API
400ms Bedrock
430ms Output guardrailThen you can answer:
"Why is the agent slow?"
Maybe:
LLM = 120ms
RAG = 40ms
Risk API = 20ms
Trade API = 800ms ← bottleneckThis is much better than simply looking at total latency.
23. Cost tracking
Your AI Gateway should attach:
{
"tenant_id": "BANK-A",
"user_id": "U123",
"application": "risk-agent",
"model": "claude",
"input_tokens": 4200,
"output_tokens": 850,
"latency_ms": 1430
}Then:
Tenant
│
▼
AI Gateway
│
├── Token accounting
├── Model accounting
├── Request accounting
└── Cost accounting
│
▼
BigQuery/S3
│
▼
Dashboard24. What makes this architecture "Senior Architect" level?
Not:
CloudFront
+
ECS
+
Bedrock
+
OpenSearchAnyone can draw AWS services.
The architecture becomes senior-level when you explain:
┌──────────────┐
│ REQUIREMENTS │
└──────┬───────┘
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
Security Reliability Cost
│ │ │
▼ ▼ ▼
IAM/WAF Retry/CB Model routing
KMS Fallback Caching
VPC Queue Token budget
│ │ │
└─────────────────┼─────────────────┘
▼
Scalability
│
▼
ObservabilityAnd especially:
RAG:
"Find the right information."
Agent:
"Decide which actions/tools are required
to solve the problem."
LLM:
"Reason/generate."
Tools:
"Actually interact with enterprise systems."
Guardrails:
"Constrain what the system is allowed to do."
Human:
"Approve high-impact decisions."That distinction is one of the strongest concepts to internalize for an AWS GenAI Architect interview.
One final architecture to memorize
┌─────────────────────┐
│ USER │
└──────────┬──────────┘
▼
┌─────────────────────┐
│ CloudFront │
│ WAF + Shield │
└──────────┬──────────┘
▼
┌─────────────────────┐
│ ALB │
└──────────┬──────────┘
▼
┌─────────────────────────────┐
│ ECS / EKS PRIVATE SUBNET │
│ │
│ AI Gateway │
│ Agent Orchestrator │
│ RAG Service │
└─────────────┬───────────────┘
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
Guardrails Knowledge Base Tools
│ │ │
│ ▼ ├── Risk API
│ OpenSearch ├── Trade API
│ / Aurora ├── SQL
│ │ └── MCP
│ │
└─────────────────┼─────────────────┐
▼ │
Amazon Bedrock │
Claude/Llama/Titan │
│ │
▼ │
Agent Result ◄─────────┘
│
▼
Human Approval
│
▼
USERThis single architecture can answer a surprisingly large number of AWS GenAI Architect interview questions: RAG, agents, Bedrock, security, networking, multi-tenancy, governance, scalability, observability, cost optimization, human-in-the-loop, and enterprise integration.